Pārlūkot izejas kodu

More battle workflow:

 - Enemies are assigned and can be read from Lua scripts. They have their own internal ATBs.
 - Targetig windows shown and usable for all target cases.
 - Actions can be selected and queued (but not executed, yet).
Iñigo Valentin 3 gadi atpakaļ
vecāks
revīzija
d716df78d0

+ 35 - 1
data/data/screens/battle/battle.xml

@@ -58,7 +58,7 @@
                     <animation name="Position12" length="0" x="0:80" y="0:66%+7" />
                     <animation name="Position12" length="0" x="0:80" y="0:66%+7" />
                 </sprite>
                 </sprite>
             </widget>
             </widget>
-            <widget name="List" x="42%" y="5%" width="120" height="95%" visible="false">
+            <widget name="List" x="32%" y="5%" width="120" height="95%" visible="false">
                 <prototype name="Window" />
                 <prototype name="Window" />
                 <text_area name="List1" x="10" y="0%+5" width="100%-5" height="25%" font="FFVIIFont" visible="true" />
                 <text_area name="List1" x="10" y="0%+5" width="100%-5" height="25%" font="FFVIIFont" visible="true" />
                 <text_area name="List2" x="10" y="22%+5" width="100%-5" height="25%" font="FFVIIFont" visible="true" />
                 <text_area name="List2" x="10" y="22%+5" width="100%-5" height="25%" font="FFVIIFont" visible="true" />
@@ -71,6 +71,40 @@
                     <animation name="Position4" length="0" x="0:-15" y="0:66%+7" />
                     <animation name="Position4" length="0" x="0:-15" y="0:66%+7" />
                 </sprite>
                 </sprite>
             </widget>
             </widget>
+            <widget name="Target" x="42%" y="5%" width="160" height="95%" visible="false">
+                <prototype name="Window" />
+                <text_area name="L1" x="10" y="0%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <text_area name="L2" x="10" y="22%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <text_area name="L3" x="10" y="44%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <text_area name="L4" x="10" y="66%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <sprite name="Separator" x="80" y="10%" width="1" height="80%" colour="0.1 0.1 0.1" visible="true" />
+                <text_area name="R1" x="90" y="0%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <text_area name="R2" x="90" y="22%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <text_area name="R3" x="90" y="44%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <text_area name="R4" x="90" y="66%+5" width="100%-5" height="25%" font="FFVIIFont" text_name="BattleUiHp" visible="true" />
+                <sprite name="Cursor" image="icons/cursor.png" x="-15" y="0%+7" width="24" height="16" visible="true">
+                    <animation name="Position1_1" length="0" x="0:-15" y="0:0%+7" />
+                    <animation name="Position1_2" length="0" x="0:-15" y="0:22%+7" />
+                    <animation name="Position1_3" length="0" x="0:-15" y="0:44%+7" />
+                    <animation name="Position1_4" length="0" x="0:-15" y="0:66%+7" />
+                    <animation name="Position2_1" length="0" x="0:65" y="0:0%+7" />
+                    <animation name="Position2_2" length="0" x="0:65" y="0:22%+7" />
+                    <animation name="Position2_3" length="0" x="0:65" y="0:44%+7" />
+                    <animation name="Position2_4" length="0" x="0:65" y="0:66%+7" />
+                </sprite>
+                <widget name="CursorAllLeft" x="0" y="0" width="100%" hieght="100%" visible="false">
+                    <sprite name="CursorAllLeft1" image="icons/cursor.png" x="-15" y="0%+7" width="24" height="16" visible="true"/>
+                    <sprite name="CursorAllLeft2" image="icons/cursor.png" x="-15" y="22%+7" width="24" height="16" visible="true"/>
+                    <sprite name="CursorAllLeft3" image="icons/cursor.png" x="-15" y="44%+7" width="24" height="16" visible="true"/>
+                    <sprite name="CursorAllLeft4" image="icons/cursor.png" x="-15" y="66%+7" width="24" height="16" visible="true"/>
+                </widget>
+                <widget name="CursorAllRight" x="0" y="0" width="100%" hieght="100%" visible="false">
+                    <sprite name="CursorAllRight1" image="icons/cursor.png" x="65" y="0%+7" width="24" height="16" visible="true"/>
+                    <sprite name="CursorAllRight2" image="icons/cursor.png" x="65" y="22%+7" width="24" height="16" visible="true"/>
+                    <sprite name="CursorAllRight3" image="icons/cursor.png" x="65" y="44%+7" width="24" height="16" visible="true"/>
+                    <sprite name="CursorAllRight4" image="icons/cursor.png" x="65" y="66%+7" width="24" height="16" visible="true"/>
+                </widget>
+            </widget>
         </widget>
         </widget>
     </widget>
     </widget>
 </screen>
 </screen>

+ 34 - 0
data/data/scripts/battle.lua

@@ -55,6 +55,40 @@ Battle.Menu = {
     COIN = 11,
     COIN = 11,
 }
 }
 
 
+--- Target modes
+Battle.TargetType = {
+
+    --- Single target
+    SINGLE = 0,
+
+    --- All targets in a battle side
+    GROUP = 1
+}
+
+--- Target modes
+Battle.TargetGroup = {
+
+    --- Single target
+    PARTY = 0,
+
+    --- All targets in a battle side
+    ENEMIES = 1
+}
+
+--- Action types
+Battle.ActionType = {
+
+    --- A command
+    --
+    -- An action of this type will be searched in the Commands array.
+    COMMAND = 0,
+
+    --- Anything that is not a command
+    --
+    -- -- An action of this type will be searched in the Attacks array.
+    ATTACK = 1
+}
+
 Battle.ActionDefaults = {
 Battle.ActionDefaults = {
     [ Battle.Action.MONSTER_ACTION ] = { animation_script = "0" }
     [ Battle.Action.MONSTER_ACTION ] = { animation_script = "0" }
 }
 }

+ 528 - 240
data/data/scripts/battle/battle_ui.lua

@@ -1,9 +1,14 @@
 if UiContainer == nil then UiContainer = {} end
 if UiContainer == nil then UiContainer = {} end
 
 
