battle.lua 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. FFVII.Battle = {}
  2. FFVII.Battle.Action = {
  3. MONSTER_ACTION = 32,
  4. }
  5. FFVII.Battle.Row = {
  6. BACK = 0,
  7. FRONT = 1,
  8. }
  9. FFVII.Battle.Type = {
  10. ENEMY = 0,
  11. ALLY = 1,
  12. LOGIC = 2,
  13. }
  14. FFVII.Battle.ActionDefaults = {
  15. [ FFVII.Battle.Action.MONSTER_ACTION ] = { animation_script = "0" }
  16. }
  17. FFVII.Battle.AttackHitChance = {
  18. PhysicalCritical = 1, -- 0x01 upper 4 bits of formula
  19. }
  20. FFVII.Battle.Damage = {
  21. Physical = 1, -- 0x01 lower 4 bits of formula
  22. }
  23. FFVII.Battle.logic_script = {
  24. unit_type = FFVII.Battle.Type.LOGIC,
  25. battle_speed = 0,
  26. game_timer = 0,
  27. enemy_number = 0,
  28. ally_number = 0,
  29. command_queue = {},
  30. temp_data = {
  31. attacker = nil, -- 0x00
  32. -- 0x04 attacker level. We don't this. Instead we use direct data from copied attacker (0x00)
  33. -- 0x10 attack index. We don't this. Instead we use direct data from copied attack (0x2c)
  34. target = nil, -- 0x18
  35. attack = nil, -- 0x2c
  36. -- 0x40 formula. We don't this. Instead we use direct data from copied attack (0x2c)
  37. -- 0x48 power modifier. We don't this. Instead we use direct data from copied attack (0x2c)
  38. base_damage = 0, -- 0x4c
  39. -- 0xa0 upper formula. We don't this. Instead we use direct data from copied attack (0x2c)
  40. -- 0xa4 lower formula. We don't this. Instead we use direct data from copied attack (0x2c)
  41. calculated_defense = 0, -- 0x210
  42. calculated_damage = 0, -- 0x214
  43. },
  44. on_update = function( self )
  45. local timer = timer:get_game_time_total()
  46. local delta = timer - self.game_timer
  47. -- update timers
  48. for key, value in pairs( EntityContainer ) do
  49. if value.unit_type ~= FFVII.Battle.Type.LOGIC then
  50. if value.timer < 65535 then
  51. value.timer = value.timer + delta * 30 * value.battle_speed
  52. --print( tostring( key ) .. ".timer " .. tostring( value.timer ) )
  53. if value.timer > 65535 then
  54. print( tostring( key ) .. " performs script \"on_action\"" )
  55. script:request( Script.ENTITY, key, "on_action", 2 )
  56. end
  57. end
  58. end
  59. end
  60. self.game_timer = timer
  61. -- update command queue
  62. for key_p, value_p in pairs( self.command_queue ) do
  63. for key_c, value_c in pairs( value_p ) do
  64. FFVII.Battle.run_command( self, value_c )
  65. value_c.self.timer = 0
  66. table.remove( value_p, key_c )
  67. end
  68. end
  69. return 0
  70. end,
  71. }
  72. FFVII.Battle.init = function()
  73. EntityContainer.BattleLogic = FFVII.Battle.logic_script
  74. entity_manager:add_entity_script( "BattleLogic" )
  75. -- load players
  76. EntityContainer.Cloud = FFVII.Characters.Cloud
  77. entity_manager:add_entity( "Cloud", "models/ffvii/battle/units/first_ray.mesh", 0, 2, 0, 0 -1)
  78. -- init timer with start value
  79. EntityContainer.BattleLogic.game_timer = timer:get_game_time_total()
  80. -- init battle speed calculated from menu settings
  81. EntityContainer.BattleLogic.battle_speed = 65536 / ( ( ( FFVII.MenuSettings.battle_speed * 480 / 256 ) + 120 ) * 2 )
  82. local party_speed = 0
  83. for key, value in pairs( EntityContainer ) do
  84. if value.unit_type == FFVII.Battle.Type.ALLY then
  85. EntityContainer.BattleLogic.ally_number = EntityContainer.BattleLogic.ally_number + 1
  86. party_speed = party_speed + value.dexterity
  87. value.speed = value.dexterity + 50
  88. elseif value.unit_type == FFVII.Battle.Type.ENEMY then
  89. EntityContainer.BattleLogic.enemy_number = EntityContainer.BattleLogic.enemy_number + 1
  90. end
  91. end
  92. print( "ally_number = " .. tostring( EntityContainer.BattleLogic.ally_number ) )
  93. print( "enemy_number = " .. tostring( EntityContainer.BattleLogic.enemy_number ) )
  94. if EntityContainer.BattleLogic.ally_number > 0 then
  95. party_speed = ( party_speed - 1 + EntityContainer.BattleLogic.ally_number ) / EntityContainer.BattleLogic.ally_number + 50;
  96. for key, value in pairs( EntityContainer ) do
  97. if value.unit_type ~= FFVII.Battle.Type.LOGIC then
  98. value.battle_speed = EntityContainer.BattleLogic.battle_speed * value.speed / party_speed
  99. value.battle_speed = value.battle_speed * 2 -- normal speed (initial value calculated for slow)
  100. end
  101. end
  102. end
  103. end
  104. FFVII.Battle.run_command = function( self, command )
  105. print( "Command: attack = \"" .. command.attack.name .. "\", target = \"" .. tostring( command.target[ 1 ] ) .. "\"" )
  106. -- todo a lot of preparation
  107. EntityContainer.BattleLogic.temp_data.attacker = command.self
  108. EntityContainer.BattleLogic.temp_data.attack = command.attack
  109. EntityContainer.BattleLogic.temp_data.target = command.target
  110. -- todo a lot of preparation
  111. if command.action == FFVII.Battle.Action.MONSTER_ACTION then
  112. -- todo action_type_07
  113. -- todo action_type_0C
  114. FFVII.Battle.calculate_and_apply_damage() -- action_type_09
  115. end
  116. end
  117. -- action_type_09
  118. FFVII.Battle.calculate_and_apply_damage = function()
  119. -- todo mp check
  120. -- todo a lot of fuctions
  121. FFVII.Battle.set_base_damage()
  122. -- todo a lot of fuctions
  123. -- attack every unit in target
  124. for key, value in pairs( EntityContainer.BattleLogic.temp_data.target ) do
  125. FFVII.Battle.main_damage_calculation( value )
  126. end
  127. -- todo a lot of functions
  128. end
  129. FFVII.Battle.set_base_damage = function()
  130. -- todo force physical attack settings in physical formula
  131. -- todo use special settings for special attacks
  132. -- todo use another base damage for magic attack
  133. EntityContainer.BattleLogic.temp_data.base_damage = EntityContainer.BattleLogic.temp_data.attacker.physical_power
  134. -- todo apply damage modifier
  135. end
  136. FFVII.Battle.main_damage_calculation = function( target )
  137. -- todo a lot of fuctions
  138. FFVII.Battle.calculate_target_stats( target )
  139. -- todo a lot of fuctions
  140. FFVII.Battle.damage_formula_run()
  141. -- todo a lot of fuctions
  142. end
  143. FFVII.Battle.calculate_target_stats = function( target )
  144. -- todo a lot of initialization
  145. -- todo a lot of initialization
  146. -- todo defense check and modification
  147. EntityContainer.BattleLogic.temp_data.calculated_defense = target.physical_defense
  148. -- todo a lot of initialization
  149. if EntityContainer.BattleLogic.temp_data.calculated_defense > 512 then
  150. EntityContainer.BattleLogic.temp_data.calculated_defense = 512
  151. end
  152. -- todo sadness check
  153. end
  154. FFVII.Battle.damage_formula_run = function()
  155. -- run high formula
  156. if EntityContainer.BattleLogic.temp_data.attack.hit_chance_formula == FFVII.Battle.AttackHitChance.PhysicalCritical then
  157. FFVII.Battle.HighFormula.Physical()
  158. FFVII.Battle.HighFormula.Critical()
  159. end
  160. -- run low formula
  161. if EntityContainer.BattleLogic.temp_data.attack.power_modifier ~= 0 then
  162. -- todo add additional conditions for special attacks (A0 = 0;funca8e84;)
  163. if EntityContainer.BattleLogic.temp_data.attack.damage_formula == FFVII.Battle.Damage.Physical then
  164. FFVII.Battle.LowFormula.Physical()
  165. end
  166. -- todo add additional conditions for special attacks (A0 = 1;funca8e84;)
  167. end
  168. end
  169. FFVII.Battle.HighFormula = {}
  170. FFVII.Battle.HighFormula.Physical = function()
  171. -- todo add physical hit
  172. end
  173. FFVII.Battle.HighFormula.Critical = function()
  174. -- todo add critical hit
  175. end
  176. FFVII.Battle.LowFormula = {}
  177. FFVII.Battle.LowFormula.Physical = function()
  178. local damage = EntityContainer.BattleLogic.temp_data.base_damage
  179. -- calculate base damage
  180. damage = damage + ( ( EntityContainer.BattleLogic.temp_data.attacker.level + damage ) / 32 ) * ( ( EntityContainer.BattleLogic.temp_data.attacker.level * damage ) / 32 )
  181. -- apply attack data power
  182. damage = damage * EntityContainer.BattleLogic.temp_data.attack.power
  183. -- apply defense
  184. damage = damage * ( 512 - EntityContainer.BattleLogic.temp_data.calculated_defense ) / 512
  185. -- todo add always critical check
  186. -- todo critical damage
  187. -- todo berserk modificator
  188. -- todo back row modificator
  189. -- todo target defend
  190. -- todo attack from back
  191. -- todo a lot of status modifiers
  192. damage = FFVII.Battle.add_random_modifier_and_zero_check( damage )
  193. EntityContainer.BattleLogic.temp_data.calculated_damage = damage
  194. print( "Command: damage = \"" .. damage .. "\"." )
  195. end
  196. FFVII.Battle.add_random_modifier_and_zero_check = function( damage )
  197. local random_damage = damage * ( 15 + math.random() ) / 16;
  198. if random_damage == 0 then
  199. random_damage = 1
  200. end
  201. return random_damage
  202. end