1-- This file is scripting Kalya's attack animation, called by attack skills, in case she is attacking every foes at once. 2-- The initialize() function is called once, followed by calls to the update function. 3-- When the update function returns true, the attack is finished. 4 5-- Set the namespace 6local ns = {}; 7setmetatable(ns, {__index = _G}); 8kalya_attack_party_target = ns; 9setfenv(1, ns); 10 11-- local references 12local Battle = nil; 13local character = nil 14local target = nil 15-- An array referencing all the necessary data about the quarrels triggered. 16local target_arrows = {} 17local skill = nil 18 19local global_attack_step = 0; 20local global_attack_time = 0.0; 21 22-- character, the BattleActor attacking (here Kalya) 23-- target, the BattleEnemy target 24-- The skill id used on target 25function Initialize(_character, _target, _skill) 26 -- Keep the reference in memory 27 character = _character; 28 target = _target; 29 skill = _skill; 30 Battle = ModeManager:GetTop(); 31 32 local ammo_filename = character:GetAmmoAnimationFile(); 33 34 -- Don't attack if the character isn't alive 35 if (character:IsAlive() == false) then 36 return; 37 end 38 39 global_attack_step = 0; 40 global_attack_time = 0.0; 41 42 -- Register all the valid actors in the arrow table 43 local index = 0; 44 while (target:GetPartyActor(index) ~= nil) do 45 local actor = target:GetPartyActor(index) 46 if (actor:CanFight() == true) then 47 target_arrows[index] = {}; 48 target_arrows[index].actor = actor 49 end 50 51 index = index + 1 52 end 53 54 -- Register each arrows data 55 for index, arrow_info in pairs(target_arrows) do 56 -- Set the arrow flying height members 57 arrow_info.arrow_height = (character:GetSpriteHeight() / 2.0) + 5.0; 58 arrow_info.total_distance = math.abs(arrow_info.actor:GetXLocation() - character:GetXLocation()); 59 arrow_info.height_diff = arrow_info.arrow_height - (arrow_info.actor:GetSpriteHeight() / 2.0); 60 arrow_info.height_min = math.min(arrow_info.arrow_height, (arrow_info.actor:GetSpriteHeight() / 2.0)); 61 62 -- Set the arrow starting position 63 arrow_info.arrow_pos_x = character:GetXLocation() + character:GetSpriteWidth() / 2.0; 64 arrow_info.arrow_pos_y = character:GetYLocation() - arrow_info.arrow_height; 65 66 -- Make the arrow reach the enemy center 67 arrow_info.enemy_pos_x = arrow_info.actor:GetXLocation(); 68 arrow_info.enemy_pos_y = arrow_info.actor:GetYLocation() - arrow_info.actor:GetSpriteHeight() / 2.0; 69 70 distance_moved_x = SystemManager:GetUpdateTime() / vt_map.MapMode.NORMAL_SPEED * 210.0; 71 local x_diff = arrow_info.enemy_pos_x - arrow_info.arrow_pos_x; 72 local y_diff = arrow_info.arrow_pos_y - arrow_info.enemy_pos_y; 73 74 local a_coeff = 0.0; 75 local distance_moved_x = 0.0; 76 local distance_moved_y = 0.0; 77 78 if (y_diff == 0.0) then 79 a_coeff = 0.0; 80 distance_moved_y = 0.0; 81 elseif (x_diff == 0.0) then 82 a_coeff = 0.0; 83 distance_moved_y = distance_moved_x; 84 distance_moved_x = 0.0; 85 else 86 a_coeff = y_diff / x_diff; 87 if (a_coeff < 0) then a_coeff = -a_coeff; end 88 distance_moved_y = a_coeff * distance_moved_x; 89 end 90 arrow_info.a_coeff = a_coeff; 91 arrow_info.distance_moved_x = distance_moved_x; 92 arrow_info.distance_moved_y = distance_moved_y; 93 94 arrow_info.attack_step = 0; 95 arrow_info.damage_triggered = false; 96 97 -- Set Kalya's missile sprites 98 arrow_info.arrow = Battle:CreateBattleAnimation(ammo_filename); 99 arrow_info.arrow_shadow = Battle:CreateBattleAnimation(ammo_filename); 100 arrow_info.arrow_shadow:GetAnimatedImage():SetGrayscale(true); 101 102 -- splash images 103 arrow_info.splash_image = Battle:CreateBattleAnimation("data/entities/battle/effects/hit_splash.lua"); 104 arrow_info.splash_image:SetVisible(false); 105 arrow_info.splash_width = arrow_info.splash_image:GetAnimatedImage():GetWidth() 106 arrow_info.splash_height = arrow_info.splash_image:GetAnimatedImage():GetHeight() 107 108 index = index + 1 109 end 110end 111 112 113function Update() 114 115 -- Attack the enemy 116 if (global_attack_step == 0) then 117 character:ChangeSpriteAnimation("attack") 118 global_attack_step = 1 119 return false; 120 end 121 -- Make the character go back to idle once attacked 122 if (global_attack_step == 1) then 123 global_attack_time = global_attack_time + SystemManager:GetUpdateTime(); 124 if (global_attack_time > 750.0) then 125 character:ChangeSpriteAnimation("idle") 126 global_attack_step = 2; 127 end 128 return false; 129 end 130 131 for index, arrow_info in pairs(target_arrows) do 132 133 -- Make the shadow visible 134 if (arrow_info.attack_step == 0) then 135 136 if (arrow_info.arrow ~= nil) then 137 arrow_info.arrow:SetVisible(true); 138 arrow_info.arrow:SetXLocation(arrow_info.arrow_pos_x); 139 arrow_info.arrow:SetYLocation(arrow_info.arrow_pos_y); 140 end 141 142 if (arrow_info.arrow_shadow ~= nil) then 143 arrow_info.arrow_shadow:SetVisible(true); 144 arrow_info.arrow_shadow:SetXLocation(arrow_info.arrow_pos_x); 145 arrow_info.arrow_shadow:SetYLocation(arrow_info.arrow_pos_y + arrow_info.arrow_height); 146 end 147 148 arrow_info.attack_step = 1 149 end 150 151 -- The update time can vary, so update the distance on each update as well. 152 arrow_info.distance_moved_x = SystemManager:GetUpdateTime() / vt_map.MapMode.NORMAL_SPEED * 210.0; 153 if (arrow_info.a_coeff ~= 0.0) then 154 arrow_info.distance_moved_y = arrow_info.a_coeff * arrow_info.distance_moved_x; 155 end 156 157 -- Make the speed the same whatever the angle between the character and the enemy is. 158 -- We deal only with a coefficients > 1.0 for simplification purpose. 159 if (arrow_info.a_coeff > 1.0 and arrow_info.distance_moved_x ~= 0.0 and arrow_info.distance_moved_y ~= 0.0) then 160 arrow_info.distance_moved_x = arrow_info.distance_moved_x * (arrow_info.distance_moved_x / arrow_info.distance_moved_y); 161 if (arrow_info.a_coeff ~= 0.0) then 162 arrow_info.distance_moved_y = arrow_info.a_coeff * arrow_info.distance_moved_x; 163 end 164 --print ("new_ratio: ", arrow_info.a_coeff, arrow_info.distance_moved_x / arrow_info.distance_moved_y) 165 end 166 167 -- Update the arrow flying height according to the distance 168 -- Get the % of of x distance left 169 local distance_left = math.abs((arrow_info.arrow_pos_x + arrow_info.distance_moved_x) - arrow_info.enemy_pos_x); 170 171 if (arrow_info.total_distance > 0.0) then 172 if (arrow_info.height_diff > 0.0) then 173 arrow_info.arrow_height = arrow_info.height_min + ((distance_left / arrow_info.total_distance) * arrow_info.height_diff); 174 else 175 arrow_info.arrow_height = arrow_info.height_min + (((arrow_info.total_distance - distance_left) / arrow_info.total_distance) * -arrow_info.height_diff); 176 end 177 end 178 179 -- Triggers the arrow animation 180 if (arrow_info.attack_step == 1) then 181 if (arrow_info.arrow_pos_x > arrow_info.enemy_pos_x) then 182 arrow_info.arrow_pos_x = arrow_info.arrow_pos_x - arrow_info.distance_moved_x; 183 if arrow_info.arrow_pos_x < arrow_info.enemy_pos_x then arrow_info.arrow_pos_x = arrow_info.enemy_pos_x end 184 end 185 if (arrow_info.arrow_pos_x < arrow_info.enemy_pos_x) then 186 arrow_info.arrow_pos_x = arrow_info.arrow_pos_x + arrow_info.distance_moved_x; 187 if arrow_info.arrow_pos_x > arrow_info.enemy_pos_x then arrow_info.arrow_pos_x = arrow_info.enemy_pos_x end 188 end 189 if (arrow_info.arrow_pos_y > arrow_info.enemy_pos_y) then 190 arrow_info.arrow_pos_y = arrow_info.arrow_pos_y - arrow_info.distance_moved_y; 191 if arrow_info.arrow_pos_y < arrow_info.enemy_pos_y then arrow_info.arrow_pos_y = arrow_info.enemy_pos_y end 192 end 193 if (arrow_info.arrow_pos_y < arrow_info.enemy_pos_y) then 194 arrow_info.arrow_pos_y = arrow_info.arrow_pos_y + arrow_info.distance_moved_y; 195 if arrow_info.arrow_pos_y > arrow_info.enemy_pos_y then arrow_info.arrow_pos_y = arrow_info.enemy_pos_y end 196 end 197 198 -- Updates the arrow location 199 if (arrow_info.arrow ~= nil) then 200 arrow_info.arrow:SetXLocation(arrow_info.arrow_pos_x); 201 arrow_info.arrow:SetYLocation(arrow_info.arrow_pos_y); 202 end 203 204 if (arrow_info.arrow_shadow ~= nil) then 205 arrow_info.arrow_shadow:SetXLocation(arrow_info.arrow_pos_x); 206 arrow_info.arrow_shadow:SetYLocation(arrow_info.arrow_pos_y + arrow_info.arrow_height); 207 end 208 209 if (arrow_info.arrow_pos_x >= arrow_info.enemy_pos_x and arrow_info.arrow_pos_y == arrow_info.enemy_pos_y) then 210 arrow_info.attack_step = 2; 211 end 212 end 213 214 if (arrow_info.attack_step == 2) then 215 -- Remove the arrow has reached the enemy 216 if (arrow_info.damage_triggered == false) then 217 arrow_info.damage_triggered = true; 218 if (arrow_info.arrow ~= nil) then 219 arrow_info.arrow:SetVisible(false); 220 arrow_info.arrow:Remove(); 221 arrow_info.arrow = nil; 222 end 223 if (arrow_info.arrow_shadow ~= nil) then 224 arrow_info.arrow_shadow:SetVisible(false); 225 arrow_info.arrow_shadow:Remove(); 226 arrow_info.arrow_shadow = nil; 227 end 228 -- Show the hit splash image 229 arrow_info.splash_image:SetXLocation(arrow_info.arrow_pos_x); 230 arrow_info.splash_image:SetYLocation(arrow_info.arrow_pos_y); 231 arrow_info.splash_image:SetVisible(true); 232 arrow_info.splash_image:Reset(); 233 arrow_info.splash_time = 0; 234 end 235 arrow_info.attack_step = 3 236 end 237 238 -- Update the splash image 239 if (arrow_info.attack_step == 3) then 240 arrow_info.splash_time = arrow_info.splash_time + SystemManager:GetUpdateTime(); 241 arrow_info.splash_image:GetAnimatedImage():SetDimensions(arrow_info.splash_width * arrow_info.splash_time / 100.0, 242 arrow_info.splash_height * arrow_info.splash_time / 100.0) 243 if (arrow_info.splash_time > 100) then 244 if (arrow_info.splash_image ~= nil) then 245 arrow_info.splash_image:SetVisible(false); 246 arrow_info.splash_image:Remove(); 247 arrow_info.splash_image = nil; 248 end 249 arrow_info.attack_step = 4; 250 end 251 end 252 end 253 254 -- Check whether every target has received an arrow 255 for index, arrow_info in pairs(target_arrows) do 256 if (arrow_info.attack_step < 4) then 257 return false; 258 end 259 end 260 261 -- Remove the skill points at the end of all attacks 262 skill:ExecuteBattleFunction(character, target); 263 character:SubtractSkillPoints(skill:GetSPRequired()); 264 return true; 265end 266