---- The main menu.
+--- The battle UI
+--
+-- Controls the battle UI and the battle flow
+-- TODO: Merge this code into Battle
 UiContainer.BattleUi = {
 UiContainer.BattleUi = {
 
 
     --- Party members
     --- Party members
+    --
+    --
     party = {},
     party = {},
 
 
     --- Enemies
     --- Enemies
@@ -15,6 +20,9 @@ UiContainer.BattleUi = {
     -- executed in order. Actions for enemies and allies are stored here.
     -- executed in order. Actions for enemies and allies are stored here.
     action_queue = {},
     action_queue = {},
 
 
+    --- Determines if an action is being executed.
+    action_executing = false,
+
     --- Party command selection queue.
     --- Party command selection queue.
     --
     --
     -- When a party member ATB is filled, the character is added to this queue. Command selection
     -- When a party member ATB is filled, the character is added to this queue. Command selection
@@ -44,8 +52,14 @@ UiContainer.BattleUi = {
     --- First visible item in the list window
     --- First visible item in the list window
     first_list = 1,
     first_list = 1,
 
 
-    --- Current position for the cursor in the target window.
-    cursor_target = 1,
+    --- Current horizontal position for the cursor in the target window.
+    cursor_target_h = 1,
+
+    --- Current vertical position for the cursor in the target window.
+    cursor_target_v = 1,
+
+    --- First visible enemy in the target window
+    first_target = 1,
 
 
     --- ID of the character the cursor is for.
     --- ID of the character the cursor is for.
     current_character_window = -1,
     current_character_window = -1,
@@ -56,6 +70,18 @@ UiContainer.BattleUi = {
     -- witem2, eskill, throw, limit, coin.
     -- witem2, eskill, throw, limit, coin.
     current_list = "none",
     current_list = "none",
 
 
+    --- Target options of the currently selected attack
+    target_options = {},
+
+    --- Target mode.
+    target_type = Battle.TargetType.SINGLE,
+
+    --- The targeted group.
+    target_group = Battle.TargetGroup.ENEMIES,
+
+    --- The targeted unit index in the targeted group.
+    target_index = 1,
+
 
 
     --- Handles button events.
     --- Handles button events.
     --
     --
@@ -63,12 +89,8 @@ UiContainer.BattleUi = {
     -- @param button Pressed button string key. "Up", "Left", "Enter" and "Escape" are handled.
     -- @param button Pressed button string key. "Up", "Left", "Enter" and "Escape" are handled.
     -- @param event Trigger event. Normally, "Press".
     -- @param event Trigger event. Normally, "Press".
     on_button = function(self, button, event)
     on_button = function(self, button, event)
-        if self.active == false then
-            do return 0 end
-        end
-        if button == "K" then
-            Battle.finish()
-        end
+        if self.active == false then do return 0 end end
+        if button == "K" then Battle.finish() end
         -- Handle command cursors
         -- Handle command cursors
         if self.window_state == "command" then
         if self.window_state == "command" then
             local command_count = #self.party[self.current_character_window].command
             local command_count = #self.party[self.current_character_window].command
@@ -110,9 +132,7 @@ UiContainer.BattleUi = {
                 elseif self.cursor_command % 4 == 1 and command_count > self.cursor_command then
                 elseif self.cursor_command % 4 == 1 and command_count > self.cursor_command then
                     -- If on the first row, go to the last where there is a command
                     -- If on the first row, go to the last where there is a command
                     self.cursor_command = self.cursor_command + 3
                     self.cursor_command = self.cursor_command + 3
-                    while self.cursor_command > command_count do
-                        self.cursor_command = self.cursor_command - 1
-                    end
+                    while self.cursor_command > command_count do self.cursor_command = self.cursor_command - 1 end
                     cursor:set_default_animation("Position" .. tostring(self.cursor_command))
                     cursor:set_default_animation("Position" .. tostring(self.cursor_command))
                     audio_manager:play_sound("Cursor")
                     audio_manager:play_sound("Cursor")
                 else
                 else
@@ -129,9 +149,7 @@ UiContainer.BattleUi = {
                         audio_manager:play_sound("Cursor")
                         audio_manager:play_sound("Cursor")
                     else
                     else
                         local new_pos = self.cursor_command + 4 * math.floor(command_count / 4)
                         local new_pos = self.cursor_command + 4 * math.floor(command_count / 4)
-                        while new_pos > command_count do
-                            new_pos = new_pos - 4
-                        end
+                        while new_pos > command_count do new_pos = new_pos - 4 end
                         self.cursor_command = new_pos
                         self.cursor_command = new_pos
                         cursor:set_default_animation("Position" .. tostring(self.cursor_command))
                         cursor:set_default_animation("Position" .. tostring(self.cursor_command))
                         audio_manager:play_sound("Cursor")
                         audio_manager:play_sound("Cursor")
@@ -141,11 +159,8 @@ UiContainer.BattleUi = {
                 if command_count > 4 then
                 if command_count > 4 then
                     self.cursor_command = self.cursor_command + 4
                     self.cursor_command = self.cursor_command + 4
                     if self.cursor_command > command_count then
                     if self.cursor_command > command_count then
-                        self.cursor_command
-                          = self.cursor_command - 4 * math.floor(self.cursor_command / 4)
-                        if self.cursor_command < 1 then
-                            self.cursor_command = self.cursor_command + 4
-                        end
+                        self.cursor_command = self.cursor_command - 4 * math.floor(self.cursor_command / 4)
+                        if self.cursor_command < 1 then self.cursor_command = self.cursor_command + 4 end
                     end
                     end
                     cursor:set_default_animation("Position" .. tostring(self.cursor_command))
                     cursor:set_default_animation("Position" .. tostring(self.cursor_command))
                     audio_manager:play_sound("Cursor")
                     audio_manager:play_sound("Cursor")
@@ -154,9 +169,7 @@ UiContainer.BattleUi = {
                 -- Push the current character to the end of the command queue, and show the first.
                 -- Push the current character to the end of the command queue, and show the first.
                 local new_queue = {}
                 local new_queue = {}
                 for i = 1, #self.command_queue do
                 for i = 1, #self.command_queue do
-                    if self.command_queue[i + 1] ~= nil then
-                        table.insert(new_queue, self.command_queue[i + 1])
-                    end
+                    if self.command_queue[i + 1] ~= nil then table.insert(new_queue, self.command_queue[i + 1]) end
                 end
                 end
                 table.insert(new_queue, self.command_queue[1])
                 table.insert(new_queue, self.command_queue[1])
                 self.command_queue = new_queue
                 self.command_queue = new_queue
@@ -164,105 +177,301 @@ UiContainer.BattleUi = {
                 self:show_commands(self.command_queue[1])
                 self:show_commands(self.command_queue[1])
             elseif button == "Enter" then
             elseif button == "Enter" then
                 -- Check if a menu must be shown
                 -- Check if a menu must be shown
-                local cmd = Game.Commands[
-                  self.party[self.current_character_window].command[self.cursor_command]
-                ]
-                if cmd.menu == Battle.Menu.NONE then
-                    print("DIRECT COMMAND")
-                elseif cmd.menu == Battle.Menu.TARGET then
-                    print("TARGET COMMAND")
-                else
-                    self:show_list(cmd.menu)
+                local cmd = Game.Commands[self.party[self.current_character_window].command[self.cursor_command]]
+                if cmd.menu == Battle.Menu.NONE then print("DIRECT COMMAND")
+                elseif cmd.menu == Battle.Menu.TARGET then print("TARGET COMMAND")
+                else self:show_list(cmd.menu)
                 end
                 end
             end
             end
         -- Handle menu list cursor
         -- Handle menu list cursor
         elseif self.window_state == "list" then
         elseif self.window_state == "list" then
             local total = 0
             local total = 0
-            if
-              self.current_list == "magic"
-              or self.current_list == "wmagic1" or self.current_list == "wmagic2"
-            then
+            if self.current_list == "magic" or self.current_list == "wmagic1" or self.current_list == "wmagic2" then
                 total = #self.party[self.current_character_window].magic
                 total = #self.party[self.current_character_window].magic
-            elseif
-              self.current_list == "summon"
-              or self.current_list == "wsummon1" or self.current_list == "wsummon2"
-            then
-                total = #self.party[self.current_character_window].summon
-            -- TODO: Rest of cases
+            elseif self.current_list == "summon" or self.current_list == "wsummon1" or self.current_list == "wsummon2"
+            then total = #self.party[self.current_character_window].summon
             end
             end
+            -- TODO: Rest of cases
             local cursor = ui_manager:get_widget("BattleUi.Container.Bottom.List.Cursor")
             local cursor = ui_manager:get_widget("BattleUi.Container.Bottom.List.Cursor")
-                if button == "LCtrl" then
-                    self:close_list()
-                elseif button == "Down" then
-                    if total <=  self.cursor_list + self.first_list - 1 then
-                        do return 0 end
+            if button == "LCtrl" then
+                audio_manager:play_sound("Cursor")
+                self:close_list()
+            elseif button == "Down" then
+                if total <=  self.cursor_list + self.first_list - 1 then do return 0 end end
+                if self.cursor_list < 4 then
+                    -- Move cursor down
+                    audio_manager:play_sound("Cursor")
+                    self.cursor_list = self.cursor_list + 1
+                    cursor:set_default_animation("Position" .. tostring(self.cursor_list))
+                else
+                    -- Scroll down
+                    audio_manager:play_sound("Cursor")
+                    self.first_list = self.first_list + 1
+                    self:repopulate_list()
+                end
+            elseif button == "Up" then
+                if self.cursor_list == 1 and self.first_list == 1 then do return 0 end end
+                if self.cursor_list > 1 then
+                    -- Move cursor up
+                    audio_manager:play_sound("Cursor")
+                    self.cursor_list = self.cursor_list - 1
+                    cursor:set_default_animation("Position" .. tostring(self.cursor_list))
+                else
+                    -- Scroll up
+                    audio_manager:play_sound("Cursor")
+                    self.first_list = self.first_list - 1
+                    self:repopulate_list()
+                end
+            elseif button == "Enter" then
+                audio_manager:play_sound("Cursor")
+                self:select_target()
+            end
+        elseif self.window_state == "target" then
+            if button == "LCtrl" then
+                audio_manager:play_sound("Cursor")
+                self:close_target()
+            elseif button == "Up" then
+                if self.cursor_target_h == 2 then
+                    -- Allies cursor, never scroll. Go un up or to the bottom
+                    self.cursor_target_v = self.cursor_target_v - 1
+                    if self.cursor_target_v == 0 then self.cursor_target_v = #self.party end
+                    audio_manager:play_sound("Cursor")
+                    self:populate_target_list()
+                else
+                    -- Cursor on the left. Can be enemies or allies, depends on the options.
+                    if self.target_options.fixed_row == 1 and self.target_options.default_enemy == 0 then
+                        -- Allies
+                        self.cursor_target_v = self.cursor_target_v - 1
+                        if self.cursor_target_v == 0 then self.cursor_target_v = #self.party end
+                        audio_manager:play_sound("Cursor")
+                        self:populate_target_list()
+                    else
+                        -- Enemies
+                        if #self.enemies > 4 then
+                            if self.cursor_target_v == 1 then
+                                if self.first_target == 1 then
+                                    -- Scroll to the bottom, set  cursor in last
+                                    self.first_target = #self.enemies - 4
+                                    self.cursor_target_v = 4
+                                    audio_manager:play_sound("Cursor")
+                                    self:populate_target_list()
+                                else
+                                    self.first_target = self.first_target - 1
+                                    audio_manager:play_sound("Cursor")
+                                    self:populate_target_list()
+                                end
+                            else
+                                self.cursor_target_v = self.cursor_target_v - 1
+                                audio_manager:play_sound("Cursor")
+                                self:populate_target_list()
+                            end
+                        else
+                            self.cursor_target_v = self.cursor_target_v - 1
+                            if self.cursor_target_v == 0 then self.cursor_target_v = #self.enemies end
+                            audio_manager:play_sound("Cursor")
+                            self:populate_target_list()
+                        end
                     end
                     end
-                    if self.cursor_list < 4 then
-                        -- Move cursor down
+                end
+            elseif button == "Down" then
+                if self.cursor_target_h == 2 then
+                    -- Allies cursor, never scroll. Go un up or to the bottom
+                    self.cursor_target_v = self.cursor_target_v + 1
+                    if self.cursor_target_v > #self.party then self.cursor_target_v = 1 end
+                    audio_manager:play_sound("Cursor")
+                    self:populate_target_list()
+                else
+                    -- Cursor on the left. Can be enemies or allies, depends on the options.
+                    if self.target_options.fixed_row == 1 and self.target_options.default_enemy == 0 then
+                        -- Allies
+                        self.cursor_target_v = self.cursor_target_v + 1
+                        if self.cursor_target_v > #self.party then self.cursor_target_v = 1 end
                         audio_manager:play_sound("Cursor")
                         audio_manager:play_sound("Cursor")
-                        self.cursor_list = self.cursor_list + 1
-                        cursor:set_default_animation("Position" .. tostring(self.cursor_list))
+                        self:populate_target_list()
                     else
                     else
-                        -- Scroll down
+                        -- Enemies
+                        if #self.enemies > 4 then
+                            if self.cursor_target_v == 4 then
+                                if self.first_target + 4 == #self.enemies then
+                                    -- Scroll to the top, set  cursor in first
+                                    self.first_target = 1
+                                    self.cursor_target_v = 1
+                                    audio_manager:play_sound("Cursor")
+                                    self:populate_target_list()
+                                else
+                                    self.first_target = self.first_target + 1
+                                    audio_manager:play_sound("Cursor")
+                                    self:populate_target_list()
+                                end
+                            else
+                                self.cursor_target_v = self.cursor_target_v + 1
+                                audio_manager:play_sound("Cursor")
+                                self:populate_target_list()
+                            end
+                        else
+                            self.cursor_target_v = self.cursor_target_v + 1
+                            if self.cursor_target_v > #self.enemies then self.cursor_target_v = 1 end
+                            audio_manager:play_sound("Cursor")
+                            self:populate_target_list()
+                        end
+                    end
+                end
+            elseif button == "Left" then
+                if self.target_options.fixed_row == 0 and self.target_options.toggle_multiple == 0 then
+                    -- If both rows are present and multiple toggling is not available...
+                    if self.cursor_target_h == 2 then
+                        -- and the cursor is in the second column, go to the fisrt. Also, move the
+                        --cursor up until a valid enemy is pointed.
+                        self.cursor_target_h = 1
+                        while self.cursor_target_v + self.first_target - 1 > #self.enemies do self.cursor_target_v = self.cursor_target_v - 1 end
+                        audio_manager:play_sound("Cursor")
+                        self:populate_target_list()
+                    end
+                elseif self.target_options.fixed_row == 0 and self.target_options.toggle_multiple == 1 then
+                    -- If both rows are present, and multiple targets can be toggled...
+                    if self.cursor_target_h == 2 and self.target_type == Battle.TargetType.GROUP then
+                        -- ... and the cursor is on the rigth, with multiple targets, set to single
+                        -- target
+                        self.target_type = Battle.TargetType.SINGLE
+                        audio_manager:play_sound("Cursor")
+                        self:populate_target_list()
+                    elseif self.cursor_target_h == 2 and self.target_type == Battle.TargetType.SINGLE then
+                        -- ... and the cursor is on the rigth, with single targets, go to the left
+                        -- target. Also, move the cursor up until a valid enemy is pointed.
+                        self.cursor_target_h = 1
+                        while self.cursor_target_v + self.first_target - 1 > #self.enemies do self.cursor_target_v = self.cursor_target_v - 1 end
+                        audio_manager:play_sound("Cursor")
+                        self:populate_target_list()
+                    elseif self.cursor_target_h == 1 and self.target_type == Battle.TargetType.SINGLE then
+                        -- ... and the cursor is on the left, with single targets, set to multiple
+                        -- targets
+                        self.target_type = Battle.TargetType.GROUP
                         audio_manager:play_sound("Cursor")
                         audio_manager:play_sound("Cursor")
-                        self.first_list = self.first_list + 1
-                        self:repopulate_list()
+                        self:populate_target_list()
                     end
                     end
-                elseif button == "Up" then
-                    if self.cursor_list == 1 and self.first_list == 1 then
-                        do return 0 end
+                elseif self.target_options.fixed_row == 1 and self.target_options.toggle_multiple == 1 then
+                    -- If only one row is present and multiple can be toggled, toggle it
+                    local prev_mode = self.target_type
+                    if prev_mode == Battle.TargetType.GROUP then self.target_type = Battle.TargetType.SINGLE
+                    elseif prev_mode == Battle.TargetType.SINGLE then self.target_type = Battle.TargetType.GROUP
                     end
                     end
-                    if self.cursor_list > 1 then
-                        -- Move cursor up
+                end
+            elseif button == "Right" then
+                if self.target_options.fixed_row == 0 and self.target_options.toggle_multiple == 0 then
+                    -- If both rows are present and multiple toggling is not available...
+                    if self.cursor_target_h == 1 then
+                        -- and the cursor is in the left column, go to the right. Also, move the
+                        --cursor up until a valid party member is pointed.
+                        self.cursor_target_h = 2
+                        while self.cursor_target_v + self.first_target - 1 > #self.party do self.cursor_target_v = self.cursor_target_v - 1 end
                         audio_manager:play_sound("Cursor")
                         audio_manager:play_sound("Cursor")
-                        self.cursor_list = self.cursor_list - 1
-                        cursor:set_default_animation("Position" .. tostring(self.cursor_list))
-                    else
-                        -- Scroll up
+                        self:populate_target_list()
+                    end
+                elseif self.target_options.fixed_row == 0 and self.target_options.toggle_multiple == 1 then
+                    -- If both rows are present, and multiple targets can be toggled...
+                    if self.cursor_target_h == 1 and self.target_type == Battle.TargetType.GROUP then
+                        -- ... and the cursor is on the left, on multiple target mode, set to
+                        -- single target mode.
+                        self.target_type = Battle.TargetType.SINGLE
+                        audio_manager:play_sound("Cursor")
+                        self:populate_target_list()
+                    elseif self.cursor_target_h == 1 and self.target_type == Battle.TargetType.SINGLE then
+                        -- ... and the cursor is on the left, on single target mode, go to the
+                        -- right. Also, move the cursor up until a valid party member is pointed.
+                        self.cursor_target_h = 2
+                        while self.cursor_target_v + self.first_target - 1 > #self.party do self.cursor_target_v = self.cursor_target_v - 1 end
                         audio_manager:play_sound("Cursor")
                         audio_manager:play_sound("Cursor")
-                        self.first_list = self.first_list - 1
-                        self:repopulate_list()
+                        self:populate_target_list()
+                    elseif self.cursor_target_h == 2 and self.target_type == Battle.TargetType.SINGLE then
+                        -- ... and the cursor is on the right, on single target mode, set to
+                        -- multiple target mode.
+                        self.target_type = Battle.TargetType.GROUP
+                        audio_manager:play_sound("Cursor")
+                        self:populate_target_list()
+                    end
+                elseif self.target_options.fixed_row == 1 and self.target_options.toggle_multiple == 1 then
+                    -- If only one row is present and multiple can be toggled, toggle it
+                    local prev_mode = self.target_type
+                    if prev_mode == Battle.TargetType.GROUP then self.target_type = Battle.TargetType.SINGLE
+                    elseif prev_mode == Battle.TargetType.SINGLE then self.target_type = Battle.TargetType.GROUP
+                    end
+                end
+            elseif button == "Enter" then
+                -- Determine target type and target index
+                if self.target_options.fixed_row == 1 then
+                    if self.target_options.default_enemy == 1 then
+                        self.target_group = Battle.TargetGroup.ENEMIES
+                        if self.target_type == Battle.TargetType.SINGLE then self.target_index = self.cursor_target_v + self.first_target - 1
+                        else self.target_index = nil
+                        end
+                    else
+                        self.target_group = Battle.TargetGroup.PARTY
+                        if self.target_type == Battle.TargetType.SINGLE then self.target_index = self.cursor_target_v
+                        else self.target_index = nil
+                        end
+                    end
+                else
+                    if self.cursor_target_h == 1 then
+                        self.target_group = Battle.TargetGroup.ENEMIES
+                        if self.target_type == Battle.TargetType.SINGLE then self.target_index = self.cursor_target_v + self.first_target - 1
+                        else self.target_index = nil
+                        end
+                    else
+                        self.target_group = Battle.TargetGroup.PARTY
+                        if self.target_type == Battle.TargetType.SINGLE then self.target_index = self.cursor_target_v
+                        else self.target_index = nil
+                        end
                     end
                     end
                 end
                 end
+                -- Add the action to the queue.
+                self:queue_character_action()
+            end
         end
         end
         return 0
         return 0
     end,
     end,
 
 
+    --- Repopulates a list
+    --
+    -- Repopulates the currently shown list with the current cursor and scroll positions.
     repopulate_list = function(self)
     repopulate_list = function(self)
-        if self.current_list == "magic"
-          or self.current_list == "wmagic1" or self.current_list == "wmagic2"
-        then
+        if self.current_list == "magic" or self.current_list == "wmagic1" or self.current_list == "wmagic2" then
             self:populate_magic_list()
             self:populate_magic_list()
-        elseif self.current_list == "magic"
-          or self.current_list == "wmagic1" or self.current_list == "wmagic2"
-        then
+        elseif self.current_list == "summon" or self.current_list == "wsummon1" or self.current_list == "wsummon2" then
             self:populate_summon_list()
             self:populate_summon_list()
         -- TODO: all other cases
         -- TODO: all other cases
         end
         end
     end,
     end,
 
 
-    tick = function(self)
-        if System:is_paused() == true then
-            do return end
+    --- Adds a party character action to the queue
+    queue_character_action = function(self)
+        local action = {}
+        action.actor = self.current_character_window
+        if self.current_list == "none" then action.type = Battle.ActionType.COMMAND
+        else action.type = Battle.ActionType.ATTACK
         end
         end
-        --print("CALLED BattleUI:tick()")
-        --if self.window_state ~= "wait" then
-        --    do return end
-        --end
+        action.target_type = self.target_type
+        action.target_index = self.target_index
+        action.priority = 6 -- TODO: find out
+        table.insert(self.action_queue, action)
+        -- TODO: Reorder queue by priority.
+
+    end,
+
+    --- Handles a time tick.
+    --
+    -- Increases the ATBs of party and enemies. If one of them gets filled, it shows tha command
+    -- window
+    tick = function(self)
+        if System:is_paused() == true then do return end end
         -- Advance party ATBs
         -- Advance party ATBs
         for i = 1, #self.party do
         for i = 1, #self.party do
             if self.party[i].dead == false then -- TODO: Or stopped
             if self.party[i].dead == false then -- TODO: Or stopped
                 if self.party[i].atb < 255 then
                 if self.party[i].atb < 255 then
                     -- TODO: Consider haste/slow
                     -- TODO: Consider haste/slow
-                    self.party[i].atb
-                      = self.party[i].atb
-                      + 0.04 * Characters[self.party[i].character].stats.dex.total -- TODO
+                    self.party[i].atb = self.party[i].atb + 0.04 * Characters[self.party[i].character].stats.dex.total -- TODO
                     if self.party[i].atb >= 255 then
                     if self.party[i].atb >= 255 then
                         print(Characters[self.party[i].character].name .. " ATB full")
                         print(Characters[self.party[i].character].name .. " ATB full")
-                        ui_manager:get_widget(
-                          "BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.AtbFill"
-                        ):set_colour(0, 1, 0)
-                        --self:show_commands(i)
+                        ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.AtbFill"):set_colour(0, 1, 0)
                         table.insert(self.command_queue, i)
                         table.insert(self.command_queue, i)
                     end
                     end
                     -- Fill ATB UI bar
                     -- Fill ATB UI bar
@@ -270,23 +479,47 @@ UiContainer.BattleUi = {
                     -- 255 -> 18%-6
                     -- 255 -> 18%-6
                     local width_percent = math.min(18, 18 * self.party[i].atb / 255)
                     local width_percent = math.min(18, 18 * self.party[i].atb / 255)
                     local width_fixed = math.max(-6, -6 * width_percent / 18)
                     local width_fixed = math.max(-6, -6 * width_percent / 18)
-                    ui_manager:get_widget(
-                      "BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.AtbFill"
-                    ):set_width(width_percent, width_fixed)
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.AtbFill"):set_width(width_percent, width_fixed)
                 end
                 end
             end
             end
         end
         end
         -- TODO: Advance enemy ATBs
         -- TODO: Advance enemy ATBs
+        for i = 1, #self.enemies do
+            if self.enemies[i].dead == false then -- TODO: Or stopped
+                if self.enemies[i].atb < 255 then
+                    -- TODO: Consider haste/slow
+                    self.enemies[i].atb = self.enemies[i].atb + 0.04 * self.enemies[i].stats.dex -- TODO
+                    if self.enemies[i].atb >= 255 then
+                        print("Enemy " .. self.enemies[i].name .. " ATB full")
+                        -- TODO: Select an action and add to queue
+                        --table.insert(self.command_queue, i)
+                    end
+                end
+            end
+        end
         -- Show a command window if required
         -- Show a command window if required
-        if self.window_state == "wait" and #self.command_queue > 0 then
-            self:show_commands(self.command_queue[1])
+        if self.window_state == "wait" and #self.command_queue > 0 then self:show_commands(self.command_queue[1]) end
+        -- Execute an action if none is being executed
+        if self.action_executing == false and #self.action_queue > 0 then
+            self:execute_action()
         end
         end
-        --print("ENDED BattleUI:tick()")
     end,
     end,
 
 
-    show_list = function(self, menu)
+    --- Executes an action
+    --
+    -- The top action in action_queue gets executed, and then removed from the queue
+    execute_action = function(self)
+        if self.action_executing == true or #self.action_queue == 0 then do return 0 end end
+        print("EXECUTE ACTION")
+    end,
+
+    --- Shows a list of actions.
+    --
+    -- Can be used for the windows of magic, summons, items...
+    -- @param list The list to open, as in {@see Battle.Menu}
+    show_list = function(self, list)
         local cursor = ui_manager:get_widget("BattleUi.Container.Bottom.List.Cursor")
         local cursor = ui_manager:get_widget("BattleUi.Container.Bottom.List.Cursor")
-        if (menu == Battle.Menu.MAGIC) then
+        if list == Battle.Menu.MAGIC then
             audio_manager:play_sound("Cursor")
             audio_manager:play_sound("Cursor")
             self.cursor_list = 1
             self.cursor_list = 1
             self.first_list = 1
             self.first_list = 1
@@ -296,7 +529,7 @@ UiContainer.BattleUi = {
             ui_manager:get_widget("BattleUi.Container.Bottom.List"):set_visible(true)
             ui_manager:get_widget("BattleUi.Container.Bottom.List"):set_visible(true)
             cursor:set_default_animation("Position" .. tostring(self.cursor_list))
             cursor:set_default_animation("Position" .. tostring(self.cursor_list))
             cursor:set_visible(true)
             cursor:set_visible(true)
-        elseif (menu == Battle.Menu.SUMMON) then
+        elseif list == Battle.Menu.SUMMON then
             audio_manager:play_sound("Cursor")
             audio_manager:play_sound("Cursor")
             self.cursor_list = 1
             self.cursor_list = 1
             self.first_list = 1
             self.first_list = 1
@@ -306,69 +539,197 @@ UiContainer.BattleUi = {
             ui_manager:get_widget("BattleUi.Container.Bottom.List"):set_visible(true)
             ui_manager:get_widget("BattleUi.Container.Bottom.List"):set_visible(true)
             cursor:set_default_animation("Position" .. tostring(self.cursor_list))
             cursor:set_default_animation("Position" .. tostring(self.cursor_list))
             cursor:set_visible("Position" .. tostring(self.cursor_list))
             cursor:set_visible("Position" .. tostring(self.cursor_list))
-        elseif (menu == Battle.Menu.ITEM) then
-            print("Show item menu: Not implemented")
-        elseif (menu == Battle.Menu.E_SKILL) then
-            print("Show e. skill menu: Not implemented")
-        elseif (menu == Battle.Menu.THROW) then
-            print("Show throw menu: Not implemented")
-        elseif (menu == Battle.Menu.LIMIT) then
-            print("Show magic menu: Not implemented")
-        elseif (menu == Battle.Menu.W_MAGIC) then
-            print("Show w-magic menu: Not implemented")
-        elseif (menu == Battle.Menu.W_SUMMON) then
-            print("Show w-summon menu: Not implemented")
-        elseif (menu == Battle.Menu.W_ITEM) then
-            print("Show w-magic menu: Not implemented")
-        elseif (menu == Battle.Menu.COIN) then
-            print("Show coin menu: Not implemented")
+        elseif (list == Battle.Menu.ITEM) then
+            print("Show item list: Not implemented")
+        elseif (list == Battle.Menu.E_SKILL) then
+            print("Show e. skill list: Not implemented")
+        elseif (list == Battle.Menu.THROW) then
+            print("Show throw list: Not implemented")
+        elseif (list == Battle.Menu.LIMIT) then
+            print("Show magic list: Not implemented")
+        elseif (list == Battle.Menu.W_MAGIC) then
+            print("Show w-magic list: Not implemented")
+        elseif (list == Battle.Menu.W_SUMMON) then
+            print("Show w-summon list: Not implemented")
+        elseif (list == Battle.Menu.W_ITEM) then
+            print("Show w-magic list: Not implemented")
+        elseif (list == Battle.Menu.COIN) then
+            print("Show coin list: Not implemented")
         end
         end
     end,
     end,
 
 
-    close_list = function(self, menu)
+    --- Closes the currently opened list
+    close_list = function(self)
         self.current_list = "none"
         self.current_list = "none"
         self.window_state = "command"
         self.window_state = "command"
         ui_manager:get_widget("BattleUi.Container.Bottom.List"):set_visible(false)
         ui_manager:get_widget("BattleUi.Container.Bottom.List"):set_visible(false)
     end,
     end,
 
 
+    --- Shows the target selection window.
+    --
+    -- The elements displayed in the window and the navegability will depend on what is set in
+    -- {@see target_options}.
+    select_target = function(self)
+        local action = nil
+        if self.window_state == "list" then
+            if self.current_list == "magic" then action = Game.Attacks[self.party[self.current_character_window].magic[self.cursor_list + self.first_list - 1].id] end
+        end
+        if action == nil then do return end end
+        self.target_options = action.target
+        if self.target_options.default_multiple == 1 then target_type = Battle.TargetType.GROUP
+        else target_type = Battle.TargetType.SINGLE
+        end
+        self.cursor_target_h = 1
+        self.cursor_target_v = 1
+        self.first_target = 1
+        if self.target_options.default_enemy == 1 then self.cursor_target_h = 1
+        else self.cursor_target_h = 2
+        end
+        -- TODO: if self.target_options.selectable == 0, skip this and directly queue the action.
+        -- TODO: Populate options, hide and show right column and separator, and resize window
+        -- according to self.target_options
+        self:populate_target_list()
+        ui_manager:get_widget("BattleUi.Container.Bottom.Target"):set_visible(true)
+        self.window_state = "target"
+    end,
+
+    --- Closes the target window and activates the previous cursor.
+    close_target = function(self)
+        if self.current_list == "none" then self.window_state = "command"
+        else self.window_state = "list"
+        end
+        ui_manager:get_widget("BattleUi.Container.Bottom.Target"):set_visible(false)
+    end,
+
+    --- Populates the target selection window.
+    --
+    -- The elements displayed in the window and the navegability will depend on what is set in
+    -- {@see target_options}.
+    populate_target_list = function(self)
+        print("POPULATE TARGET LIST: H: " .. tostring(self.cursor_target_h) .. " V: " .. tostring(self.cursor_target_v) .. " MODE: " .. tostring(self.target_type))
+        if self.target_options == nil then do return end end
+        if self.target_options.fixed_row == 1 then
+            if self.target_options.default_enemy == 1 then
+                -- Show only enemies
+                print("Enemies only")
+            else
+                -- Show only allies
+                print("Enemies only")
+            end
+            if self.target_type == Battle.TargetType.GROUP then
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllRight"):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllLeft"):set_visible(true)
+            else
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_default_animation("Position" .. tostring(self.cursor_target_h) .. "_" .. tostring(self.cursor_target_v))
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_visible(true)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllRight"):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllLeft"):set_visible(false)
+            end
+        else
+            -- Enemies and allies
+            for e = 1, 4 do
+                if self.enemies[e + self.first_target - 1] ~= nil then
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.L" .. tostring(e)):set_text(self.enemies[e + self.first_target - 1].name)
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.L" .. tostring(e)):set_visible(true)
+                else
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.L" .. tostring(e)):set_visible(false)
+                end
+            end
+            for a = 1, 4 do
+                if self.party[a] ~= nil then
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.R" .. tostring(a)):set_text(Characters[self.party[a].character].name)
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.R" .. tostring(a)):set_visible(true)
+                else
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.R" .. tostring(a)):set_visible(false)
+                end
+            end
+            if self.target_options.all_rows == 1 or self.target_options.random == 1 then
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllLeft"):set_visible(true)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllRight"):set_visible(true)
+            elseif self.target_type == Battle.TargetType.GROUP then
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_visible(false)
+                if self.cursor_target_h == 1 then
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllLeft"):set_visible(true)
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllRight"):set_visible(false)
+                else
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllLeft"):set_visible(false)
+                    ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllRight"):set_visible(true)
+                end
+            else
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllLeft"):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.CursorAllRight"):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_visible(true)
+
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_default_animation("Position" .. tostring(self.cursor_target_h) .. "_" .. tostring(self.cursor_target_v))
+                ui_manager:get_widget("BattleUi.Container.Bottom.Target.Cursor"):set_visible(true)
+            end
+        end
+    end,
+
+    --- Populates the magic selction window.
+    --
+    -- It uses the magics the current character can use.
     populate_magic_list = function(self)
     populate_magic_list = function(self)
         local magic = self.party[self.current_character_window].magic
         local magic = self.party[self.current_character_window].magic
         for pos = 1, 4 do
         for pos = 1, 4 do
             if magic[pos + self.first_list - 1] == nil then
             if magic[pos + self.first_list - 1] == nil then
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.List.List" .. tostring(pos)
-                ):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.List.List" .. tostring(pos)):set_visible(false)
             else
             else
-                print("ADDING MAGIC " .. tostring(magic[pos + self.first_list - 1].id))
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.List.List" .. tostring(pos)
-                ):set_text(Game.Attacks[magic[pos + self.first_list - 1].id].name)
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.List.List" .. tostring(pos)
-                ):set_visible(true)
+                ui_manager:get_widget("BattleUi.Container.Bottom.List.List" .. tostring(pos)):set_text(Game.Attacks[magic[pos + self.first_list - 1].id].name)
+                ui_manager:get_widget("BattleUi.Container.Bottom.List.List" .. tostring(pos)):set_visible(true)
             end
             end
         end
         end
     end,
     end,
 
 
+    --- Populates the summon selction window.
+    --
+    -- It uses the summons the current character can use.
     populate_summon_list = function(self)
     populate_summon_list = function(self)
         local summon = self.party[self.current_character_window].summon
         local summon = self.party[self.current_character_window].summon
         for pos = 1, 4 do
         for pos = 1, 4 do
             if summon[pos + self.first_list - 1] == nil then
             if summon[pos + self.first_list - 1] == nil then
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.List.List" .. tostring(pos)
-                ):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.List.List" .. tostring(pos)):set_visible(false)
             else
             else
-                print("ADDING SUMMON " .. tostring(summon[pos + self.first_list - 1].id))
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.List.List" .. tostring(pos)
-                ):set_text(Game.Attacks[summon[pos + self.first_list - 1].id].name)
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.List.List" .. tostring(pos)
-                ):set_visible(true)
+                ui_manager:get_widget("BattleUi.Container.Bottom.List.List" .. tostring(pos)):set_text(Game.Attacks[summon[pos + self.first_list - 1].id].name)
+                ui_manager:get_widget("BattleUi.Container.Bottom.List.List" .. tostring(pos)):set_visible(true)
             end
             end
         end
         end
     end,
     end,
 
 
+    --- Load enemies
+    load_enemies = function(self)
+        local total = battle_manager:get_enemy_count()
+        for e = 0, total - 1 do
+            local enemy_src = battle_manager:get_enemy(e)
+            enemy = {}
+            enemy.dead = false
+            enemy.atb = math.random(0, 255)
+            enemy.id = enemy_src:get_id()
+            enemy.level = enemy_src:get_level()
+            enemy.name = enemy_src:get_name()
+            enemy.exp = enemy_src:get_exp()
+            enemy.ap = enemy_src:get_ap()
+            enemy.money = enemy_src:get_money()
+            enemy.stats = {}
+            enemy.stats.str = enemy_src:get_str();
+            enemy.stats.def = enemy_src:get_def();
+            enemy.stats.mag = enemy_src:get_mag();
+            enemy.stats.spr = enemy_src:get_spr();
+            enemy.stats.dex = enemy_src:get_dex();
+            enemy.stats.lck = enemy_src:get_lck();
+            enemy.stats.eva = enemy_src:get_eva();
+            enemy.stats.meva = enemy_src:get_meva();
+            enemy.stats.hp = enemy_src:get_hp();
+            enemy.stats.hp_max = enemy_src:get_hp_max();
+            enemy.stats.mp = enemy_src:get_mp();
+            enemy.stats.mp_max = enemy_src:get_mp_max();
+            -- TODO: Get more data
+            table.insert(self.enemies, enemy)
+        end
+    end,
+
     --- Loads party character data
     --- Loads party character data
     --
     --
     -- Reads materia, calculates stats, computes attacks...
     -- Reads materia, calculates stats, computes attacks...
@@ -396,23 +757,17 @@ UiContainer.BattleUi = {
                 -- Fill Limit UI bar
                 -- Fill Limit UI bar
                 -- 0   -> 0%
                 -- 0   -> 0%
                 -- 255 -> 18%-6
                 -- 255 -> 18%-6
-                local width_percent = math.min(
-                  18, 18 * Characters[self.party[i].character].limit.bar / 255
-                )
+                local width_percent = math.min(18, 18 * Characters[self.party[i].character].limit.bar / 255)
                 local width_fixed = math.max(-6, -6 * width_percent / 18)
                 local width_fixed = math.max(-6, -6 * width_percent / 18)
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.LimitFill"
-                ):set_width(width_percent, width_fixed)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.LimitFill"):set_width(width_percent, width_fixed)
                 -- Read materia
                 -- Read materia
                 local w_magic = false
                 local w_magic = false
                 local w_item = false
                 local w_item = false
                 local w_summon = false
                 local w_summon = false
                 for e = 1, 2 do -- Loop for weapon, armor
                 for e = 1, 2 do -- Loop for weapon, armor
                     local equip = nil
                     local equip = nil
-                    if e == 1 then
-                        equip = Characters[Party[i]].weapon
-                    else
-                        equip = Characters[Party[i]].armor
+                    if e == 1 then equip = Characters[Party[i]].weapon
+                    else equip = Characters[Party[i]].armor
                     end
                     end
 
 
                     for m = 1, 8 do -- lop for materia in weapon/armor
                     for m = 1, 8 do -- lop for materia in weapon/armor
@@ -420,11 +775,7 @@ UiContainer.BattleUi = {
                             local materia = Game.Materia[equip.materia[m - 1].id]
                             local materia = Game.Materia[equip.materia[m - 1].id]
                             local ap = equip.materia[m - 1].ap
                             local ap = equip.materia[m - 1].ap
                             local level = 0
                             local level = 0
-                            for l = 1, #materia.levels_ap do
-                                if materia.levels_ap[l] <= ap then
-                                    level = l
-                                end
-                            end
+                            for l = 1, #materia.levels_ap do if materia.levels_ap[l] <= ap then level = l end end
                             if materia.type == 5 then -- Summon
                             if materia.type == 5 then -- Summon
                                 summon = {
                                 summon = {
                                     id = materia.summon,
                                     id = materia.summon,
@@ -462,24 +813,16 @@ UiContainer.BattleUi = {
                             elseif materia.type == 3 then -- Command
                             elseif materia.type == 3 then -- Command
                                 -- Pick only the highest level command available
                                 -- Pick only the highest level command available
                                 local command_id = nil
                                 local command_id = nil
-                                for lv, cmd in ipairs(materia.command) do
-                                    if level >= lv then
-                                        command_id = cmd
-                                    end
-                                end
+                                for lv, cmd in ipairs(materia.command) do if level >= lv then command_id = cmd end end
                                 if command_id ~= nil then
                                 if command_id ~= nil then
-                                    if
-                                      command_id == 1 or command_id == 20 or command_id == 24
-                                      or command_id == 25 or command_id == 26 or command_id == 26
-                                    then
+                                    if command_id == 1 or command_id == 20 or command_id == 24 or command_id == 25 or command_id == 26 or command_id == 26 then
                                         -- Attack substitutes, index 1
                                         -- Attack substitutes, index 1
                                         -- TODO: Handle priorities
                                         -- TODO: Handle priorities
                                         -- 1: Attack, 20: Limit, 24: Slash-all,
                                         -- 1: Attack, 20: Limit, 24: Slash-all,
                                         -- 25: 2x-Cut, 26: Flash, 27: 4x-Cut
                                         -- 25: 2x-Cut, 26: Flash, 27: 4x-Cut
                                         self.party[i].command[1] = command_id
                                         self.party[i].command[1] = command_id
                                     else
                                     else
-                                        self.party[i].command[#self.party[i].command + 1]
-                                          = command_id
+                                        self.party[i].command[#self.party[i].command + 1] = command_id
                                     end
                                     end
                                     if command_id == 21 then w_magic = true end
                                     if command_id == 21 then w_magic = true end
                                     if command_id == 22 then w_summon = true end
                                     if command_id == 22 then w_summon = true end
@@ -496,35 +839,22 @@ UiContainer.BattleUi = {
                 if w_item == false then self.party[i].command[#self.party[i].command + 1] = 4 end
                 if w_item == false then self.party[i].command[#self.party[i].command + 1] = 4 end
 
 
                 -- Enable Magic command if any magic is available and W-Magic is disabled.
                 -- Enable Magic command if any magic is available and W-Magic is disabled.
-                if #self.party[i].magic > 0 and w_magic == false then
-                    self.party[i].command[#self.party[i].command + 1] = 2
-                end
+                if #self.party[i].magic > 0 and w_magic == false then self.party[i].command[#self.party[i].command + 1] = 2 end
                 -- Enable Summon command if any magic is available and W-Summon is disabled.
                 -- Enable Summon command if any magic is available and W-Summon is disabled.
-                if #self.party[i].summon > 0 and w_summon == false then
-                    self.party[i].command[#self.party[i].command + 1] = 3
-                end
+                if #self.party[i].summon > 0 and w_summon == false then self.party[i].command[#self.party[i].command + 1] = 3 end
                 -- TODO: Sort commands/magic/summons
                 -- TODO: Sort commands/magic/summons
                 table.sort(
                 table.sort(
                   self.party[i].command,
                   self.party[i].command,
                   function(l, r)
                   function(l, r)
                       -- Attack substitutes always go first
                       -- Attack substitutes always go first
-                      if l == 1 or l == 20 or l == 24 or l == 25 or l == 26 or l == 26 then
-                          return true
-                      else
-                          return l < r
+                      if l == 1 or l == 20 or l == 24 or l == 25 or l == 26 or l == 26 then return true
+                      else return l < r
                       end
                       end
                   end
                   end
                 )
                 )
 
 
-                if #self.party[i].magic > 1 then
-                    print("SORT MAGIC " .. tostring(i))
-                    table.sort(self.party[i].magic, function(l, r) return l.id < r.id end)
-                end
-                if #self.party[i].summon > 1 then
-                    print("SORT SUMMON " .. tostring(i))
-                    table.sort(self.party[i].summon, function(l, r) return l.id < r.id end)
-                end
-                print("ALL SORTED " .. tostring(i))
+                if #self.party[i].magic > 1 then table.sort(self.party[i].magic, function(l, r) return l.id < r.id end) end
+                if #self.party[i].summon > 1 then table.sort(self.party[i].summon, function(l, r) return l.id < r.id end) end
             end
             end
         end
         end
     end,
     end,
@@ -537,23 +867,19 @@ UiContainer.BattleUi = {
         ui_manager:get_widget("BattleUi"):set_visible(true)
         ui_manager:get_widget("BattleUi"):set_visible(true)
         self.active = true;
         self.active = true;
 
 
-        -- Lopad party data
+        -- Lopad combatant data
         self:load_party_members()
         self:load_party_members()
+        self:load_enemies()
 
 
         -- Set various transparencies
         -- Set various transparencies
         ui_manager:get_widget("BattleUi.Container.Help.Center"):set_alpha(0.5)
         ui_manager:get_widget("BattleUi.Container.Help.Center"):set_alpha(0.5)
         ui_manager:get_widget("BattleUi.Container.Message.Center"):set_alpha(0.5)
         ui_manager:get_widget("BattleUi.Container.Message.Center"):set_alpha(0.5)
         ui_manager:get_widget("BattleUi.Container.Message.Center"):set_alpha(0.5)
         ui_manager:get_widget("BattleUi.Container.Message.Center"):set_alpha(0.5)
         for i = 1, #self.party do
         for i = 1, #self.party do
-            ui_manager:get_widget(
-              "BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.AtbFill"
-            ):set_alpha(0.45)
-            ui_manager:get_widget(
-              "BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.LimitFill"
-            ):set_alpha(0.45)
+            ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.AtbFill"):set_alpha(0.45)
+            ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(i) .. ".Right.LimitFill"):set_alpha(0.45)
         end
         end
 
 
-
         -- DEBUG:
         -- DEBUG:
         --ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Center"):set_alpha(0.5)
         --ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Center"):set_alpha(0.5)
         --self:show_commands(1)
         --self:show_commands(1)
@@ -561,8 +887,8 @@ UiContainer.BattleUi = {
         return 0;
         return 0;
     end,
     end,
 
 
-    ---
-    -- Shows the command window for a character
+    --- Shows the command window for a character
+    --
     -- @param party_id The ID of the party member whose commands to show
     -- @param party_id The ID of the party member whose commands to show
     show_commands = function(self, party_id)
     show_commands = function(self, party_id)
         self.current_character_window = party_id
         self.current_character_window = party_id
@@ -570,47 +896,28 @@ UiContainer.BattleUi = {
         self.window_state = "command"
         self.window_state = "command"
         -- Colour the character name
         -- Colour the character name
         for c = 1, #self.party do
         for c = 1, #self.party do
-            if c == party_id then
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"
-                ):set_colour(1, 1, 0)
-            else
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"
-                ):set_colour(1, 1, 1)
+            if c == party_id then ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name" ):set_colour(1, 1, 0)
+            else ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"):set_colour(1, 1, 1)
             end
             end
-            ui_manager:get_widget(
-              "BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"
-            ):set_text(Characters[Party[c]].name)
+            ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"):set_text(Characters[Party[c]].name)
         end
         end
         -- Show command names
         -- Show command names
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_visible(false)
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_visible(false)
         local total_commands = 0
         local total_commands = 0
         for c = 1, 12 do
         for c = 1, 12 do
-            if self.party[party_id].command[c] == nil then
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Commands.Cmd" .. tostring(c)
-                ):set_visible(false)
+            if self.party[party_id].command[c] == nil then ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Cmd" .. tostring(c)):set_visible(false)
             else
             else
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Commands.Cmd" .. tostring(c)
-                ):set_text(Game.Commands[self.party[party_id].command[c]].name)
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Commands.Cmd" .. tostring(c)
-                ):set_visible(true)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Cmd" .. tostring(c)):set_text(Game.Commands[self.party[party_id].command[c]].name)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Cmd" .. tostring(c)):set_visible(true)
                 total_commands = total_commands + 1
                 total_commands = total_commands + 1
             end
             end
         end
         end
         -- Resize the window
         -- Resize the window
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_visible(false)
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_visible(false)
-        ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_width(
-          60 * (1 + math.floor(total_commands / 4))
-        )
+        ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_width(60 * (1 + math.floor(total_commands / 4)))
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_visible(true)
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands"):set_visible(true)
         -- Set and show cursor
         -- Set and show cursor
-        ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Cursor"):set_default_animation(
-          "Position" .. tostring(self.cursor_command)
-        )
+        ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Cursor"):set_default_animation("Position" .. tostring(self.cursor_command))
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Cursor"):set_visible(true)
         ui_manager:get_widget("BattleUi.Container.Bottom.Commands.Cursor"):set_visible(true)
         self.window_state = "command"
         self.window_state = "command"
 
 
@@ -620,48 +927,29 @@ UiContainer.BattleUi = {
     --
     --
     -- It also sets this widget to inactive.
     -- It also sets this widget to inactive.
     hide = function(self)
     hide = function(self)
-
         ui_manager:get_widget("BattleUi"):set_visible(false)
         ui_manager:get_widget("BattleUi"):set_visible(false)
         self.active = false
         self.active = false
-
-        --MenuSettings.pause_available = true
-        --entity_manager:set_paused(false)
-
         return 0;
         return 0;
     end,
     end,
 
 
-
+    --- Populates the battle bottom left and right pannels
     populate = function(self)
     populate = function(self)
 
 
         space_pad = function(val, length)
         space_pad = function(val, length)
             str = tostring(val)
             str = tostring(val)
-            while #(str) < length do
-                str = " " .. str
-            end
+            while #(str) < length do str = " " .. str end
             return str
             return str
         end
         end
 
 
         for c = 1, 3 do
         for c = 1, 3 do
             if Party[c] ~= nil then
             if Party[c] ~= nil then
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c)
-                ):set_visible(true)
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"
-                ):set_text(Characters[Party[c]].name)
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Hp.HpCurrent"
-                ):set_text(space_pad(Characters[Party[c]].stats.hp.current, 5))
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Hp.HpMax"
-                ):set_text(space_pad(Characters[Party[c]].stats.hp.base, 5))
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Mp.MpCurrent"
-                ):set_text(space_pad(Characters[Party[c]].stats.mp.current, 5))
+                ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c)):set_visible(true)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Left.Name"):set_text(Characters[Party[c]].name)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Hp.HpCurrent"):set_text(space_pad(Characters[Party[c]].stats.hp.current, 5))
+                ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Hp.HpMax"):set_text(space_pad(Characters[Party[c]].stats.hp.base, 5))
+                ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c) .. ".Right.Mp.MpCurrent"):set_text(space_pad(Characters[Party[c]].stats.mp.current, 5))
             else
             else
-                ui_manager:get_widget(
-                  "BattleUi.Container.Bottom.Character" .. tostring(c)
-                ):set_visible(false)
+                ui_manager:get_widget("BattleUi.Container.Bottom.Character" .. tostring(c)):set_visible(false)
             end
             end
         end
         end
         return 0
         return 0

+ 1 - 0
data/data/scripts/debug_data.lua

@@ -58,6 +58,7 @@ Characters[0].armor.materia = {
     [6] = {id = 0, ap = 0},
     [6] = {id = 0, ap = 0},
     [7] = {id = 26, ap = 0},
     [7] = {id = 26, ap = 0},
 }
 }
+Characters[0].weapon.materia[0] = {id = 64, ap = 15340}
 for i = 1, 24 do -- E. Skill list
 for i = 1, 24 do -- E. Skill list
     if i == 1 or i == 6 or i == 9 or i == 13 or i == 14 or i == 15 or i == 23 or i == 24 then
     if i == 1 or i == 6 or i == 9 or i == 13 or i == 14 or i == 15 or i == 23 or i == 24 then
         Characters[0].armor.materia[2].skills[i] = true
         Characters[0].armor.materia[2].skills[i] = true

+ 7 - 0
src/core/BattleManager.cpp

@@ -190,6 +190,13 @@ void BattleManager::AddEnemy(
     )->SetRotation(Ogre::Degree(180));
     )->SetRotation(Ogre::Degree(180));
 }
 }
 
 
+unsigned int BattleManager::ScriptGetEnemyCount() const{return enemies_.size();}
+
+Enemy* BattleManager::ScriptGetEnemy(const unsigned int index){
+    if (index >= enemies_.size()) return nullptr;
+    return &enemies_[index];
+}
+
 void BattleManager::AddCamera(
 void BattleManager::AddCamera(
   const unsigned int id, const Ogre::Vector3 pos, const Ogre::Vector3 dir
   const unsigned int id, const Ogre::Vector3 pos, const Ogre::Vector3 dir
 ){
 ){

+ 20 - 0
src/core/BattleManager.h

@@ -230,6 +230,26 @@ class BattleManager : public Manager, public Ogre::Singleton<BattleManager>{
           const bool targeteable, const bool active, const std::string cover
           const bool targeteable, const bool active, const std::string cover
         );
         );
 
 
+        /**
+         * Retrieves the number of enemies in the battle.
+         *
+         * To be called from Lua scripts.
+         *
+         * @return The number of enemies in the battle formation.
+         */
+        unsigned int ScriptGetEnemyCount() const;
+
+        /**
+         * Retrieves an enemy.
+         *
+         * To be called from Lua scripts.
+         *
+         * @param[in] index The enemy index, 0 based. must be lower than reported by
+         * {@see ScriptGetEnemyCount}.
+         * @return The enemy at the selected indes, nullptr if it doesn't exists.
+         */
+        Enemy* ScriptGetEnemy(const unsigned int index);
+
         /**
         /**
          * Loads enemy info from the enemy XML enemy file.
          * Loads enemy info from the enemy XML enemy file.
          */
          */

+ 19 - 1
src/core/Enemy.cpp

@@ -99,7 +99,7 @@ const std::string Enemy::GetModel() const{return model_;}
 
 
 void Enemy::SetModel(const std::string model){model_ = model;}
 void Enemy::SetModel(const std::string model){model_ = model;}
 
 
-const Ogre::String& Enemy::GetName() const{return name_;}
+const std::string Enemy::GetName() const{return name_;}
 
 
 void Enemy::SetName(const Ogre::String& name){name_ = name;}
 void Enemy::SetName(const Ogre::String& name){name_ = name;}
 
 
@@ -216,6 +216,12 @@ Ogre::Vector3& Enemy::GetPos(){return pos_;}
 
 
 void Enemy::SetPos(const Ogre::Vector3 &pos){pos_ = pos;}
 void Enemy::SetPos(const Ogre::Vector3 &pos){pos_ = pos;}
 
 
+void Enemy::ScriptGetPos() const{
+    ScriptManager::getSingleton().AddValueToStack(pos_.x);
+    ScriptManager::getSingleton().AddValueToStack(pos_.y);
+    ScriptManager::getSingleton().AddValueToStack(pos_.z);
+}
+
 bool Enemy::IsFront() const{return front_;}
 bool Enemy::IsFront() const{return front_;}
 
 
 void Enemy::SetFront(bool front){front_ = front;}
 void Enemy::SetFront(bool front){front_ = front;}
@@ -236,6 +242,18 @@ std::string Enemy::GetCover() const{return cover_;}
 
 
 void Enemy::SetCover(std::string cover){cover_ = cover;}
 void Enemy::SetCover(std::string cover){cover_ = cover;}
 
 
+int Enemy::ScriptGetAttackCount(){return attacks_.size();}
+
+int Enemy::ScriptGetAttack(const unsigned int index){
+    if (attacks_.size() < index) return -1;
+    return attacks_[index].id;
+}
+
+int Enemy::ScriptGetCameraForAttack(const unsigned int index){
+    if (attacks_.size() < index) return -1;
+    return attacks_[index].camera;
+}
+
 void Enemy::ReadFromXml(){
 void Enemy::ReadFromXml(){
     std::string filename = std::to_string(id_);
     std::string filename = std::to_string(id_);
     while (filename.length() < 4) filename = "0" + filename;
     while (filename.length() < 4) filename = "0" + filename;

+ 41 - 1
src/core/Enemy.h

@@ -164,7 +164,7 @@ class Enemy{
          *
          *
          * @return The enemy name.
          * @return The enemy name.
          */
          */
-        const Ogre::String& GetName() const;
+        const std::string GetName() const;
 
 
         /**
         /**
          * Sets the enemy name.
          * Sets the enemy name.
@@ -552,6 +552,14 @@ class Enemy{
          */
          */
         void SetPos(const Ogre::Vector3 &pos);
         void SetPos(const Ogre::Vector3 &pos);
 
 
+        /**
+         * Retrieves the enemy position.
+         *
+         * To be used from Lua scripts only. It doesn't return anything, but adds three values to
+         * the stack for the X, Y and Z coordinates.
+         */
+        void ScriptGetPos() const;
+
         /**
         /**
          * Checks if the enemy is in the front row.
          * Checks if the enemy is in the front row.
          *
          *
@@ -628,6 +636,38 @@ class Enemy{
          */
          */
         void SetCover(std::string cover);
         void SetCover(std::string cover);
 
 
+        /**
+         * Retrieves the number of attacks of the enemy.
+         *
+         * To be used from Lua scripts.
+         *
+         * @return The number of attacks.
+         */
+        int ScriptGetAttackCount();
+
+        /**
+         * Retrieves an attack.
+         *
+         * To be used from Lua scripts.
+         *
+         * @param[in] index The index of the attack to retrieve. Must be lower than reported by
+         * {@see ScriptGetAttackCount}.
+         * @return The ID of the attack in the specified index, or -1 if no such attack exists.
+         */
+        int ScriptGetAttack(const unsigned int index);
+
+        /**
+         * Retrieves the camera for an attack.
+         *
+         * To be used from Lua scripts.
+         *
+         * @param[in] index The index of the attack to retrieve. Must be lower than reported by
+         * {@see ScriptGetAttackCount}.
+         * @return The ID of camera associated to the attack. -1 if no such attack exists or if it
+         * doesn't have an specific camera associated.
+         */
+        int ScriptGetCameraForAttack(const unsigned int index);
+
     private:
     private:
 
 
         /**
         /**

+ 3 - 2
src/core/Entity.h

@@ -232,9 +232,10 @@ class Entity{
         const Ogre::Vector3 GetPosition() const;
         const Ogre::Vector3 GetPosition() const;
 
 
         /**
         /**
-         * Informs the script manager of the entity position.
+         * Retrieves the entity position.
          *
          *
-         * @todo Im not really sure what this actually does.
+         * To be used from Lua scripts only. It doesn't return anything, but adds three values to
+         * the stack for the X, Y and Z coordinates.
          */
          */
         void ScriptGetPosition() const;
         void ScriptGetPosition() const;
 
 

+ 47 - 0
src/core/ScriptManagerBinds.h

@@ -19,6 +19,7 @@
 #include "Console.h"
 #include "Console.h"
 #include "Logger.h"
 #include "Logger.h"
 #include "CameraManager.h"
 #include "CameraManager.h"
+#include "Enemy.h"
 #include "Entity.h"
 #include "Entity.h"
 #include "EntityManager.h"
 #include "EntityManager.h"
 #include "BattleManager.h"
 #include "BattleManager.h"
@@ -270,8 +271,54 @@ void ScriptManager::InitBinds(){
             "start_battle", (void(BattleManager::*)(const unsigned int)) &BattleManager::StartBattle
             "start_battle", (void(BattleManager::*)(const unsigned int)) &BattleManager::StartBattle
           )
           )
           .def("end_battle", (void(BattleManager::*)()) &BattleManager::EndBattle)
           .def("end_battle", (void(BattleManager::*)()) &BattleManager::EndBattle)
+          .def("get_enemy_count", (int(BattleManager::*)()) &BattleManager::ScriptGetEnemyCount)
+          .def(
+            "get_enemy",
+            (Enemy*(BattleManager::*)(const unsigned int)) &BattleManager::ScriptGetEnemy
+          )
     ];
     ];
 
 
+    // Commands for enemy handling.
+    luabind::module(lua_state_)[
+    luabind::class_<Enemy>("Enemy")
+      .def("get_id", (int(Enemy::*)()) &Enemy::GetId)
+      .def("get_name", (std::string(Enemy::*)()) &Enemy::GetName)
+      .def("get_level", (int(Enemy::*)()) &Enemy::GetLevel)
+      .def("get_ap", (int(Enemy::*)()) &Enemy::GetAp)
+      .def("get_exp", (int(Enemy::*)()) &Enemy::GetExp)
+      .def("get_money", (int(Enemy::*)()) &Enemy::GetMoney)
+      .def("get_str", (int(Enemy::*)()) &Enemy::GetStr)
+      .def("get_def", (int(Enemy::*)()) &Enemy::GetDef)
+      .def("get_mag", (int(Enemy::*)()) &Enemy::GetMag)
+      .def("get_spr", (int(Enemy::*)()) &Enemy::GetSpr)
+      .def("get_dex", (int(Enemy::*)()) &Enemy::GetDex)
+      .def("get_lck", (int(Enemy::*)()) &Enemy::GetLck)
+      .def("get_eva", (int(Enemy::*)()) &Enemy::GetEva)
+      .def("get_meva", (int(Enemy::*)()) &Enemy::GetMeva)
+      .def("get_hp", (int(Enemy::*)()) &Enemy::GetHp)
+      .def("get_hp_max", (int(Enemy::*)()) &Enemy::GetHpMax)
+      .def("get_mp", (int(Enemy::*)()) &Enemy::GetMp)
+      .def("get_mp_max", (int(Enemy::*)()) &Enemy::GetMpMax)
+      .def("get_position", (void(Enemy::*)()) &Enemy::ScriptGetPos)
+      .def("is_front", (bool(Enemy::*)()) &Enemy::IsFront)
+      .def("is_visible", (bool(Enemy::*)()) &Enemy::IsVisible)
+      .def("is_targeteable", (bool(Enemy::*)()) &Enemy::IsTargeteable)
+      .def("is_active", (bool(Enemy::*)()) &Enemy::IsActive)
+      .def("get_attack_count", (int(Enemy::*)()) &Enemy::ScriptGetAttackCount)
+      .def("get_attack", (int(Enemy::*)(const unsigned int)) &Enemy::ScriptGetAttack)
+      .def(
+        "get_camera_for_attack",
+        (int(Enemy::*)(const unsigned int)) &Enemy::ScriptGetCameraForAttack
+      )
+      // TODO: Implement cover flags.
+      // TODO: Implement immunities
+      // TODO: Implement elements
+      // TODO: Implement item drops
+      // TODO: Implement stealable items
+      // TODO: Implement manipulability status and attacks.
+      // TODO: Implement morph item
+];
+
     // Commands for the audio manager.
     // Commands for the audio manager.
     luabind::module(lua_state_)[
     luabind::module(lua_state_)[
         luabind::class_<AudioManager>("AudioManager")
         luabind::class_<AudioManager>("AudioManager")

+ 3 - 2
src/installer/KernelDataInstaller.cpp

@@ -111,8 +111,9 @@ int KernelDataInstaller::ReadCommands(){
         else data.target.selection_enabled = false;
         else data.target.selection_enabled = false;
         if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
         if (data.target_raw == (data.target_raw | 0x02)) data.target.default_enemy = true;
         else data.target.default_enemy = false;
         else data.target.default_enemy = false;
-        if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = true;
-        else data.target.default_multiple = false;
+        // Default multiple is inverted
+        if (data.target_raw == (data.target_raw | 0x04)) data.target.default_multiple = false;
+        else data.target.default_multiple = true;
         if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
         if (data.target_raw == (data.target_raw | 0x08)) data.target.toggle_multiple = true;
         else data.target.toggle_multiple = false;
         else data.target.toggle_multiple = false;
         if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;
         if (data.target_raw == (data.target_raw | 0x10)) data.target.fixed_row = true;