· 6 years ago · Mar 17, 2020, 01:56 PM
1math.randomseed(tick()) --set math.randomseed to tick
2local Battle = {FinishedAttacking = true}
3--dummy variables
4local CameraShaker = require(game:GetService('ReplicatedStorage').ModuleScripts.CameraShaker);
5local Difficulty;
6local OneMore = false
7local Player = game.Players.LocalPlayer;
8local PlayerGui = Player.PlayerGui;
9local Character = Player.Character or Player.CharacterAdded:Wait();
10local RichText = require(PlayerGui:WaitForChild('RichText'))
11--note: for attacks that hit everyone, do the effect on all targets and then damage
12--useful variables
13local ReplicatedStorage = game:GetService('ReplicatedStorage')
14local Music = game:GetService('ReplicatedStorage'):WaitForChild('Music');
15local Shouts = ReplicatedStorage:WaitForChild('Shouts')
16local Items = ReplicatedStorage:WaitForChild('ModuleScripts'):WaitForChild('Items');
17Items = require(Items);
18local Attacks = ReplicatedStorage:WaitForChild("ModuleScripts"):WaitForChild('Attacks')
19Attacks = require(Attacks)
20local Personas = ReplicatedStorage:WaitForChild("ModuleScripts"):WaitForChild('PersonaList')
21Personas = require(Personas)
22local EnemyAPI = require(ReplicatedStorage:WaitForChild("ModuleScripts"):WaitForChild'EnemyAPI')
23local Effects = require(ReplicatedStorage:WaitForChild'ModuleScripts':WaitForChild('Effects'))
24local UIS = game:GetService('UserInputService');
25local E = Enum;
26local CollectionService = game:GetService('CollectionService');
27local Shake = ReplicatedStorage:WaitForChild('ModuleScripts'):WaitForChild('Shake')
28Shake = require(Shake);
29function recalculateHipHeight(TargetModel)
30 local bottomOfHumanoidRootPart = TargetModel.HumanoidRootPart.Position.Y - (1/2 * TargetModel.HumanoidRootPart.Size.Y)
31 local bottomOfFoot = TargetModel.LeftFoot.Position.Y - (1/2 * TargetModel.LeftFoot.Size.Y) -- Left or right. Chose left arbitrarily
32 local newHipHeight = bottomOfHumanoidRootPart - bottomOfFoot
33
34 return newHipHeight
35end
36local K = E.KeyCode;
37impwarn = warn;
38impprint = print;
39local currentTween;
40if not _G.Dev then
41 warn = function() end;
42 print = function() end;
43 --print = function() end;
44end
45function Battle:InvisibleParty()
46 self.InvisiblePartyFlag = not self.InvisiblePartyFlag;
47 if (self.InvisiblePartyFlag) then
48 for i, v in pairs(self.PartyContainer:GetChildren()) do
49 v.PrimaryPart.Anchored = true
50 v:SetPrimaryPartCFrame(v:GetPrimaryPartCFrame() - Vector3.new(0,200, 0))
51 end
52 Character:SetPrimaryPartCFrame(Character:GetPrimaryPartCFrame() - Vector3.new(0, 200, 0))
53 else
54 for i, v in pairs(self.PartyContainer:GetChildren()) do
55 v:SetPrimaryPartCFrame(v:GetPrimaryPartCFrame() + Vector3.new(0,200, 0))
56 v.PrimaryPart.Anchored = false
57 end
58 Character:SetPrimaryPartCFrame(Character:GetPrimaryPartCFrame() + Vector3.new(0, 200, 0))
59 end
60end
61function Battle:InvisibleEnemies()
62 self.InvisibleEnemiesFlag = not self.InvisibleEnemiesFlag;
63 if (self.InvisibleEnemiesFlag) then
64 for i, v in pairs(self.EnemyContainer:GetChildren()) do
65 v.PrimaryPart.Anchored = true
66 v:SetPrimaryPartCFrame(v:GetPrimaryPartCFrame() - Vector3.new(0,200, 0))
67 end
68 else
69 for i, v in pairs(self.EnemyContainer:GetChildren()) do
70 v:SetPrimaryPartCFrame(v:GetPrimaryPartCFrame() + Vector3.new(0,200, 0))
71 v.PrimaryPart.Anchored = false;
72 end
73 end
74end
75function Battle:EndBattleProtocol(NoHealth, NHealth, force)
76 if force or (NoHealth == #self.Enemies or NHealth == #self.Characters) then
77 CurrentCameraShake:StopSustained(1)
78 spawn(function()
79 wait(1)
80 CurrentCameraShake:Stop()
81 end)
82
83 self:EndBattle();
84
85 for i, v in pairs(Character.Humanoid:GetPlayingAnimationTracks()) do
86 v:Stop(); --stop all playing animations, the default animator will replay animations again so it doesn't matter'
87 end
88 local PLighting = ReplicatedStorage:FindFirstChild('Previous Lighting');
89 if (PLighting) then
90 for i, v in pairs(PLighting:GetChildren()) do
91 pcall(function()
92 game:GetService('Lighting')[v.Name] = v.Value;
93 end)
94 end
95 end
96 self.BattleArea:Destroy();
97 for i, v in pairs(game:GetService'Lighting':GetChildren()) do
98 if (v.ClassName:match('Effect') and v.Name ~= 'e') then
99 v.Enabled = true
100 end
101 end
102 Character:SetPrimaryPartCFrame(self.PositionBeforeBattle)
103 Character:WaitForChild('HumanoidRootPart').Anchored = false;
104
105 pcall(StopAnimation, nil, Character:WaitForChild('Humanoid'))
106 _G.Music:Resume();
107 return true, script:Destroy(); --self destruct script just to be safe
108 end
109end
110repeat wait() until _G.BattleAnnouncement;
111--stupid shit
112
113function GS(s)
114 return game:GetService(s)
115end
116
117function playAnimOnModel(m, Anim, waittime)
118 if (not m) then return nil end
119 local m2 = m:Clone();
120 m2.Parent = workspace;
121 local CFThingToDisconnect = game:GetService('RunService').RenderStepped:Connect(function(Step)
122 for i, v in pairs(m:GetChildren()) do
123 if (not v:FindFirstChild('originalCFrame') and v:IsA('BasePart')) then
124 local CF = Instance.new('CFrameValue', v)
125 CF.Name = 'originalCFrame';
126 CF.Value = v.CFrame;
127 end
128 for i,x in pairs(m2:GetChildren()) do
129 if (v.Name == x.Name and v:IsA('BasePart')) then
130 v.CFrame = x.CFrame;
131 --
132 end
133 end
134 end
135 end)
136
137 if (not Anim) then CFThingToDisconnect:Disconnect(); return nil end
138
139 local anim = m2:WaitForChild('Humanoid'):LoadAnimation(Anim);
140 anim:Play()
141 --
142 if (waittime) then
143 wait(waittime)
144 end
145
146 --
147
148 spawn(function(s)
149 wait(anim.Length+0.25)
150 CFThingToDisconnect:Disconnect();
151 for i, v in pairs(m:GetChildren()) do
152 if (v:FindFirstChild('originalCFrame')) then
153 v.CFrame = v.originalCFrame.Value;
154 --
155 end
156 end
157 end)
158 --
159 --
160 --
161 m2:Destroy();
162 return true;
163end
164
165function showMaskSteal()
166 local ViewportFrame = PlayerGui:WaitForChild('MaskStealAnimation'):WaitForChild('ViewportFrame')
167 local XYZ = ViewportFrame;
168 for i = 1, 0, -0.25 do
169 GS('RunService').RenderStepped:Wait()
170 XYZ.ImageTransparency = i;
171 end
172
173
174 local MaskSteal = GS'ReplicatedStorage':WaitForChild('AnimationAssets'):WaitForChild('Mask Steal');
175 local A1 = ViewportFrame:WaitForChild('maskSteal'):WaitForChild('person1');
176 local B1 = ViewportFrame:WaitForChild('maskSteal'):WaitForChild('person2');
177 playAnimOnModel(A1, MaskSteal.person1, nil)
178 playAnimOnModel(B1, MaskSteal.person2, nil)
179 --playAnimOnModel(animModel, Anim, waittime)
180
181 spawn(function(xyz) --to prevent people from doing the stuffs
182 wait(2.4)
183 for i = 0, 1, 0.25 do
184 GS('RunService').RenderStepped:Wait()
185 XYZ.ImageTransparency = i;
186 end
187 end)
188 spawn(function(xyztwo)
189 wait(1.25)
190 ReplicatedStorage.Music:WaitForChild('Glass Shattering'):Play();
191 end)
192
193 wait(2.1)
194 --
195 return true
196end
197
198BattleInfo = { --Independant turns for every character.
199 EnemyTurns = {}; --one for the enemies
200 PlayerTurns = {}; --one for the player. this allows for rakukaja to turn on/off not when it's Akira's turn
201 EnemyActions = {};
202
203 MemberActions = {};
204 MemberAnimations = {};
205 SelectedPersonaAttack = nil;
206
207 BattleStage = 'Main'; --using general identifiers for battlestage
208 SelectedMember = 0; --Default to 0 so we can know this is the start of the battle.
209}
210
211function Battle:GetFirstLivingEnemy()
212 for i, v in pairs(self.Enemies) do
213 if v.Health > 0 then
214 return i, v;
215 end
216 end
217end
218
219function Battle:showOneMore()
220 ReplicatedStorage.Music:WaitForChild('Explosion'):Play();
221 PlayerGui.OneMore.Frame.BackgroundTransparency = 0;
222 spawn(function(x)
223 for i = 0, 1, 0.1 do
224 wait();
225 PlayerGui.OneMore.Frame.BackgroundTransparency = i;
226 end
227 end)
228 PlayerGui.OneMore.ViewportFrame.ImageTransparency = 0;
229 wait(1.15)
230 for i = 0, 1, 0.1 do
231 wait()
232 PlayerGui.OneMore.ViewportFrame.ImageTransparency = i;
233 end
234end
235
236function Battle:MoveCameraToCharacter(i, varia)
237 if (currentTween) then currentTween:Cancel(); currentTween = nil; end
238 varia = typeof(varia) == 'table' and varia or {};
239 local pointTo = varia.PointTo
240 local instant = varia.Instant or varia.instant;
241 local yield = varia.Yield or varia.yield;
242
243 local Char = self:GetCharacterFromID(i);
244 local SpawnCFValue = Char.PrimaryPart.CFrame;
245 local SpawnLookVector = SpawnCFValue.LookVector * 8.5;
246 local ROT = CFrame.Angles(CFrame.new(SpawnLookVector + SpawnCFValue.Position, Char.PrimaryPart.Position):ToEulerAnglesXYZ());
247 local RealCFValue = CFrame.new(SpawnLookVector)-- * ROT
248 local CFValue = RealCFValue.Position + Char.PrimaryPart.CFrame.p
249
250 if (pointTo) then
251 CFValue = CFrame.new(CFValue) * CFrame.Angles(CFrame.new(CFValue, typeof(pointTo) == 'Instance' and pointTo.Position or pointTo):ToEulerAnglesXYZ())
252 else
253 CFValue = CFrame.new(CFValue) * ROT
254 end
255
256 currentTween = Tween(workspace.CurrentCamera, TweenInfo.new(instant and 0.1 or 0.25), {CFrame = CFValue})
257 currentTween = currentTween:Play();
258 local x = yield and wait(0.25);
259 return true
260end
261
262 --face camera towards players if not ambush, if ambush then just move the reticle --iiifat
263--add zeroes
264local function safetyZero(num, places)
265 --
266 --
267 places = places or 2
268 num = num or 1
269 return ('0'):rep(#tostring(places)-#tostring(num))..tostring(num)
270end
271
272function Battle:GetEnemyFromID(i, returnChar)
273
274 --iterate over all enemies in the enemies table
275
276 for index, value in pairs(self.Enemies) do
277 if (value.Health > 0 and index >= i) then --if the ID is invalid, then return the first available enemy
278 if (returnChar) then
279 return self.EnemyContainer:WaitForChild(tostring(index))
280 else
281 return index, value
282 end
283 end
284 end
285
286
287end
288
289
290function Battle:MoveCameraToEnemy(i, yield, offset)
291
292 --let's use getChildren for this, we'll switch to an ID-based system in case the game gets confused with their sorting for some reason
293
294 local Char = self.EnemyContainer[tostring(i)]--:GetChildren()[i]
295 local SpawnCFValue = Char.PrimaryPart.CFrame--self.EnemySpawns['Spawn'..i].CFrame;
296 local SpawnLookVector = SpawnCFValue.LookVector * (8.5 * (Char.PrimaryPart.Size.Y / 1.459))
297 local ROT = CFrame.Angles(CFrame.new(SpawnLookVector + SpawnCFValue.Position, Char.PrimaryPart.Position):ToEulerAnglesXYZ());
298 local RealCFValue = CFrame.new(SpawnLookVector) * ROT
299 local CFValue = RealCFValue + Char.PrimaryPart.CFrame.p;
300 Tween(workspace.CurrentCamera, TweenInfo.new(0.25), {CFrame = CFValue}):Play();
301 local x = yield and wait(0.25);
302 return true;
303end
304
305
306DifficultyModifiers = { --difficulty modifiers to get rates of exchange
307 Safety = {
308 DamageRecieved=0.5;
309 DamageDealt=2.0;
310 Experience=3.0;
311 Money=5.0;
312 };
313
314 Easy = {
315 DamageRecieved=0.75;
316 DamageDealt=1.5;
317 Experience=1.5;
318 Money=1.5;
319 };
320
321 Normal = {
322 DamageRecieved=1.0;
323 DamageDealt=1.0;
324 Experience=1.0;
325 Money=1.0;
326 };
327
328 Hard = {
329 DamageRecieved=1.15;
330 DamageDealt=0.9;
331 Experience=1.0;
332 Money=1.0;
333 };
334
335 Merciless={
336 DamageRecieved=1.25;
337 DamageDealt=0.8;
338 Experience=0.77;
339 Money=0.67;
340 };
341 Satanic = {
342 DamageRecieved = 1.35;
343 DamageDealt = 0.71;
344 Experience = 0.765;
345 Money = 0.625;
346 }
347
348}
349
350--function to turn any table into a table ready for battle, can be used as many times as needed
351local Dropped;
352function Metatable(t)
353 for i,v in pairs(t) do
354 if (not v.MaxHealth) and (v.Attacks) then
355 v.MaxHealth = v.Health;
356 end
357
358 if (not v.Persona) then
359 v.ID = i;
360 print('Name:', v.Name);
361 for i,v in pairs(v) do
362 if (i ~= 'Name') then
363 if (typeof(v) == 'table') then
364 for x, v in pairs(v) do
365 print(i..'.'..x..':', v)
366 end
367 else
368 print(i..':', v)
369 end
370 end
371 end
372 local Likings = require(game:GetService('ReplicatedStorage').ModuleScripts.Dialogue.PersonaLikings);
373 v.Personality = Likings[math.random(1, #Likings)].Type
374 local ShouldDropItem = math.random() < (math.random(1, math.random(100)))/100
375 if (not Dropped and ShouldDropItem) then
376 local ViableItemsList = {};
377 for i, v in pairs(Items) do
378 if ( (v.HP or v.SP) and v.Price and v.NoBattle) then
379 ViableItemsList[#ViableItemsList+1] = i;
380 end
381 end
382
383 local SelectedItem = ViableItemsList[math.random(1, #ViableItemsList)];
384 v.BoundItem = SelectedItem;
385 end
386 end
387 local mt = setmetatable(v, {});
388 mt.__index = v;
389 function v:GetHealth()
390 return self.Health;
391 end
392 function v:SubtractHealth(amt)
393 if (typeof(amt) == 'string') then
394 if (amt:lower() == 'all') then amt = self.MaxHealth end;
395 if (amt:lower() == 'half') then amt = self.Health/2 end;
396 end
397 self.Health = math.floor(math.clamp(self.Health - amt, 0, math.huge));
398 return self.Health;
399 end
400
401 function v:Heal(amt, dismiss)
402
403 --impwarn("amount:", amt)
404
405 amt = amt or 0;
406 amt = tostring(amt):lower() == 'half' and self.MaxHealth/2 or amt;
407
408 amt = tostring(amt):lower() == 'max' and math.huge or 100;
409
410 self.Health = math.ceil(math.clamp(self.Health + amt, 0, self.MaxHealth));
411 if (not dismiss) then
412 if (amt < self.MaxHealth*0.356789) then
413 local Audio = ReplicatedStorage:WaitForChild('SFX'):WaitForChild('LowHeal');
414 Audio = Audio:Clone();
415 Audio.Parent = PlayerGui;
416 Audio.PlayOnRemove = true;
417 Audio:Destroy();
418 else
419 local Audio = ReplicatedStorage:WaitForChild('SFX'):WaitForChild('LowHeal');
420 Audio = Audio:Clone();
421 Audio.Parent = PlayerGui;
422 Audio.PlayOnRemove = true;
423 Audio:Destroy();
424 end;
425 end
426 return self.Health;
427 end
428
429 function v:BuffDamage(amt)
430 self.AddedAttack = self.AddedAttack+amt;
431 return self.AddedAttack;
432 end
433
434 function v:AddDebuff(table)
435 print('Added debuff:', table.Name or #self.Debuffs+1);
436 table.Length = table.Length+1;
437 self.Debuffs = self.Debuffs or {};
438 self.Debuffs[table.Name or #self.Debuffs+1] = table
439 end
440
441 function v:BuffDefense(amt)
442 self.AddedDefense = self.AddedDefense+amt;
443 return self.AddedDefense;
444 end
445
446 function v:SubtractAmmo()
447 local EquippedGun = Items[self.Equipped.Gun];
448 if (self.Ammo == -1) then self.Ammo = EquippedGun.Ammo-1; return self.Ammo; end;
449 self.Ammo = self.Ammo - 1;
450 return self.Ammo;
451 end
452
453 function v:GetAmmo()
454 local EquippedGun = Items[self.Equipped.Gun];
455 if (self.Ammo == -1) then self.Ammo = EquippedGun.Ammo end;
456 return self.Ammo;
457 end
458
459 function v:SubtractSP(amt)
460 self.SP = self.SP and math.clamp(self.SP-amt, 0, self.MaxSP or 100) or 0
461 end
462 function v:AddSP(amt)
463 self.SP = self.SP and math.clamp(self.SP+amt, 0, self.MaxSP or 100) or 0
464 end
465 function v:concatKey(sep)
466 local str = '';
467 for i, v in pairs(self) do
468 str = str..string.format('%s - %s%s\n', tostring(i), tostring(v), sep or ', ')
469 end
470 return str
471 end
472 end
473end
474
475
476--functions for animations
477
478
479--function to get enemies from strings
480function getPersonaFromString(s, r)
481
482 local n = Personas[s];
483 local newTable = {};
484
485 --two layer-deep unpack monkaW
486
487 for i, v in pairs(n) do
488 if (typeof(v) == 'table') then
489 newTable[i] = {};
490 for z,v in pairs(v) do
491 newTable[i][z] = v;
492 end
493 else
494 newTable[i] = v;
495 end
496 end
497
498 return newTable;
499end
500
501--useless but useful get attacks function
502function getAttack(n)
503 return Attacks[n]
504end
505
506
507
508
509--modify damage function to calculate HP costs based on max health
510function modifyDamage(n,mx)
511 return math.ceil(mx - (((100-n)/100)*mx))
512end
513
514
515function Battle:getCharacterOnRight(iv, include_dead)
516
517 for i, v in pairs(Battle.Characters) do
518 if (i > iv)
519 and ((include_dead and v.Health > 0) or not include_dead) then
520 return i
521 end
522 end
523 return iv
524end
525
526function Battle:getCharacterOnLeft(iv, include_dead)
527
528 for i, v in pairs(Battle.Characters) do
529 if (i < iv) and ((include_dead and v.Health > 0) or not include_dead) then
530 return i
531 end
532 end
533 return iv
534end
535
536function Battle:GetEnemy(mode, iv)
537 mode = mode:lower()
538 for i, v in pairs(self.Enemies) do
539 local compL = i < iv --I sincerely have no idea why this happens.
540 local compR = i > iv;
541 local comp;
542
543 if (mode == 'l') then
544 for i = iv, 0, -1 do
545
546 if (not self.Enemies[i]) then
547 return iv; --if there is no enemy before one
548 elseif --[[(not checkIncapacitated(self.Enemies[i])) and]] i ~= iv and self.Enemies[i].Health > 0 then
549 return i
550 end
551 end
552 elseif (mode == 'r') then
553 comp = compR;
554 end
555
556 if (comp) and v.Health > 0 then
557 return i;
558 end
559 end
560
561 return iv;
562end
563
564
565function Battle:GetCharacter(mode, iv, include_dead)
566 mode = mode:lower()
567 for i, v in pairs(self.Characters) do
568 local compL = i > iv;
569 local compR = i < iv;
570 local comp;
571 if (mode == 'l') then
572 comp = compL;
573 elseif (mode == 'r') then
574 comp = compR;
575 end
576 if (not include_dead and v.Health > 0) or include_dead then
577 if (comp) then
578 return i;
579 end
580 end
581 end
582
583 return iv;
584end
585--animation functon for humanoid objects
586
587function LoadAnimation(AnimationObject, Target)
588 if (BattleInfo.MemberAnimations[Target]) then --if the humanoid was already used as a target
589 if (BattleInfo.MemberAnimations[Target][tostring(AnimationObject.AnimationId)]) then --check if the humanoid already loaded the animation object
590 return BattleInfo.MemberAnimations[Target][tostring(AnimationObject.AnimationId)] --return the animation track if so
591 else --otherwise
592
593 BattleInfo.MemberAnimations[Target][tostring(AnimationObject.AnimationId)] = Target:LoadAnimation(AnimationObject) --make animationobject point to the animationtrack
594 return BattleInfo.MemberAnimations[Target][tostring(AnimationObject.AnimationId)] --return the animation track
595 end
596 else --if the humanoid is fresh
597
598 BattleInfo.MemberAnimations[Target] = {}; --set the humanoid to point to an animation storage table
599 BattleInfo.MemberAnimations[Target][tostring(AnimationObject.AnimationId)] = Target:LoadAnimation(AnimationObject) --save animation to table
600 return BattleInfo.MemberAnimations[Target][tostring(AnimationObject.AnimationId)] --return animation
601 end
602end
603function Battle:LoadAnimation(...)
604 return LoadAnimation(...)
605end
606function StopAnimation(Animation, Target)
607 -- MemberAnimations -> [Table (Humanoid Object/Target)] -> AnimationObject Name == AnimationTrack
608 --MemberAnimations -> Table -> Animation Object -> Animation Track
609
610 Animation = typeof(Animation) == "string" and {Name = Animation} or Animation;
611 for i, v in pairs(Target:GetPlayingAnimationTracks()) do
612 if (v.Name == Animation.Name) then
613 v:Stop();
614 end
615 end
616 return warn('Couldn\'t find animation', Animation.Name)
617end
618
619function animationStatus(Animation, Humanoid)
620 for i, v in pairs(Humanoid:GetPlayingAnimationTracks()) do
621 if (v.Name:lower() == Animation.Name:lower()) then
622 --impwarn('Found animation track.')
623 return v;
624 end
625 end
626 return false
627end
628
629--personaify function to make text randomly black or white with random rotation
630function personaIfy(text)
631 local MAX = 3;
632 local str='';
633 local NONCOUNT = 1;
634 local LastPersonaIfied = false;
635 for i = 0, #text do
636 if (math.random() < 0.5 and MAX ~= 0 and LastPersonaIfied ~= true and NONCOUNT >= 2) then
637 NONCOUNT = 0;
638 MAX=MAX-1
639 LastPersonaIfied = true;
640 str = str..'<TextColor3=Black><Rotation='..math.random(-5, 5)..'><BackgroundTransparency=0>'..text:sub(i,i)..'<TextColor3=White><BackgroundTransparency=1><Rotation=0>'
641 else
642 NONCOUNT = NONCOUNT+1;
643 LastPersonaIfied = false;
644 str = str..text:sub(i,i)
645 end
646 end
647 return str
648end
649
650local StageDirections = { --utilize stage directions in order to make going forward and backwards easier
651 Main = {}; --we don't include main because that could lead to any direction. the main screen will look messy at the start
652 PersonaAttackList = {Back = 'Main', Next = 'PersonaTarget'};
653 Shoot = {Back = 'Main'};
654 Item = {Back = 'Main', Next = 'ItemSelect'};
655 PersonaChange = {Back = 'PersonaAttackList'}
656}
657
658
659--get character from number ID
660function Battle:GetCharacterFromID(id)
661 if (id == 1) then return Character end;
662
663 if (typeof(id) == 'table') then
664 for i, v in pairs(self.Characters) do
665 if (v == id) then
666 if (v.Name == self.Characters[1].Name) then
667 return Character, i;
668 else
669 return self.PartyContainer:WaitForChild(v.Name), i
670 end
671 end
672 end
673 elseif (typeof(id) == 'string') then
674 for i, v in pairs(self.Characters) do
675 if (v.Name == id) then
676 return (i == 1 and Character or self.PartyContainer:WaitForChild(v.Name)), i
677 end
678 end
679 end
680 if (self.Characters and self.Characters[id]) then --if the id is valid
681 return workspace:WaitForChild('Party Container'):WaitForChild(self.Characters[id].Name)
682 end
683
684 return 0;
685end
686
687function Battle:GetEnemyFromName(id)
688 if (self.Enemies and self.Enemies[id]) then
689 if (typeof(id) == 'number') then
690 return workspace:WaitForChild('Enemy Container'):WaitForChild(id)
691 elseif (typeof(id) == 'string') then
692 for i, v in pairs(workspace:WaitForChild('Enemy Container'):GetChildren()) do
693 if (v:WaitForChild('PersonaName').Value:lower() == id:lower()) then --bad idea because duplicates will be there
694 return v;
695 end
696 end
697 end
698 end
699end
700
701
702--persona create function
703
704function RemoveAllPersonas(Transition)
705 CurrentPersonaThing = nil;
706 for i, v in pairs(CollectionService:GetTagged('PersonaObject')) do
707 local x = v;
708 if (Transition) then
709 for i, v in pairs(v:GetDescendants()) do
710 spawn(function()
711 if v:IsA('BasePart') or v:IsA('Decal') then
712 for i = v.Transparency, 1, 0.1 do
713 wait();
714 v.Transparency = i;
715 end
716 end
717 x:Destroy()
718 end)
719 end
720 else
721 v:Destroy()
722 end
723 print'Persona Removed.'
724 end
725end
726
727function Battle:createPersona(rf, summonall, t)
728 if (not summonall) then
729 RemoveAllPersonas();
730 end
731 if (not self.Ambush) then
732 self:CharacterPositionButWithPersona(nil, nil, rf);
733 end
734 CurrentPersonaThing = nil;
735 local Sona = game:GetService('ReplicatedStorage'):WaitForChild('Personas'):WaitForChild(self.Characters[t or BattleInfo.SelectedMember].Persona.Name):Clone()
736
737 local n = self.Characters[t or BattleInfo.SelectedMember].Persona.CustomSize or {};
738 local H = Sona:WaitForChild('Humanoid');
739 H.BodyDepthScale.Value = (n.Depth or 2);
740 H.BodyHeightScale.Value = (n.Height or 2);
741 H.BodyProportionScale.Value = (n.Proportions or 1);
742 H.BodyTypeScale.Value = (n.Type or 1.75);
743 H.BodyWidthScale.Value = (n.Width or 2);
744 H.HeadScale.Value = (n.Head or 2);
745 local bodyColors = Sona:WaitForChild('Body Colors')
746 local bodyColor = Color3.fromRGB(4, 175, 236)
747 --2,2, 1, 1.75, 2, 2
748 do --BodyProperties
749 bodyColors.HeadColor3 = bodyColor
750 bodyColors.LeftArmColor3 = bodyColor
751 bodyColors.LeftLegColor3 = bodyColor
752 bodyColors.RightArmColor3 = bodyColor
753 bodyColors.RightLegColor3 = bodyColor
754 bodyColors.TorsoColor3 = bodyColor
755 end
756 local pl = Instance.new('PointLight')
757 pl.Brightness = math.abs(math.sin(tick())*10)
758 pl.Range = math.abs(math.sin(tick())*16)
759 for i, v in pairs(Sona:GetDescendants()) do
760 if v:IsA('BasePart') then
761 v.Transparency = 0.7;
762 if (not v:FindFirstAncestorWhichIsA('Accessory') and not v:FindFirstAncestorWhichIsA('Hat')) then
763 v.Material = Enum.Material.ForceField
764 end
765 end
766 if (v.Name == 'HumanoidRootPart') then--
767 v.Transparency = 1;
768 pl.Parent = v;
769 end
770 end
771 CollectionService:AddTag(Sona, "PersonaObject");
772 Sona.Name = "Persona";
773 if ((t or BattleInfo.SelectedMember) == 1) then
774 Sona.Parent = workspace;--game.Players.LocalPlayer.Character;
775 Sona:WaitForChild('HumanoidRootPart').Anchored = true;
776 while Sona.Parent and not Sona.Parent:IsA('Folder') do
777 if (Sona.Parent:IsA('Folder')) then break end;
778 pl.Brightness = math.abs(math.sin(tick())*10)
779 pl.Range = math.abs(math.sin(tick())*16)
780 wait()
781 if (not CurrentPersonaThing) and Sona:FindFirstChild('Humanoid') then
782 LoadAnimation(game:GetService('ReplicatedStorage').AnimationAssets['Hover Animation']:WaitForChild('HoverAnimation'), Sona.Humanoid):Play()
783 end
784 local T = Sona.PrimaryPart or Sona:FindFirstChild('HumanoidRootPart') or Sona:FindFirstChild('Torso');
785 if (not Sona.Parent) then break end;
786 if (Sona.PrimaryPart) then
787 Sona:SetPrimaryPartCFrame(CFrame.new((game.Players.LocalPlayer.Character.UpperTorso.CFrame.lookVector * -3.5) + game.Players.LocalPlayer.Character.UpperTorso.CFrame.p + Vector3.new(0, math.sin(tick()), 0)) * CFrame.Angles(self.PartySpawns:WaitForChild('Spawn'..(t or BattleInfo.SelectedMember)).CFrame:toEulerAnglesXYZ()) + Vector3.new(0, 5, 0))
788 end
789 if (summonall) then
790 return Sona;
791 end
792 end
793 else
794 Sona.Parent = workspace;--workspace:WaitForChild('Party Container'):WaitForChild(self.Characters[t or BattleInfo.SelectedMember].Name);
795 local xyz = workspace:WaitForChild('Party Container'):WaitForChild(self.Characters[t or BattleInfo.SelectedMember].Name)
796 Sona:WaitForChild('HumanoidRootPart').Anchored = true;
797 while Sona.Parent and not Sona.Parent:IsA('Folder') do
798 pl.Brightness = math.abs(math.sin(tick())*10)
799 pl.Range = math.abs(math.sin(tick())*16)
800 if (Sona.Parent:IsA('Folder') or Sona.Parent == nil) then break end;
801 wait()
802 if (not CurrentPersonaThing) and (Sona:FindFirstChild('Humanoid')) then
803 --
804 --CurrentPersonaThing:Play(game:GetService('ReplicatedStorage').AnimationAssets['Hover Animation']:WaitForChild('HoverAnimation'));
805 LoadAnimation(game:GetService('ReplicatedStorage').AnimationAssets['Hover Animation']:WaitForChild('HoverAnimation'), Sona.Humanoid):Play()
806 end
807 local T = Sona.PrimaryPart or Sona:FindFirstChild('HumanoidRootPart') or Sona:FindFirstChild('Torso');
808 local Torso = xyz.PrimaryPart;
809 if (Sona.PrimaryPart) then
810 Sona:SetPrimaryPartCFrame(CFrame.new((xyz.UpperTorso.CFrame.lookVector * -7) + xyz.UpperTorso.CFrame.p + Vector3.new(0, math.sin(tick()), 0)) * CFrame.Angles(self.PartySpawns:WaitForChild('Spawn'..(t or BattleInfo.SelectedMember)).CFrame:toEulerAnglesXYZ()) + Vector3.new(0, 5, 0));
811 elseif (T) then
812 T.CFrame = (CFrame.new((Torso.CFrame.lookVector * -7) + Torso.CFrame.p) * CFrame.Angles(Torso.CFrame:toEulerAnglesXYZ()) + Vector3.new(0, math.sin(tick()), 0) + Vector3.new(0, 5, 0))
813 end
814 if (summonall) then
815 return Sona;
816 end
817 end
818 end
819end
820
821
822--global tween function
823function Tween(obj, ti, goalTable)
824
825 if (not obj) then error('invalid object'); end;
826 if (not ti) then error('invalid tween info'); end;
827 if (not goalTable) then error('invalid goal table'); end;
828
829 local TS = game:GetService('TweenService');
830
831 return game:GetService('TweenService'):Create(obj, ti, goalTable);
832end
833--camera functions
834function Battle:CharacterPositionButWithPersona(t, lookAt, inst, ofst, vertoffset)
835 --impwarn('Started new thread!')
836 --impwarn('B1')
837 lookAt = typeof(lookAt) == 'CFrame' and {CFrame = lookAt} or (typeof(lookAt) == 'Instance' and {CFrame = lookAt.CFrame})
838 if (currentTween) then currentTween:Cancel(); currentTween = nil; end;
839 local C = Battle.Characters[t or BattleInfo.SelectedMember];
840 local OBJ = nil;
841 --impwarn('B2')
842 if ((t or BattleInfo.SelectedMember) <=1) then
843 OBJ = game.Players.LocalPlayer.Character;
844 else
845 OBJ = workspace:WaitForChild('Party Container'):WaitForChild(C.Name)
846 end
847 --impwarn('B3')
848 local OBJ2 = OBJ.PrimaryPart or self.BattleArea:WaitForChild(self.Ambush and 'Ambush Spawns' or 'Spawns')['Party Spawns']:WaitForChild('Spawn'..(t or BattleInfo.SelectedMember))
849 --impwarn(OBJ2)
850 local Equation = CFrame.new(OBJ2.CFrame.lookVector * -(ofst or 20) + --[[workspace.CurrentCamera.CFrame]]OBJ2.CFrame.RightVector*9) * CFrame.Angles(OBJ2.CFrame:toEulerAnglesXYZ()) + OBJ2.Position + Vector3.new(0,10,0);
851 --impwarn('B5')
852
853
854 local X,Y,Z = CFrame.new(Equation.Position + (not lookAt and OBJ2.CFrame.RightVector*-6.5 or Vector3.new(0,0,0)), OBJ2.Position + Vector3.new(0, (vertoffset or 7.5), 0)):ToEulerAnglesXYZ();
855 Equation = CFrame.new(Equation.Position) * (
856 not lookAt and CFrame.Angles(X,Y,Z) or
857 CFrame.Angles(
858 CFrame.new(workspace.CurrentCamera.CFrame.Position, lookAt.CFrame.Position):ToEulerAnglesXYZ())
859 )
860 --impwarn('B6')
861
862 currentTween = Tween(workspace.CurrentCamera, TweenInfo.new(not lookAt and not inst and 1 or 0, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0), {CFrame = Equation})
863 currentTween:Play(); --* CFrame.Angles(workspace.CurrentCamera.CFrame:ToEulerAnglesXYZ());
864 --impwarn('B7')
865 wait()
866end
867
868function Battle:CharacterPosition(player, inverse, start)
869 if (currentTween) then currentTween:Cancel(); currentTween = nil; end
870 player = player or BattleInfo.SelectedMember
871 local C = self.Characters[player];
872
873
874 local Keyword = self.BattleArea:WaitForChild(self.Ambush and 'Ambush Spawns' or 'Spawns')
875
876 local OBJ = nil;
877 if (player <=1) then
878 OBJ = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait();
879 else
880 OBJ = workspace:WaitForChild('Party Container'):WaitForChild(C.Name)
881 end
882 OBJ = OBJ.PrimaryPart;
883 local c = inverse and Keyword['Enemy Spawns']:WaitForChild('Spawn1') or OBJ
884 local mp = (not inverse) and -9 or 6.25
885 local RightVector = (not inverse) and 11.25 or 0;
886 if (not start) then
887 local CF = CFrame.new((OBJ.CFrame.lookVector * mp) + OBJ.CFrame.rightVector*RightVector)+ OBJ.Position + Vector3.new(0,OBJ.Parent.Humanoid.HipHeight+0.24,0)
888 currentTween = Tween(
889 workspace.CurrentCamera,
890 TweenInfo.new(0.2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0),
891 {
892 CFrame = CF *
893 CFrame.Angles(CFrame.new(CF.Position, OBJ.Position):ToEulerAnglesXYZ())
894 }
895 )
896 currentTween:Play();
897 else
898 local CF = CFrame.new((OBJ.CFrame.lookVector * mp) + OBJ.CFrame.rightVector*RightVector)+ OBJ.Position + Vector3.new(0,OBJ.Parent.Humanoid.HipHeight+0.24,0)
899 workspace.CurrentCamera.CFrame = CF *
900 CFrame.Angles(CFrame.new(CF.Position, OBJ.Position):ToEulerAnglesXYZ())
901 end
902end
903
904function Battle:CharacterAttacked(player)
905 player = player or BattleInfo.SelectedMember
906 local C = self.Characters[player];
907
908
909 local Keyword = self.BattleArea:WaitForChild(self.Ambush and 'Ambush Spawns' or 'Spawns')
910
911 local OBJ = nil;
912 if (player <=1) then
913 OBJ = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait();
914 else
915 OBJ = workspace:WaitForChild('Party Container'):WaitForChild(C.Name)
916 end
917 local Increase = 8.5
918 OBJ = OBJ.PrimaryPart--Keyword['Party Spawns']:WaitForChild('Spawn'..(player))
919 local c = OBJ
920 local mp = 7
921
922 workspace.CurrentCamera.CFrame = CFrame.new(OBJ.CFrame.lookVector*-mp + OBJ.CFrame.rightVector*2.5) * CFrame.Angles(c.CFrame:toEulerAnglesXYZ()) + OBJ.Position --+ Vector3.new(0,Increase, 0)
923
924 local Formula = workspace.CurrentCamera.CFrame.LookVector * -10 + workspace.CurrentCamera.CFrame.Position;
925 Tween(workspace.CurrentCamera, TweenInfo.new(5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {
926
927 CFrame = CFrame.new(Formula) * CFrame.Angles(CFrame.new(Formula, OBJ.Position):ToEulerAnglesXYZ())
928
929 }):Play();
930
931 wait(1.15)
932end
933
934function Battle:PartyAttacked()
935 local Root = Player.Character.PrimaryPart
936
937 local Keyword = self.BattleArea:WaitForChild(self.Ambush and 'Ambush Spawns' or 'Spawns')
938
939 Keyword = Keyword["Party Spawns"];
940 local SpawnOne = Keyword:GetChildren()[1];
941 local SpawnTwo = Keyword:GetChildren()[#Keyword:GetChildren()];
942 local mp = 11
943
944 local Half = SpawnOne.CFrame:Lerp(SpawnTwo.CFrame, .5)
945 Half = {CFrame = Half, Position = Half.Position}
946
947 print(typeof(Half))
948 workspace.CurrentCamera.CFrame =
949 (CFrame.new(
950 Half.CFrame.LookVector*-mp
951 +
952 Half.CFrame.rightVector*
953 2.5
954 ) + Vector3.new(0, Root.Parent.Humanoid.HipHeight + 4.5, 0)) *
955 CFrame.Angles(
956 Half.CFrame:toEulerAnglesXYZ()
957 ) +
958 Half.Position --+ Vector3.new(0,Increase, 0)
959
960 local Formula = workspace.CurrentCamera.CFrame.LookVector * -10 + workspace.CurrentCamera.CFrame.Position;
961 Tween(workspace.CurrentCamera, TweenInfo.new(5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {
962
963 CFrame = CFrame.new(Formula) * CFrame.Angles(CFrame.new(Formula, Half.Position):ToEulerAnglesXYZ())
964
965 }):Play();
966end
967
968function isCloserToPosition(p, op, modulofactor, clamp)
969 p = p.CFrame;
970 local p1 = math.abs(((-p.RightVector + p.Position) - op.Position).Magnitude);
971 local p2 = math.abs(((p.RightVector + p.Position) - op.Position).Magnitude);
972
973 if (math.floor(p1) > math.floor(p2)) then --if the other part is closer to the right side
974 return 'Right', math.clamp(p2/(modulofactor or 1), -clamp, clamp);
975 else --if the other part is closer to the left side
976 return 'Left', math.clamp(p1/(modulofactor or 1), -clamp, clamp);
977 end
978end
979
980function Battle:CharacterAttacking(player, target, crit, mhit)
981 player = player or BattleInfo.SelectedMember
982 local C = self.Characters[player];
983
984
985 local Keyword = self.BattleArea:WaitForChild(self.Ambush and 'Ambush Spawns' or 'Spawns')
986
987 local OBJ = nil;
988 if (player <=1) then
989 OBJ = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait();
990 else
991 OBJ = workspace:WaitForChild('Party Container'):WaitForChild(C.Name)
992 end
993 local Increase = 8.5
994 OBJ = OBJ.PrimaryPart--Keyword['Party Spawns']:WaitForChild('Spawn'..(player))
995 local ClosestTo, shiftFactor = isCloserToPosition(OBJ, target, 10, 2)
996 if (mhit) then
997 local Keyword = Keyword['Enemy Spawns']
998 local CF = Keyword:GetChildren()[1].CFrame:Lerp(Keyword:GetChildren()[#Keyword:GetChildren()].CFrame, 0.5)
999 target = {CFrame = CF, Position = CF.Position}
1000 end
1001 local c = OBJ
1002 local mp = 5--(ClosestTo == 'Right' and 1 or 5)
1003 local RV = (ClosestTo == 'Right' and -shiftFactor-5 or 5+shiftFactor)--move closer to the left if the attacked person is too far to the right
1004
1005
1006
1007 workspace.CurrentCamera.CFrame = CFrame.new(Vector3.new(0,6.5,0)+OBJ.CFrame.lookVector*-mp + OBJ.CFrame.rightVector*(crit and 0 or RV)) * CFrame.Angles(CFrame.new(c.CFrame--[[:toEulerAnglesXYZ()]].Position, target.CFrame.Position):ToEulerAnglesXYZ()) + OBJ.Position --+ Vector3.new(0,Increase, 0)
1008 wait();
1009 local Formula = workspace.CurrentCamera.CFrame.LookVector * -(crit and -5 or 5) + workspace.CurrentCamera.CFrame.Position;
1010 Tween(workspace.CurrentCamera, TweenInfo.new(2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {
1011
1012 CFrame = CFrame.new(Formula) * CFrame.Angles(CFrame.new(Formula, target.CFrame.Position):ToEulerAnglesXYZ())
1013
1014 }):Play();
1015
1016 wait(1.25)
1017end
1018
1019--functions for battle
1020function getNextStage()
1021 for i, v in pairs(StageDirections) do
1022 if (i == BattleInfo.BattleStage) then
1023 return v.Next;
1024 end
1025 end
1026
1027 return nil;
1028end
1029
1030function getPreviousStage()
1031 for i, v in pairs(StageDirections) do
1032 if (i == BattleInfo.BattleStage) then
1033 return v.Next;
1034 end
1035 end
1036
1037 return nil;
1038end
1039w = warn;
1040
1041function Battle:selectViableMember(RefillMembers)
1042 if (self.BattleFinished) then return 1 end;
1043 if (not self.AvailableUsers) then
1044 self.AvailableUsers = {};
1045 end
1046 local AvailableUsers = self.AvailableUsers;
1047 if (not BattleInfo.TotalTurn) then
1048
1049 BattleInfo.TotalTurn = 0;
1050 end
1051
1052 print('Baton Count:', self.BatonCount or 0);
1053
1054 if (self.BatonPass) then
1055 self.BatonCount = self.BatonCount + 1;
1056
1057 if (self.BatonCount == 1) then
1058 showLabel('Attack and Recovery increased!')
1059 elseif (self.BatonCount == 2) then
1060 showLabel('Attack and Recovery greatly increased!')
1061 elseif (self.BatonCount == 3) then
1062 showLabel('Attack and Recovery massively increased!')
1063 elseif (self.BatonCount == 4) then
1064 showLabel('Attack and Recovery tremendously increased!')
1065 end
1066
1067 local OBT = self.BatonPass;
1068 self.BatonPass = nil;
1069 return OBT
1070 end
1071
1072
1073
1074 if (self.OneMore) then
1075
1076 Battle:showOneMore()
1077 return BattleInfo.SelectedMember;
1078 end
1079
1080 for i, v in pairs(self.Characters) do
1081 v.BatonPassed = false;
1082 end
1083
1084 self.BatonCount = 0;
1085
1086 --use X prefix to describe enemies
1087
1088 --Add all ids to one table so we can determine their agility for turn order
1089
1090 if (not self.Ambush) then
1091
1092 if (BattleInfo.TotalTurn == 0) then
1093
1094 spawn(function()
1095 local RandomAppraisals = {"Awesome, Joker! We have the first strike! Make it good!", "Alright Joker, we have the upper hand! Don't mess it up!", "Alright team, you know what to do!", "Slay them all!", "Cut down their family tree!"}
1096 if (self.Boss) then
1097 RandomAppraisals = {'Alright team, stay calm! I know this one\'s strong, but think your actions through!'}
1098 end;
1099 local WeakAppraisals = {}
1100 local lv = 0;
1101 for i, v in pairs(self.Enemies) do
1102 lv = lv + (v.Level or 0);
1103 end
1104 lv = (lv/#self.Enemies) --get average of enemies
1105 local clv = 0;
1106 for i, v in pairs(self.Characters) do
1107 clv = clv + (v.Level or 0);
1108 end
1109
1110 clv = (clv/#self.Characters);
1111
1112 if (clv - lv > 5) then
1113 for i, v in pairs(not self.Boss and WeakAppraisals or {}) do
1114 RandomAppraisals[#RandomAppraisals+1] = v;
1115 end
1116 elseif (clv - lv < -5) then
1117 RandomAppraisals = not self.Boss and {
1118 string.format("Joker, be cautious! %s very strong!", #self.Enemies > 1 and "These guys are" or "This guy is");
1119 string.format("Joker, be careful! %s tough..", #self.Enemies > 1 and "These ones're" or "This one's");
1120 string.format("Joker, be careful! We may have the upper hand, but %s tough!", #self.Enemies > 1 and "These ones're" or "This one's");
1121 string.format("Be cautious, everyone! %s tough!", #self.Enemies > 1 and "These ones're" or "This one's")
1122 } or RandomAppraisals;
1123 end
1124
1125 _G.BattleAnnouncement(RandomAppraisals[math.random(1, #RandomAppraisals)], ReplicatedStorage:WaitForChild('Party Members'):WaitForChild('Yuki'))
1126 end)
1127
1128-- for i, v in pairs(self.Characters) do
1129--
1130-- AvailableUsers[#AvailableUsers+1] = {i, 7000-(math.random(1, 500))}
1131-- end
1132 end
1133 elseif (BattleInfo.TotalTurn == 0) then
1134
1135 for i, v in pairs(self.Enemies) do
1136
1137 AvailableUsers[#AvailableUsers+1] = {"X"..v.ID, 7000-(math.random(1, 500))}
1138 end
1139 end
1140
1141 if (RefillMembers) then
1142 self.knockedChar = false;
1143 --impwarn("Refilling...")
1144 BattleInfo.EnemyActions = {};
1145 BattleInfo.MemberActions = {};
1146 for i, v in pairs(self.Characters) do --character personas dont have an agility stat yet SIKE THEY DO NOW
1147
1148 BattleInfo.PlayerTurns[i] = BattleInfo.PlayerTurns[i] or 1
1149
1150 local Incapacitated = checkIncapacitated(v, nil, BattleInfo.PlayerTurns[i] or 1);
1151
1152 if (not BattleInfo.MemberActions[i]) --[[and (not checkIncapacitated(v, nil, BattleInfo.PlayerTurns[i]))]] then
1153 AvailableUsers[#AvailableUsers+1] = {i, v.Persona.Stats.Agility};
1154
1155 elseif Incapacitated then
1156
1157 impprint('Player was incapacitated. Skipping turn and adding one.')
1158 BattleInfo.PlayerTurns[i] = BattleInfo.PlayerTurns[i] and (BattleInfo.PlayerTurns[i]+1)or 1
1159 end
1160 end
1161
1162 for i, v in pairs(self.Enemies) do
1163 if (v.TurnCount) then
1164
1165 v.CTC = v.CTC or 1;
1166 end
1167
1168 BattleInfo.EnemyTurns[v.ID] = BattleInfo.EnemyTurns[v.ID] or 1
1169
1170 local Incapacitated = checkIncapacitated(v, nil, BattleInfo.EnemyTurns[v.ID] or 1);
1171
1172 if (not BattleInfo.EnemyActions[i]) and (not Incapacitated) then
1173
1174 if (v.TurnCount and v.CTC <= v.TurnCount) then
1175
1176 for i = 0, v.TurnCount do
1177 --NO WONDER IT DIDNT WORK, IT ONLY DID IT FOR TURN COUNTS ONLY WHAT
1178 AvailableUsers[#AvailableUsers+1] = {'X'..v.ID, (v.EnemyStats or v.Stats).Agility};
1179 end
1180 elseif (not v.TurnCount) and (not BattleInfo.EnemyActions[v.ID]) and (not Incapacitated) then
1181 AvailableUsers[#AvailableUsers+1] = {'X'..v.ID, (v.EnemyStats or v.Stats).Agility};
1182 end
1183 elseif Incapacitated then
1184
1185 impprint('Enemy was incapacitated. Skipping turn and adding one.', "Name:", v.Name, "ID", v.ID or 0)
1186
1187 local oa = BattleInfo.EnemyTurns[i] or 1;
1188
1189 BattleInfo.EnemyTurns[i] = BattleInfo.EnemyTurns[i] and (BattleInfo.EnemyTurns[i]+1) or 1
1190
1191 impwarn('Previously:', oa, 'Now:', BattleInfo.EnemyTurns[i])
1192 end
1193 end
1194
1195 end
1196
1197 --sort the table based on their agility. convert all strings to numbers and then place in the table if the string's numbers are valid
1198 for i, v in pairs(AvailableUsers) do
1199
1200 impprint('Before Turn Order:', table.concat(v, ', '))
1201 end
1202
1203 table.sort(AvailableUsers, function(a, b)
1204
1205
1206 local newA = a[2];
1207 local newB = b[2];
1208
1209 return newA > newB
1210 end)
1211 for i, v in pairs(AvailableUsers) do
1212
1213 impprint('After Turn Order:', table.concat(v, ', '))
1214
1215 end
1216
1217 local CharacterCount = 0;
1218
1219 local y = tostring(AvailableUsers[1][1]);
1220 --hehe
1221 BattleInfo.TotalTurn = BattleInfo.TotalTurn + 1;
1222
1223 for i, v in pairs(self.Enemies) do
1224 v.Debuffs = v.Debuffs or {};
1225 local Enemy = v;
1226 for i, v in pairs(v.Debuffs) do
1227 if (v.TurnAdded and v.TurnAdded + v.Length < (BattleInfo.EnemyTurns[Enemy.ID] or 0)) then
1228 Battle:MoveCameraToEnemy(Enemy.ID)
1229 if (v.Name ~= 'Down') then
1230 showLabel(v.Name..'has worn off!', 2.5)
1231 else
1232 Battle.HoldUpped = false;
1233 end
1234 v.Debuffs[i] = nil;
1235 else
1236 impwarn("");
1237 impwarn("Debuff Data:");
1238 impwarn("Receiver Name:", Enemy.Name, "Debuff Name:", v.Name, "::", "TurnAdded:", v.TurnAdded, "Length:", v.Length, "Finishing Turn:", v.TurnAdded + v.Length, "Current Turn:", BattleInfo.TotalTurn, "\n")
1239
1240 end
1241 end
1242 end
1243 for i, v in pairs(self.Characters) do
1244 v.Debuffs = v.Debuffs or {};
1245 local Character = v;
1246 for i, v in pairs(v.Debuffs) do
1247 if (v.TurnAdded and v.TurnAdded + v.Length < (BattleInfo.PlayerTurns[i] or 0)) then
1248 Battle:MoveCameraToCharacter(i)
1249 if (v.Name ~= 'Down') then
1250 showLabel(v.Name..'has worn off!', 2.5)
1251 end
1252 v.Debuffs[i] = nil;
1253 else
1254 impwarn("");
1255 impwarn("Debuff Data (Player):")
1256 impwarn("Receiver Name:", Character.Name, "Debuff Name:", v.Name, "::", "TurnAdded:", v.TurnAdded, "Length:", v.Length, "Finishing Turn:", v.TurnAdded + v.Length, "Current Turn:", BattleInfo.TotalTurn, "\n")
1257 end
1258 end
1259 end
1260 if (tostring(AvailableUsers[1][1]):match('X')) then
1261 warn("X Found!");
1262 return self.Enemies[tonumber(AvailableUsers[1][1]:match('(%d+)'))]
1263 else
1264 warn("X Not Found!");
1265 return tonumber(AvailableUsers[1][1])
1266 end
1267
1268end
1269
1270
1271
1272local Technicals = {
1273 wind = {burn = true};
1274 physical = {frozen = true, shock = true};
1275 nuclear = {frozen = true, burning = true, shock = true};
1276 psychic = {confuse = true, fear = true, despair = true, rage = true, brainwash = true};
1277
1278} --Technicals
1279local CMS = require(game:GetService('Players').LocalPlayer:WaitForChild('PlayerScripts'):WaitForChild('PlayerModule'):WaitForChild('ControlModule'));
1280
1281
1282local KeypadTranslations = { --translate alternative inputs to base inputs for easier coding within the UserInputService InputBegan
1283 Y = 'Z';
1284 X = 'X';
1285 A = 'V';
1286}
1287
1288function Battle:RemoveHealthbars()
1289 for i, v in pairs(CollectionService:GetTagged('TemporaryAdornee')) do
1290 v:Destroy();
1291 end
1292end
1293
1294function Battle:AdorneeHealth(type)
1295-- if ((BattleInfo.SelectedPersonaAttack.Type == 'Kaja' or BattleInfo.SelectedPersonaAttack.Type == 'Buff') and BattleInfo.SelectedPersonaAttack.Type2 ~= 'Debuff') or BattleInfo.BattleStage == 'BatonPass' then
1296-- local Guy = self.Characters[BattleInfo.SelectedEnemyGuy];
1297-- PlayerGui:WaitForChild('HealthBar').Adornee = self:GetCharacterFromID(BattleInfo.SelectedEnemyGuy).PrimaryPart;
1298-- PlayerGui.HealthBar.Frame.Frame.Frame.Size = UDim2.new(math.clamp(Guy.Health/Guy.MaxHealth-0.05, 0, math.huge), 0, 0.6, 0)
1299-- PlayerGui.HealthBar.HealthLabel.Text = tostring(Guy.Health)
1300-- else
1301-- local Guy = self.Enemies[BattleInfo.SelectedEnemyGuy];
1302--
1303-- PlayerGui:WaitForChild('HealthBar').Adornee = self:GetEnemyFromName(BattleInfo.SelectedEnemyGuy, true).PrimaryPart;
1304-- PlayerGui.HealthBar.Frame.Frame.Frame.Size = UDim2.new(math.clamp(Guy.Health/Guy.MaxHealth-0.05, 0, math.huge), 0, 0.6, 0)
1305-- PlayerGui.HealthBar.WeakLabel.Visible = Guy.Weak and Guy.Weak[BattleInfo.SelectedPersonaAttack.Type] or false
1306-- PlayerGui.HealthBar.HealthLabel.Text = tostring(Guy.Health)
1307-- end
1308
1309
1310
1311 if (BattleInfo.SelectedPersonaAttack) then
1312 if (BattleInfo.SelectedPersonaAttack.Heals) then
1313 for i, v in pairs(self.Characters) do
1314 local newHealthBar = PlayerGui:WaitForChild('HealthBar'):Clone();
1315 if (v.ID) then
1316 local IDValue = Instance.new('StringValue', newHealthBar);
1317 IDValue.Name = "Enemy";
1318 IDValue.Value = tostring(v.ID);
1319 end
1320 newHealthBar.Parent = self:GetCharacterFromID(i).PrimaryPart;
1321 newHealthBar.Adornee = newHealthBar.Parent;
1322 newHealthBar.HealthLabel.Text = v.Health;
1323 newHealthBar.Frame.Frame.Frame.Size = UDim2.new(math.clamp(v.Health/v.MaxHealth-0.05, 0, math.huge), 0, 0.6, 0)
1324 newHealthBar.WeakLabel.Visible = (not not v.Persona.Weak[BattleInfo.SelectedPersonaAttack.Type])
1325 CollectionService:AddTag(newHealthBar, 'TemporaryAdornee')
1326 end
1327 elseif (BattleInfo.SelectedPersonaAttack.Damages) then
1328 for i, v in pairs(self.Enemies) do
1329 if (v.Health > 0) then
1330 local newHealthBar = PlayerGui:WaitForChild('HealthBar'):Clone();
1331 if (v.ID) then
1332 local IDValue = Instance.new('StringValue', newHealthBar);
1333 IDValue.Name = "Enemy";
1334 IDValue.Value = tostring(v.ID);
1335 end
1336
1337 newHealthBar.Parent = self:GetEnemyFromName(v.ID, true).PrimaryPart;
1338 newHealthBar.Adornee = newHealthBar.Parent;
1339 newHealthBar.HealthLabel.Text = v.Health;
1340 newHealthBar.Frame.Frame.Frame.Size = UDim2.new(math.clamp(v.Health/v.MaxHealth-0.05, 0, math.huge), 0, 0.6, 0)
1341 if (v.Weak) then
1342 newHealthBar.WeakLabel.Visible = (not not v.Weak[BattleInfo.SelectedPersonaAttack.Type])
1343 end
1344 CollectionService:AddTag(newHealthBar, 'TemporaryAdornee')
1345 end
1346 end
1347 elseif (BattleInfo.SelectedPersonaAttack.Type2 ~= 'Debuff') and (tonumber(BattleInfo.SelectedEnemyGuy)) and (BattleInfo.SelectedPersonaAttack.Type == 'Kaja' or BattleInfo.SelectedPersonaAttack.Type == 'Buff') then
1348 local C = self:GetCharacterFromID(BattleInfo.SelectedEnemyGuy)
1349 if (C.PrimaryPart) then
1350 print("Yes Primary Part");
1351 local newHealthBar = PlayerGui:WaitForChild('HealthBar'):Clone();
1352 local IDValue = Instance.new('StringValue', newHealthBar);
1353 IDValue.Name = "Player";
1354 IDValue.Value = tostring(BattleInfo.SelectedEnemyGuy);
1355 newHealthBar.Parent = C.PrimaryPart;
1356 newHealthBar.Adornee = newHealthBar.Parent;
1357 newHealthBar.HealthLabel.Text = self.Characters[BattleInfo.SelectedEnemyGuy].Health
1358 newHealthBar.Frame.Frame.Frame.Size = UDim2.new(math.clamp(self.Characters[BattleInfo.SelectedEnemyGuy].Health/self.Characters[BattleInfo.SelectedEnemyGuy].MaxHealth-0.05, 0, math.huge), 0, 0.6, 0)
1359 CollectionService:AddTag(newHealthBar, 'TemporaryAdornee')
1360 end
1361 else
1362 local Guy = self.Enemies[BattleInfo.SelectedEnemyGuy];
1363 if (self:GetEnemyFromName(BattleInfo.SelectedEnemyGuy, true).PrimaryPart) and Guy.Health > 0 then
1364 print("Yes Primary Part");
1365 local newHealthBar = PlayerGui:WaitForChild('HealthBar'):Clone();
1366 local IDValue = Instance.new('StringValue', newHealthBar);
1367 IDValue.Name = "Enemy";
1368 IDValue.Value = tostring(BattleInfo.SelectedEnemyGuy);
1369 newHealthBar.Parent = self:GetEnemyFromName(BattleInfo.SelectedEnemyGuy, true).PrimaryPart;
1370 newHealthBar.Adornee = newHealthBar.Parent;
1371 newHealthBar.HealthLabel.Text = Guy.Health
1372 newHealthBar.Frame.Frame.Frame.Size = UDim2.new(math.clamp(Guy.Health/Guy.MaxHealth-0.05, 0, math.huge), 0, 0.6, 0)
1373 newHealthBar.WeakLabel.Visible = (not not Guy.Weak[BattleInfo.SelectedPersonaAttack.Type])
1374 CollectionService:AddTag(newHealthBar, 'TemporaryAdornee')
1375 end
1376 end
1377 end
1378 return true;
1379end
1380
1381
1382
1383function Battle:TweenHealth(t)
1384 local ty = tonumber(PlayerGui.HealthBar.HealthLabel.Text);
1385
1386 local waitTime = t--(ty - Guy.Health) * 1/60
1387
1388
1389 for i, v in pairs(CollectionService:GetTagged('TemporaryAdornee')) do
1390 local Guy;
1391 if (v:FindFirstChild("Enemy")) then
1392 Guy = self.Enemies[tonumber(v.Enemy.Value)];
1393 elseif (v:FindFirstChild("Player")) then
1394 Guy = self.Characters[tonumber(v.Player.Value)]
1395 end
1396 v.Frame.Frame.Frame:TweenSize(UDim2.new(math.clamp(Guy.Health/Guy.MaxHealth-0.05, 0, math.huge), 0, 0.6, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, waitTime, true)
1397 v.HealthLabel.Text = Guy.Health;
1398 end
1399
1400-- for i = ty, Guy.Health, -1 do
1401--
1402-- if (i < Guy.Health) then
1403--
1404-- break; --so no infinite loops
1405-- end
1406-- wait(1/60)
1407-- PlayerGui.HealthBar.HealthLabel.Text = i;
1408-- end
1409
1410
1411 wait(waitTime)
1412end
1413
1414function Battle:AmbushPosition(t)
1415 workspace.CurrentCamera.CFrame = self.BattleArea.Cameras.AmbushCamera.CFrame;
1416 --return Tween(workspace.CurrentCamera, TweenInfo.new(tonumber(t) or 0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0), {CFrame = self.BattleArea.Cameras.AmbushCamera.CFrame}):Play();
1417end
1418
1419function checkIncapacitated(t, isdown, abc)
1420 if (t) then
1421 if (t.Debuffs) then
1422 local y = t; -- if (v.Health > 0) and (not v.Debuffs.Down) and (not v.Debuffs.Sleep) and (not v.Debuffs.Shock) and (not v.Debuffs.Confused) and (not v.Debuffs.Dizzy) and (not v.Debuffs.Fear) then
1423 local t = t.Debuffs;
1424
1425 if ((not isdown and t.Down) or t.Sleep or t.Shock or t.Confused or t.Fear or y.Health <= 0) then
1426 if (not t.Down) and (y.Health > 0) then
1427 return (math.random() < 0.25) and false or true -- 25% chance to be able to act even when debuffed (but not downed)
1428 end
1429 if abc and (t.Down and t.Down.Length + t.Down.TurnAdded <= abc+1) then
1430
1431 return false --so they can have a turn, they get up, then they attack. epic!!
1432 end
1433 return true;
1434 end
1435 else
1436 t.Debuffs = {};
1437 end
1438
1439 if (t.Health <= 0) then
1440 return true;
1441 end
1442 else
1443 warn('error in checkIncapacitated')
1444 end
1445 return false
1446end
1447
1448function Battle:NewTurn()
1449 local DC = 0;
1450 local LivingEnemies = 0;
1451 for i, v in pairs(self.Enemies) do
1452 if (v.Health > 0) then
1453 if (v.Debuffs and v.Debuffs.Down) then
1454 DC = DC+1;
1455 end
1456 LivingEnemies = LivingEnemies + 1;
1457 end
1458 end
1459 impwarn(DC, LivingEnemies, 'downcount & living enemies')
1460 if (DC == LivingEnemies) and DC > 0 and not Battle.HoldUpped then
1461 self.OneMore = false;
1462 end
1463 for i, v in pairs(ReplicatedStorage:WaitForChild('AnimationAssets'):WaitForChild('CritAnim'):GetChildren()) do
1464 if (tonumber(BattleInfo.SelectedMember) and tonumber(BattleInfo.SelectedMember) ~= 0) then
1465 --impwarn('mem:', BattleInfo.SelectedMember);
1466 local Z = Battle:GetCharacterFromID(BattleInfo.SelectedMember):FindFirstChild('Humanoid', true);
1467 local Y = animationStatus(v, Z);
1468 if (Y) then
1469 Y:AdjustWeight(1, 2)
1470 StopAnimation(v, Z)
1471 end
1472 end
1473 end
1474 CurrentCameraShake.RotationInfluence = Vector3.new(0.1, 0.1, 0)
1475 coroutine.wrap(function()
1476 wait();
1477 self:RemoveHealthbars();
1478 end)();
1479 if (self.BattleFinished) then return nil end;
1480 CMS:Disable()
1481 if (not (self.Characters[1].Debuffs.Down or self.Characters[1].Health == 0)) and (DC == LivingEnemies) and DC > 0 and not Battle.HoldUpped then
1482 --Hold Up
1483 CurrentCameraShake.RotationInfluence = Vector3.new(0.05, 0.05, 0)
1484 RemoveAllPersonas(true);
1485 local stateType = Enum.HumanoidStateType
1486 print('HOLD UP!')
1487 local CFrames = {};
1488 for i, v in pairs(self.Characters) do
1489 if (i ~= 1) then
1490
1491
1492 v = Battle:GetCharacterFromID(i)
1493 for i, v in pairs(v:GetDescendants()) do
1494 if v:IsA('BasePart') then
1495 v.Velocity = Vector3.new(0,0,0)
1496 v.RotVelocity = Vector3.new(0,0,0)
1497 end
1498 end
1499 CFrames[i] = v and v:GetPrimaryPartCFrame() or error ("improper coding idiot")
1500 v.Humanoid:SetStateEnabled(stateType.FallingDown, false)
1501 v.Humanoid:SetStateEnabled(stateType.Ragdoll, false)
1502 --impwarn(v);
1503 local PrimaryPart = v.PrimaryPart;
1504 PrimaryPart.Anchored = false;
1505 wait(.1)
1506 v.Humanoid:MoveTo(PrimaryPart.CFrame.LookVector*7 + PrimaryPart.Position)
1507 end
1508 end --movecameratoenemy
1509
1510 for i, v in pairs(Character:GetDescendants()) do
1511 if v:IsA('BasePart') then
1512 v.Velocity = Vector3.new(0,0,0)
1513 v.RotVelocity = Vector3.new(0,0,0)
1514 end
1515 end
1516 CFrames[1] = Character:GetPrimaryPartCFrame();
1517 Character.Humanoid:SetStateEnabled(stateType.FallingDown, false)
1518 Character.Humanoid:SetStateEnabled(stateType.Ragdoll, false)
1519 wait(.1);
1520 Character.PrimaryPart.Anchored = false;
1521 Character.Humanoid:MoveTo(Character.PrimaryPart.CFrame.LookVector*7 + Character.PrimaryPart.CFrame.Position)
1522
1523 Character.Humanoid.MoveToFinished:Wait()
1524 local ColorCorrection = Instance.new('ColorCorrectionEffect', game:GetService('Lighting'));
1525 ColorCorrection.Name = "BattleEffect";
1526 local Length = 1;
1527 Tween(ColorCorrection, TweenInfo.new(Length), {Brightness = -0.45}):Play();
1528 Battle.OtherMusic = game:GetService('ReplicatedStorage').Music['Negotiation']:Clone();
1529 Battle.OtherMusic.Volume = 0;
1530 Battle.OtherMusic.Parent = Player.PlayerGui;
1531 Battle.OtherMusic:Play();
1532 local Vol = self.Music.Volume;
1533 for i = self.Music.Volume, 0, -0.075 do
1534 self.Music.Volume = i;
1535 Battle.OtherMusic.Volume = Battle.OtherMusic.Volume + (Vol - i)
1536 wait();
1537 end
1538 self.Music:Pause();
1539 local Input;
1540
1541 BattleInfo.SelectedEnemyGuy = Battle:GetFirstLivingEnemy();
1542 local SEG = BattleInfo.SelectedEnemyGuy;
1543 local Char = self:GetEnemyFromName(BattleInfo.SelectedEnemyGuy, true);
1544 Battle:CharacterPositionButWithPersona(1, Char.PrimaryPart, true, 11, 3.5) --(t, lookAt, inst, ofst)
1545
1546
1547 local Part;
1548 Part = not (Part and Part:Destroy()) and Instance.new('Part')
1549 Part.Anchored = true;
1550 Part.Transparency = 1;
1551 Part.CFrame = Char:GetPrimaryPartCFrame() + Vector3.new(0,5,0);
1552 Part.CanCollide = false;
1553 Part.Parent = workspace;
1554 do --create new scope so other scopes cannot access these current local scopes.
1555 for i, v in pairs(self.PartyContainer:GetChildren()) do
1556 local Part = Instance.new('Part')
1557 Part.Anchored = true;
1558 Part.Transparency = 1;
1559 Part.CFrame = v:GetPrimaryPartCFrame() + Vector3.new(0,5,0);
1560 Part.CanCollide = false;
1561 Part.Parent = workspace;
1562
1563 local PointLight = Instance.new('PointLight')
1564 PointLight.Color = Color3.fromRGB(206, 200, 131)
1565 PointLight.Range = 4;
1566 PointLight.Brightness = 32.25;
1567 PointLight.Parent = Part;
1568 end
1569
1570 local Part = Instance.new('Part')
1571 Part.Anchored = true;
1572 Part.Transparency = 1;
1573 Part.CFrame = Character:GetPrimaryPartCFrame() + Vector3.new(0,5,0);
1574 Part.CanCollide = false;
1575 Part.Parent = workspace;
1576
1577 local PointLight = Instance.new('PointLight')
1578 PointLight.Color = Color3.fromRGB(206, 200, 131)
1579 PointLight.Range = 4;
1580 PointLight.Brightness = 32.25;
1581 PointLight.Parent = Part;
1582 end
1583 local PointLight = Instance.new('PointLight')
1584 PointLight.Color = Color3.fromRGB(206, 200, 131)
1585 PointLight.Range = 4;
1586 PointLight.Brightness = 32.25;
1587 PointLight.Parent = Part;
1588 local lastInput;
1589 self.OtherMusic = Battle.OtherMusic;
1590 repeat
1591 Input = (typeof(lastInput or true) ~= 'boolean' and lastInput) or UIS.InputBegan:Wait()
1592 if (Input == 'MessedUp') then
1593 for i, v in pairs(self.Characters) do
1594 v = Battle:GetCharacterFromID(i);
1595 v:SetPrimaryPartCFrame(CFrames[i]);
1596 end
1597 local Index = PlayerGui:FindFirstChild('BattleChoices', true) and PlayerGui:FindFirstChild('BattleChoices', true):Destroy() or nil;
1598 local OtherIndex = PlayerGui:FindFirstChild('BattleBox', true) and PlayerGui:FindFirstChild('BattleBox', true):Destroy() or nil;
1599 Part = Part and Part:Destroy();
1600 local Length = 0.25;
1601 Tween(ColorCorrection, TweenInfo.new(Length), {Brightness = 0}):Play();
1602 Input = true; Battle.HoldUpped = true; break;
1603 end
1604 if (Input.KeyCode == Enum.KeyCode.Z) then
1605 local Index = PlayerGui:FindFirstChild('BattleChoices', true) and PlayerGui:FindFirstChild('BattleChoices', true):Destroy() or nil;
1606 local OtherIndex = PlayerGui:FindFirstChild('BattleBox', true) and PlayerGui:FindFirstChild('BattleBox', true):Destroy() or nil;
1607
1608 for i, v in pairs(self.Characters) do
1609 v = Battle:GetCharacterFromID(i);
1610 v:SetPrimaryPartCFrame(CFrames[i]);
1611 end
1612 Part = Part and Part:Destroy();
1613 local Length = 0.25;
1614 Tween(ColorCorrection, TweenInfo.new(Length), {Brightness = 0}):Play();
1615 Input = true; Battle.HoldUpped = true; break;
1616 elseif (Enum.KeyCode.X == Input.KeyCode) then --cursed
1617 Tween(workspace.CurrentCamera, TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0), {CFrame = self.BattleArea.Cameras.AmbushCamera.CFrame}):Play();
1618 local Index = PlayerGui:FindFirstChild('BattleChoices', true) and PlayerGui:FindFirstChild('BattleChoices', true):Destroy() or nil;
1619 local OtherIndex = PlayerGui:FindFirstChild('BattleBox', true) and PlayerGui:FindFirstChild('BattleBox', true):Destroy() or nil;
1620 self.Music:Resume();
1621 for i = 0, Vol, 0.075 do
1622 self.Music.Volume = i;
1623 Battle.OtherMusic.Volume = Battle.OtherMusic.Volume - i;
1624 wait();
1625 end
1626 for i, v in pairs(self.Characters) do
1627 v = Battle:GetCharacterFromID(i);
1628 v:SetPrimaryPartCFrame(CFrames[i]);
1629 end
1630 Part = Part and Part:Destroy();
1631 local Length = 0.25;
1632 Tween(ColorCorrection, TweenInfo.new(Length), {Brightness = 0}):Play()
1633 local Personas = {};
1634 local what = game:GetService('ReplicatedStorage'):WaitForChild('EffectStorage'):WaitForChild('DustPart'):Clone();
1635 local MiddleCF = self.EnemySpawns:GetChildren()[1].CFrame:Lerp(self.EnemySpawns:GetChildren()[#self.EnemySpawns:GetChildren()].CFrame, 0.5);
1636 local ChosenEffects = {};
1637 local ACF=0;
1638 local CompletedEffects = {};
1639 local Passed;
1640-- spawn(function()
1641-- repeat wait(.5) what.ParticleEmitter:Emit(1500) until Passed
1642-- end)
1643 what.CFrame = MiddleCF;
1644 what.Parent = Instance.new('Model', workspace)
1645 what.Parent.PrimaryPart = what;
1646 local a = Instance.new('Humanoid', what.Parent);
1647 what.ParticleEmitter.Enabled = true;
1648 a.HipHeight = game.Players.LocalPlayer.Character.Humanoid.HipHeight
1649 for i, v in pairs(self.Characters) do
1650 local N = v;
1651 if (i ~= BattleInfo.SelectedMember) then
1652 v = Battle:GetCharacterFromID(i);
1653 for i, v in pairs(v:GetDescendants()) do
1654 if (v:IsA("BasePart") or v:IsA('Decal')) and (v.Name ~= 'HumanoidRootPart') then
1655 local Transparency = Instance.new'NumberValue';
1656 Transparency.Name = 'Opacity'
1657 Transparency.Value = v.Transparency;
1658 Transparency.Parent = v
1659 spawn(function(a)
1660 wait(0.5)
1661 for i = v.Transparency, 1, 0.1 do
1662 wait();
1663 v.Transparency = i;
1664 end
1665 end)
1666 end
1667 end
1668 end
1669 ChosenEffects[N.Persona.Name] = N.Persona.Attacks[math.random(1, #N.Persona.Attacks)]
1670 ACF=ACF+1;
1671 end
1672 for i, v in pairs(self.Characters) do --todo // change all _G.Characters to self.Characters unless in initialization function
1673 Personas[v.Persona.Name]=Battle:createPersona(nil, true, i)
1674 Personas[v.Persona.Name].Name = v.Name;
1675 end
1676 wait();
1677 for i, v in pairs(self.Characters) do
1678 local N = v;
1679 if (i ~= BattleInfo.SelectedMember) then
1680 v = Battle:GetCharacterFromID(i);
1681 v:WaitForChild('Humanoid'):MoveTo(MiddleCF.Position);
1682 end
1683 end
1684 wait(3.5);
1685 spawn(function()
1686 local Next = 0.1+math.random()/2
1687 while wait(Next) do
1688 if (Passed) then
1689 local HeavyHit = ReplicatedStorage.Music:WaitForChild('HeavyHit')
1690 HeavyHit = HeavyHit:Clone()
1691 HeavyHit.Parent = game.Players.LocalPlayer.PlayerGui;
1692 HeavyHit.PlayOnRemove = true;
1693 HeavyHit:Destroy();
1694 break;
1695 end;
1696 local HeavyHit = ReplicatedStorage.Music:WaitForChild('NormalHit')
1697 HeavyHit = HeavyHit:Clone()
1698 HeavyHit.Parent = game.Players.LocalPlayer.PlayerGui;
1699 HeavyHit.PlayOnRemove = true;
1700 HeavyHit:Destroy();
1701 Next = 0.1+math.random()/2
1702 end
1703 end)
1704 for i, v in pairs(ChosenEffects) do
1705 local Effect = Effects[getAttack(v).Effect] or function() end;
1706 coroutine.wrap(function()
1707 Effect({
1708 PrimaryPart = what;
1709 TargetPart = Personas[i].PrimaryPart;
1710 IgnoreAnimation = false;
1711 TargetFolder = self.EnemyContainer;
1712 });
1713 CompletedEffects[#CompletedEffects+1] = v;
1714 end)()
1715 end
1716 repeat wait() --[[impwarn(#CompletedEffects, ACF, ACF==#CompletedEffects)]] until #CompletedEffects == ACF
1717 Passed = true;
1718 for i, v in pairs(self.Characters) do
1719 v = Battle:GetCharacterFromID(i);
1720 v.Humanoid:MoveTo(v.PrimaryPart.Position);
1721 wait();
1722 v:SetPrimaryPartCFrame(CFrames[i]);
1723 for i, v in pairs(v:GetDescendants()) do
1724 spawn(function(a)
1725 if (v:IsA('BasePart') or v:IsA('Decal')) and (v:FindFirstChild'Opacity') then
1726 --impwarn(v.Transparency, v.Opacity.Value)
1727 for i = v.Transparency, v.Opacity.Value, -0.1 do
1728 wait();
1729 v.Transparency = i;
1730 end
1731 end
1732 end)
1733 end
1734 end
1735-- Effects[attack.Effect]({PrimaryPart = Char.PrimaryPart, --enemy's part
1736-- IgnoreAnimation = ia, --ignore animation?
1737-- TargetPart = Me.PrimaryPart, --my primary part
1738-- TargetFolder = self.EnemyContainer --enemy's folder? WHAT
1739-- })
1740
1741 what.ParticleEmitter.Enabled = false;
1742 local Damage = 0;
1743 for i, v in pairs(self.Characters) do
1744 local EquippedMelee = v.Equipped.Melee
1745 local Item = Items[EquippedMelee];
1746 if (Item) then
1747 Damage = Damage+(Item.Damage or 0);
1748 end
1749 end
1750 --[[
1751 attacks.Lunge = {
1752 Name = 'Lunge';
1753 Type = 'Physical',
1754 Damage = 35;
1755 HPRequired = 5;
1756 Description = 'Slight Physical damage to one foe.';
1757 JPDesc = '???????????????' --//??
1758 }
1759 --]]
1760 wait(1);
1761 Battle:AdorneeHealth();
1762 Battle:Damage(self.Characters[1], self.Enemies[1], {
1763 Name = "All Out Attack",
1764 Type = "Almighty",
1765 Damages = "All";
1766 Damage = Damage;
1767 HPRequired = 0;
1768 Description = "No time for apologies!";
1769 }, true)
1770 Battle:TweenHealth();
1771 for i, v in pairs(self.Enemies) do
1772 v.Debuffs = {};
1773 end
1774 RemoveAllPersonas(true)
1775 Input = true;
1776 elseif (Input.KeyCode == Enum.KeyCode.Left or Input.KeyCode == Enum.KeyCode.Right or Input.KeyCode == Enum.KeyCode.DPadLeft or lastInput == "Left" or lastInput == "Right") then
1777 --print(Input.Name:match('Left') or Input.Name:match('Right'));
1778 Input = lastInput and {Name = lastInput} or Input.KeyCode;
1779 Input = {Name = Input.Name:match('Left') or Input.Name:match('Right')};
1780 BattleInfo.SelectedEnemyGuy = self:GetEnemy(Input.Name:sub(1,1):lower(), BattleInfo.SelectedEnemyGuy)
1781 local Char = self:GetEnemyFromName(BattleInfo.SelectedEnemyGuy, true);
1782 Battle:CharacterPositionButWithPersona(1, Char.PrimaryPart, nil, 11, 3.5)
1783 Part = not (Part and Part:Destroy()) and Instance.new('Part')
1784 Part.Anchored = true;
1785 Part.Transparency = 1;
1786 Part.CFrame = Char:GetPrimaryPartCFrame() + Vector3.new(0,5,0);
1787 Part.CanCollide = false;
1788 Part.Parent = workspace;
1789
1790 local PointLight = Instance.new('PointLight')
1791 PointLight.Color = Color3.fromRGB(206, 200, 131)
1792 PointLight.Range = 4;
1793 PointLight.Brightness = 32.25;
1794 PointLight.Parent = Part;
1795
1796 lastInput = nil;
1797 lastInput = _G.ShowIntroSpeech(game:GetService('ReplicatedStorage').ModuleScripts.Dialogue.Timid, self.Enemies[SEG].Name, Battle, self.Enemies[SEG], BattleInfo.SelectedEnemyGuy);
1798 end
1799 until Input == true;
1800 self.Music:Resume();
1801 for i = 0, Vol, 0.075 do
1802 self.Music.Volume = i;
1803 Battle.OtherMusic.Volume = Battle.OtherMusic.Volume - i;
1804 wait();
1805 end
1806 Battle.OtherMusic:Stop();
1807 Battle.OtherMusic:Destroy();
1808 self.OneMore = false;
1809 end
1810
1811
1812
1813
1814
1815
1816
1817
1818 if (self.OneMore == 'W') then
1819 self.OneMore = true
1820 end
1821
1822 --PlayerGui.Reticle.Enabled = false;
1823 local NoHealth = 0;
1824 for i, v in pairs(self.Enemies) do
1825 if (v.Health <= 0) then
1826 NoHealth = NoHealth + 1;
1827 end
1828 end
1829
1830 local NHealth = 0
1831 for i, v in pairs(self.Characters) do
1832 if (v.Health <= 0) then
1833 NHealth = NHealth + 1;
1834 end;
1835 end
1836 RemoveAllPersonas(true)
1837
1838 self:EndBattleProtocol(NoHealth, NHealth, false)
1839-- if (NoHealth == #self.Enemies or NHealth == #self.Characters) then
1840-- self:EndBattle();
1841--
1842-- for i, v in pairs(Character.Humanoid:GetPlayingAnimationTracks()) do
1843-- v:Stop(); --stop all playing animations, the default animator will replay animations again so it doesn't matter'
1844-- end
1845-- local PLighting = ReplicatedStorage:FindFirstChild('Previous Lighting');
1846-- if (PLighting) then
1847-- for i, v in pairs(PLighting:GetChildren()) do
1848-- pcall(function()
1849-- game:GetService('Lighting')[v.Name] = v.Value;
1850-- end)
1851-- end
1852-- end
1853-- self.BattleArea:Destroy();
1854-- for i, v in pairs(game:GetService'Lighting':GetChildren()) do
1855-- if (v.ClassName:match('Effect') and v.Name ~= 'e') then
1856-- v.Enabled = true
1857-- end
1858-- end
1859-- Character:SetPrimaryPartCFrame(self.PositionBeforeBattle)
1860-- Character:WaitForChild('HumanoidRootPart').Anchored = false;
1861-- StopAnimation(nil, Character:WaitForChild('Humanoid'))
1862-- _G.Music:Play();
1863-- return true, script:Destroy(); --self destruct script just to be safe
1864-- end
1865 BattleInfo.BattleStage = 'Main'; --reset BattleStage so the battle can basically refresh itself upon a new turn
1866 BattleInfo.SelectedEnemyGuy = 1 --workspace['Enemy Container']:GetChildren()[1] --set the selectedenemyguy to the first person
1867 if (BattleInfo.SelectedMember == 0) then
1868 --reset all tables in case a goof happened
1869 BattleInfo.EnemyTurns = {};
1870 BattleInfo.PlayerTurns = {};
1871 BattleInfo.MemberActions = {};
1872 elseif (BattleInfo.SelectedMember == 'Enemy') then
1873 BattleInfo.MemberActions = {}; --reset member actions if the player has already done stuff
1874 end
1875
1876 local ChosenMember;
1877 if (not self.AvailableUsers) or (#self.AvailableUsers == 0) then
1878 impwarn("Refilling now.")
1879 ChosenMember = self:selectViableMember(true); --modify selectViableMember to provide enemy turns so debuffs wear off individually
1880 else
1881 impwarn("Not refilling, choosing a chracter now.")
1882 ChosenMember = self:selectViableMember() --true variable means that it just needs to choose a character and thats it, no reselecting
1883 end
1884 repeat game:GetService('RunService').RenderStepped:Wait();
1885 if not (typeof(ChosenMember) == "table") then
1886 if (not self.AvailableUsers) or (#self.AvailableUsers == 0) then
1887 impwarn("No chosen member. Refilling now.")
1888 ChosenMember = self:selectViableMember(true); --modify selectViableMember to provide enemy turns so debuffs wear off individually
1889 else
1890 impwarn("No chosen member. Not refilling.")
1891 ChosenMember = self:selectViableMember() --true variable means that it just needs to choose a character and thats it, no reselecting
1892 end
1893 end
1894 until (typeof(ChosenMember) == "table")
1895 impwarn("PASSED.")
1896 table.remove(self.AvailableUsers, 1)
1897 ChosenMember.Guard = false;
1898 BattleInfo.SelectedMember = ChosenMember;
1899
1900 for x, v in pairs(self.Characters) do
1901 local n = v;
1902 BattleInfo.PlayerTurns[x] = BattleInfo.PlayerTurns[x] or 0;
1903 --warn('lope')
1904 if (v.Debuffs) then
1905 --warn('fat')
1906 for i, v in pairs(v.Debuffs) do
1907 --warn('worn')
1908 if (v.TurnAdded and v.Length and v.TurnAdded + v.Length <= BattleInfo.PlayerTurns[x]) then
1909 --warn('hi lol ecksdee')
1910 self:MoveCameraToCharacter(x)
1911 if (v.Name ~= 'Down') then
1912 local DebuffTitle = (v.Name or '???')..' has worn off!';
1913 DebuffTitle = v.WearOff or DebuffTitle;
1914 showLabel(DebuffTitle, 1.5);
1915 end
1916 if (v.Name == 'Down') then
1917 self.Characters[x].Debuffs.Down = nil;
1918 end
1919 spawn(function()
1920 print(n.Debuffs[i])
1921 end)
1922 impwarn('Debuff data:', v.Name, v.Length, v.TurnAdded, 'Turn:', BattleInfo.EnemyTurns[x], 'Holder:', n.Name)
1923 end
1924 end
1925 end
1926 if (v.Health == 0) then
1927 v.Debuffs = {};
1928 end
1929 end
1930
1931 if (self.Characters[BattleInfo.SelectedMember] and self.Characters[BattleInfo.SelectedMember].Health > 0) then
1932 if (animationStatus(game.ReplicatedStorage.AnimationAssets.Death.Stay, Battle:GetCharacterFromID(BattleInfo.SelectedMember).Humanoid) and animationStatus(game.ReplicatedStorage.AnimationAssets.Death.Stay, Battle:GetCharacterFromID(BattleInfo.SelectedMember).Humanoid).IsPlaying) then
1933 impwarn('Character was alive but down! Recovering...')
1934 local Humanoid = Battle:GetCharacterFromID(BattleInfo.SelectedMember).Humanoid;
1935 --stop animation b
1936 self:InvisibleEnemies()
1937 StopAnimation(game.ReplicatedStorage.AnimationAssets.Death.Stay, Humanoid)
1938 StopAnimation(game.ReplicatedStorage.AnimationAssets.Death.Fall, Humanoid)
1939 self:MoveCameraToCharacter(BattleInfo.SelectedMember)
1940 local Anim = LoadAnimation(game.ReplicatedStorage.AnimationAssets.Rise.Rise, Humanoid)
1941 Anim:Play()
1942 Anim.Stopped:Wait()
1943 self:InvisibleEnemies()
1944 end
1945 end
1946 if (typeof(ChosenMember) ~= 'table') and not self.OneMore then
1947 BattleInfo.PlayerTurns[ChosenMember] = BattleInfo.PlayerTurns[ChosenMember] and BattleInfo.PlayerTurns[ChosenMember] + 1 or 1;
1948 warn(_G.Characters[ChosenMember].Name.."'s Turn:", BattleInfo.PlayerTurns[ChosenMember])
1949 if (checkIncapacitated(self.Characters[ChosenMember], nil)) then
1950 warn'incapazitated'
1951 return Battle:NewTurn()
1952 end
1953 end
1954-- Battle:ResetCharacters()
1955 if (checkIncapacitated(self.Characters[ChosenMember])) then
1956 warn('Member is incapacitated! Skipping turn..')
1957 BattleInfo.MemberActions[ChosenMember] = "Incapacitated"
1958 return Battle:NewTurn();
1959 end
1960
1961 for x, v in pairs(self.Enemies) do
1962 local n = v;
1963 --warn('lope2')
1964 if (v.Debuffs) then
1965 --warn('fat2')
1966 for i, v in pairs(v.Debuffs) do
1967 --warn('lorn2')
1968 BattleInfo.EnemyTurns[n.ID] = BattleInfo.EnemyTurns[n.ID] or 1;
1969 if (v.TurnAdded and v.Length and v.TurnAdded + v.Length <= BattleInfo.EnemyTurns[n.ID]) then
1970 --warn('enemy lolecksdee')
1971 Battle:MoveCameraToEnemy(n.ID)
1972 if (v.Name ~= 'Down') then
1973 showLabel((v.Name or '???')..' has worn off!', 1.5);
1974 end
1975
1976 if (v.Name == 'Down') then
1977 n.Debuffs.Down = nil;
1978 warn("DOWN DATA:", n.Debuffs.Down)
1979 --stop animation a
1980 self:InvisibleParty()
1981 local Humanoid = Battle:GetEnemyFromID(n.ID, true).Humanoid;
1982 StopAnimation(game.ReplicatedStorage.AnimationAssets.Death.Stay, Humanoid)
1983 StopAnimation(game.ReplicatedStorage.AnimationAssets.Death.Fall, Humanoid)
1984 local Anim = LoadAnimation(game.ReplicatedStorage.AnimationAssets.Rise.Rise, Humanoid)
1985 Anim:Play()
1986 Anim.Stopped:Wait()
1987 self:InvisibleParty()
1988 end
1989 else
1990 warn('Debuff data:', v.Name, v.Length, v.TurnAdded, 'Turn:', BattleInfo.EnemyTurns[n.ID], 'Holder:', n.Name)
1991 end
1992 end
1993 end
1994 if (v.Health == 0) then
1995 v.Debuffs = {};
1996 end
1997 end
1998
1999 if (not self.Ambush) and tonumber(ChosenMember) then
2000 Battle:CharacterPosition() --reset camera position to the player's back
2001 elseif (self.Ambush) then
2002 Battle:AmbushPosition()
2003 end
2004 if (typeof(ChosenMember) == 'table') then
2005 BattleInfo.EnemyTurns[ChosenMember.ID] = BattleInfo.EnemyTurns[ChosenMember.ID] and BattleInfo.EnemyTurns[ChosenMember.ID] + 1 or 1;
2006 PlayerGui.PersonaListR.Adornee = nil;
2007 PlayerGui.HealthBar.Adornee = nil;
2008 if (checkIncapacitated(ChosenMember)) then
2009 warn('Enemy is incapacitated! Skipping turn..')
2010 BattleInfo.EnemyActions[ChosenMember.ID] = "Incapacitated";
2011 return Battle:NewTurn();
2012 end
2013 --Battle:PointCameraToEnemy(ChosenMember.ID, true)
2014 if (ChosenMember.CTC and ChosenMember.TurnCount and ChosenMember.CTC >= ChosenMember.TurnCount) then
2015 --impwarn("First")
2016 BattleInfo.EnemyActions[ChosenMember.ID] = true;
2017 elseif (ChosenMember.CTC and ChosenMember.TurnCount and ChosenMember.CTC < ChosenMember.TurnCount) then
2018 --impwarn("Second")
2019 ChosenMember.CTC = ChosenMember.CTC+1;
2020 else
2021 --impwarn("Third");
2022 BattleInfo.EnemyActions[ChosenMember.ID] = true;
2023 end
2024 EnemyAPI:EnemyFunction(self.Characters[math.random(1, #self.Characters)], ChosenMember, Battle)
2025
2026 wait(1.5)
2027
2028 return Battle:NewTurn(); --make the function recursive
2029 end --enemy ai
2030 PlayerGui.PersonaListR.Adornee = ChosenMember == 1 and Character.PrimaryPart or workspace:WaitForChild('Party Container'):WaitForChild(self.Characters[ChosenMember].Name).PrimaryPart
2031 --^ set the adornee to the localplayer's primary part if the chosenmember is one otherwise it sets it to the other's primaryparts.
2032
2033 --using a stage system to determine where we are at
2034
2035 --connect to UserInputService for epicness
2036 local InputBegan; --define InputBegan as a dummy variable
2037 local KeyPressed;
2038 pcall(function()
2039 self.Characters[BattleInfo.SelectedEnemyGuy].Guard = false;
2040 end)
2041 InputBegan = UIS.InputBegan:Connect(function(Key, Process)
2042 if (KeyPressed or Process) then return nil end
2043 BattleInfo.MemberActions[BattleInfo.SelectedMember] = true; --remove this
2044 ReplicatedStorage.Music.Blip:Play();
2045
2046 --redefine InputBegan as the signal so we can keep the signal local whilst being able to disconnect it in the signal
2047 Key = Key.KeyCode;
2048 local Stage = BattleInfo.BattleStage
2049
2050
2051 if (Stage == 'Main' or Stage == 'BatonPass') then
2052
2053
2054
2055 if (Key == K.Z or Key == K.ButtonY) then
2056
2057
2058 local Humanoid = self:GetCharacterFromID(BattleInfo.SelectedMember):WaitForChild('Humanoid')
2059 BattleInfo.BattleStage = 'PersonaAttackList'
2060 PlayerGui['Persona Attacks List'].Enabled = true
2061 BattleInfo.MemberActions[BattleInfo.SelectedMember] = true;
2062 game:GetService('RunService').RenderStepped:Wait()
2063-- for i, v in pairs(PlayerGui['Persona Attacks List'].Table:GetChildren()) do
2064-- if (v:IsA('Frame')) then
2065-- v.Button.Selected = true;
2066-- game:GetService('GuiService').SelectedObject = v.Button;
2067-- break;
2068-- end
2069-- end
2070 return true;
2071 elseif (Key == K.Q or Key == K.ButtonR2) and (self.OneMore) then
2072
2073 BattleInfo.BattleStage = 'BatonPass'
2074 BattleInfo.SelectedEnemyGuy = BattleInfo.SelectedMember; --set btn pass to passer guy
2075 self:MoveCameraToCharacter(BattleInfo.SelectedMember)
2076 return true;
2077 end
2078 end
2079
2080 if (Key == K.Backspace or Key == K.ButtonB) and Stage ~= 'Main' then
2081 Battle:RemoveHealthbars();
2082 if (Stage == 'AwaitGuard') then
2083 if (not self.Ambush) then
2084 Battle:CharacterPosition() --reset camera position to the player's back
2085 else
2086 Battle:AmbushPosition()
2087 end
2088 RemoveAllPersonas()
2089 PlayerGui['Guard'].Enabled = false;
2090 BattleInfo.BattleStage = 'Main'
2091 return nil;
2092 elseif (Stage == 'PersonaTarget' or Stage == 'PersonaChange') then
2093 BattleInfo.Waffle = "AnimAndSound";
2094 BattleInfo.BattleStage = 'PersonaAttackList'
2095 self.PersonaSelect = nil;
2096 return nil;
2097 elseif (Stage == 'Analysis') then
2098
2099 BattleInfo.SelectedPersonaAttack = {Name = 'Analysis'}; --KOWALSKI
2100 BattleInfo.BattleStage = 'PersonaTarget'
2101 return nil;
2102
2103 else
2104 if (not self.Ambush) then
2105 Battle:CharacterPosition() --reset camera position to the player's back
2106 else
2107 Battle:AmbushPosition()
2108 end
2109 RemoveAllPersonas()
2110 BattleInfo.BattleStage = 'Main'
2111 BattleInfo.SelectedPersonaAttack = {};
2112 return nil;
2113 end;
2114 elseif (Key == K.LeftBracket or Key == K.RightBracket or Key == K.ButtonL1 or Key == K.ButtonR1) and (Stage == 'PersonaChange' or Stage == 'PersonaAttackList') and (BattleInfo.SelectedMember == 1) then
2115 Key = (Key == K.LeftBracket or Key == K.ButtonL1) and 'Left' or 'Right'
2116 local OrigTable = {}
2117 local x = 0;
2118 local targetI = nil;
2119 for i, v in pairs(Personas) do
2120 if ((not self.PersonaSelect) and (v.Name == self.Characters[1].Persona.Name)) or self.PersonaSelect == x then
2121 --warn('Not Self.PersonaSelect, and v.Name is self.Characters[1].Persona.Name, or self.PersonaSelect is equal to X.')
2122 targetI = x;
2123 else
2124 --warn('?????')
2125 end
2126 if (not v.Unspawnable) and (v.Name) then
2127 x=x+1; --put the x in the Unspawnable area so it only increments if the persona is indeed spawnable, so we dont spawn a boss persona.
2128
2129 OrigTable[x] = v
2130
2131 end --so we don't use big boss personas by accident
2132 end
2133
2134 self.CurrentPersona = nil
2135 --obtain player
2136 for i, v in pairs(OrigTable) do
2137
2138 if (i == targetI) and (Stage ~= 'PersonaChange') then --v-1
2139
2140 self.PersonaSelect = targetI;
2141 self.CurrentPersona = v[2] --set thing to the table so we can use it's first iterator value to determine what place we are in'
2142 elseif (i == self.PersonaSelect or i == 1) then
2143 if (Key == 'Left') then
2144 if (OrigTable[(self.PersonaSelect or 0)-1]) then
2145 self.PersonaSelect = self.PersonaSelect and self.PersonaSelect-1 or #OrigTable;
2146 else
2147 self.PersonaSelect = #OrigTable;
2148 end
2149 elseif (Key == 'Right') then
2150 if (OrigTable[(self.PersonaSelect or 0)+1]) then
2151 self.PersonaSelect = self.PersonaSelect and self.PersonaSelect+1 or 1;
2152 else
2153 self.PersonaSelect = 1;
2154 end
2155 end
2156 self.CurrentPersona = OrigTable[self.PersonaSelect];
2157 break;
2158 end
2159 end
2160
2161 if (not self.CurrentPersona) then
2162 self.CurrentPersona = OrigTable[1];
2163 self.PersonaSelect = 1;
2164 end
2165
2166 _G.RequestPersona(self.CurrentPersona or OrigTable[1]);
2167 BattleInfo.BattleStage = 'PersonaChange';
2168 elseif (Key == K.R or Key == K.ButtonL1) and (BattleInfo.BattleStage == 'Main') then
2169 BattleInfo.SelectedPersonaAttack = {Name = 'Analysis'}; --KOWALSKI
2170 BattleInfo.BattleStage = 'PersonaTarget'
2171 elseif (Key == K.Return or Key == K.ButtonA) then
2172
2173 if (UIS:IsKeyDown(K.R)) then
2174 KeyPressed = true;
2175 return true;
2176 end
2177
2178 if (BattleInfo.BattleStage == 'PersonaTarget' and BattleInfo.SelectedPersonaAttack and BattleInfo.SelectedPersonaAttack.Name == 'Analysis') then
2179
2180 _G.RequestPersona(self.Enemies[BattleInfo.SelectedEnemyGuy] or self.Enemies[#self.Enemies], true)
2181 BattleInfo.BattleStage = 'Analysis'
2182 return true;
2183 end
2184
2185 if (self.CurrentPersona and Stage == 'PersonaChange') then
2186 local Persona = self.CurrentPersona or Personas.Widgeon;
2187 local NeverSwappedPersona = self.CurrentPersona.Name == self.Characters[1].Persona.Name
2188 self.Characters[1].Persona = self.CurrentPersona or Personas.Widgeon;
2189 RefreshPersonaList(not NeverSwappedPersona)
2190 BattleInfo.BattleStage = 'PersonaAttackList'
2191 return true;
2192 end
2193
2194 if (Stage == 'AwaitGuard') then
2195 self.Characters[BattleInfo.SelectedMember].Guard = true;
2196 KeyPressed = true;
2197 PlayerGui['Guard'].Enabled = false;
2198 BattleInfo.MemberActions[BattleInfo.SelectedMember] = true;
2199 wait(.25)
2200 return true;
2201 end
2202
2203 if (Stage == 'BatonPass') then
2204 if (BattleInfo.SelectedEnemyGuy == BattleInfo.SelectedMember) then
2205 spawn(function(a) showLabel('Cannot baton pass to yourself.', 0.25) end)
2206 ReplicatedStorage.Music.Error:Play();
2207 return true;
2208 end
2209 if (self.Characters[BattleInfo.SelectedEnemyGuy].BatonPassed) then
2210 showLabel('Cannot baton pass to someone twice.', 0.25)
2211 return true;
2212 end
2213 self.Characters[BattleInfo.SelectedEnemyGuy].BatonPassed = true;
2214 self.BatonPass = BattleInfo.SelectedEnemyGuy;
2215 KeyPressed = true;
2216 return true;
2217 end
2218
2219 if (Stage == 'PersonaAttackList') then
2220 KeyPressed = 'Waiting'
2221 if (not game:GetService('GuiService').SelectedObject) then KeyPressed = false; return nil end;
2222
2223 local Attack = getAttack(game:GetService('GuiService').SelectedObject.Parent.AttackTitle.Text);
2224
2225 if Attack.HPRequired and (modifyDamage(Attack.HPRequired, self.Characters[BattleInfo.SelectedMember].MaxHealth) > self.Characters[BattleInfo.SelectedMember].Health) then
2226 KeyPressed = false;
2227 ReplicatedStorage.Music['Error']:Play();
2228 return true, showLabel('Not enough HP!');
2229 elseif (Attack.SPRequired and self.Characters[BattleInfo.SelectedMember].SP < Attack.SPRequired) then
2230 KeyPressed = false;
2231 ReplicatedStorage.Music['Error']:Play();
2232 return true, showLabel('Not enough SP!');
2233 elseif Attack.Type == 'Buff' then
2234 if (Attack.Type2 == 'Revive') then
2235 local NobodyDead = true
2236 for i, v in pairs(self.Characters) do
2237 if (v.Health == 0) then
2238 NobodyDead = false
2239 end
2240 end
2241 if (NobodyDead) then
2242 KeyPressed = false;
2243 ReplicatedStorage.Music['Error']:Play();
2244 return true, showLabel('There are no fallen party members.');
2245 end
2246 elseif (Attack.Type2 == 'Cure') then
2247 local HasDebuff = false;
2248 for i, v in pairs(self.Characters) do
2249 for i, v in pairs(v.Debuffs) do
2250 if (Attack.Debuffs[v.Name]) then
2251 HasDebuff = true;
2252 end
2253 end
2254 end
2255 if (not HasDebuff) then
2256 KeyPressed = false;
2257 ReplicatedStorage.Music['Error']:Play();
2258 return true, showLabel('There are no party members with debuffs.');
2259 end
2260 else
2261 local FullHealth = 0;
2262 for i, v in pairs(self.Characters) do
2263 if (v.Health == v.MaxHealth) then
2264 FullHealth = FullHealth+1
2265 end
2266 end
2267
2268 if (FullHealth == #self.Characters) then
2269 KeyPressed = false;
2270 ReplicatedStorage.Music['Error']:Play();
2271 return true, showLabel('All party members are fully healed.');
2272 end
2273 end
2274 end
2275 BattleInfo.BattleStage = 'PersonaTarget'
2276 BattleInfo.SelectedEnemyGuy = (not (Attack.Type == 'Buff' or (Attack.Type == 'Kaja' and Attack.Type2 ~= 'Debuff'))) and self:GetFirstLivingEnemy() or BattleInfo.SelectedMember;
2277 BattleInfo.SelectedPersonaAttack = Attack
2278 self:RemoveHealthbars()
2279 self:AdorneeHealth();
2280 KeyPressed = false;
2281 --local x = not self.Ambush and ((Attack.Type == 'Buff' or Attack.Type == 'Kaja') and
2282 --self:MoveCameraToCharacter(BattleInfo.SelectedMember) or self:MoveCameraToEnemy(self:GetEnemyFromID(BattleInfo.SelectedEnemyGuy)))
2283
2284 --get attack from selected object name^
2285 if (self.Ambush) and ((Attack.Type == 'Kaja' and Attack.Type2 ~= 'Debuff') or Attack.Type == 'Buff') then
2286 --PlayerGui.Reticle.Enabled = true;
2287 PlayerGui.Reticle.Adornee = self:GetCharacterFromID(BattleInfo.SelectedMember)
2288 end
2289
2290 local Char = self:GetEnemyFromName(BattleInfo.SelectedEnemyGuy, true);
2291
2292 --move camera seamelessly
2293
2294 local Factor = (Attack.Heals and "Heals") or (Attack.Damages and "Damages") or nil;
2295 if (Factor and not self.Ambush) then
2296 local y = (Factor == "Heals" and self.PartySpawns:GetChildren()) or (Factor == "Damages" and self.EnemySpawns:GetChildren());
2297 local First, Last;
2298 local LivingEnemies = 0;
2299 for i, v in pairs(self.Enemies) do
2300 if (v.Health > 0) then
2301 LivingEnemies=LivingEnemies+1;
2302 end
2303 end
2304 First = y[1]; --get the first spawn
2305 Last = y[LivingEnemies]; --get the last spawn
2306
2307 local PositionToCirculateAround = First.CFrame:Lerp(Last.CFrame, 0.5) --get their distance from the leftmost cframe
2308 local thing = CFrame.new(PositionToCirculateAround.LookVector*(#(Factor == "Damages" and (function()local a={};for i=0,LivingEnemies do a[#a+1]=i return a end end)() or self.Characters)*3.5) + PositionToCirculateAround.Position);
2309 --local newThing = thing + Vector3.new(0,LivingEnemies*4,0)
2310 local EC = 0;
2311 local D
2312 for i, v in pairs(self.Enemies) do
2313 if (v.Health > 0) then
2314 EC = EC+1;
2315 D = not D and v.ID or D;
2316 end
2317 end
2318 workspace.CurrentCamera.CFrame = CFrame.new(workspace.CurrentCamera.CFrame.Position, (EC == 1 and self:GetCharacterFromID(D).PrimaryPart.CFrame.Position) or thing.Position+Vector3.new(0,(Character.Humanoid.HipHeight+2 or 6.5),0))
2319 return 0;
2320 end
2321
2322 if (not self.Ambush) and (not Factor) then
2323 Battle:CharacterPositionButWithPersona(nil, Char.PrimaryPart.CFrame)
2324 else
2325 PlayerGui.Reticle.Adornee = Char.PrimaryPart;
2326 --PlayerGui.Reticle.Enabled = true;
2327 end
2328
2329 if (self.Ambush) and not (Attack.Type == 'Kaja' or Attack.Type == 'Buff') then --woo spaghetti
2330 PlayerGui.Reticle.Adornee = Char.PrimaryPart;
2331 --PlayerGui.Reticle.Enabled = true;
2332 elseif (not self.Ambush) then
2333 --PlayerGui.Reticle.Enabled = false;
2334 end
2335 elseif (BattleInfo.BattleStage == 'PersonaTarget' and Battle.FinishedAttacking) then
2336 local Attack = BattleInfo.SelectedPersonaAttack;
2337 Battle.FinishedAttacking = false;
2338 if (Attack.Damage) then
2339 pcall(function()
2340 local SelectedShouts = Shouts.AttackShouts[tostring(BattleInfo.SelectedMember or 1)]
2341 local newShout = SelectedShouts:GetChildren()[math.random(1, #SelectedShouts:GetChildren())]:Clone();
2342 newShout.Parent = PlayerGui;
2343 newShout.PlayOnRemove = true;
2344 wait();
2345 newShout:Destroy();
2346 end)
2347 end
2348 Battle:Damage(self.Characters[BattleInfo.SelectedMember], (not Attack.Heals) and self.Enemies[BattleInfo.SelectedEnemyGuy] or self.Characters[1], Attack);
2349 KeyPressed = true;
2350 end
2351 elseif (Key == K.C or Key == K.ButtonB) then
2352 if (BattleInfo.BattleStage == 'Main') then
2353 BattleInfo.BattleStage = 'AwaitGuard'
2354 PlayerGui['Guard'].Enabled = true;
2355 return nil;
2356 elseif (BattleInfo.BattleStage == 'AwaitGuard') then
2357 PlayerGui['Guard'].Enabled = false;
2358 BattleInfo.BattleStage = 'Main'
2359 return nil;
2360 end
2361 elseif (Key == K.Left or Key == K.Right or Key == K.DPadLeft or Key == K.DPadRight) and (BattleInfo.SelectedPersonaAttack and (BattleInfo.BattleStage == 'PersonaTarget' or BattleInfo.BattleStage == 'BatonPass')) and (not BattleInfo.SelectedPersonaAttack.Damages) and not BattleInfo.SelectedPersonaAttack.Heals then
2362 local Attack = BattleInfo.SelectedPersonaAttack;
2363 Key = {Name = Key.Name:match('Left') or Key.Name:match('Right')};
2364 local Factor = (Attack.Heals and "Heals") or (Attack.Damages and "Damages") or nil;
2365
2366 if (Attack.Type2 ~= "Debuff") and (BattleInfo.BattleStage == 'BatonPass' or Attack.Type == 'Kaja' or Attack.Type == 'Buff') then
2367 print(Attack.Name, Attack.Type, Attack.Type2, "Facing toward character.")
2368 BattleInfo.SelectedEnemyGuy = self:GetCharacter(Key.Name:sub(1,1):lower(), BattleInfo.SelectedEnemyGuy, (BattleInfo.SelectedPersonaAttack.Type2 == 'Revive' or nil)) or BattleInfo.SelectedEnemyGuy
2369 local Char = self:GetCharacterFromID(BattleInfo.SelectedEnemyGuy);
2370 Battle:MoveCameraToCharacter(BattleInfo.SelectedEnemyGuy);
2371 --PlayerGui.Reticle.Adornee = Char.PrimaryPart;
2372 ----PlayerGui.Reticle.Enabled = true;
2373 else
2374 print(Attack.Name, Attack.Type, Attack.Type2, "Facing toward enemy.")
2375 BattleInfo.SelectedEnemyGuy = self:GetEnemy(Key.Name:sub(1,1):lower(), BattleInfo.SelectedEnemyGuy)
2376 local Char = self:GetEnemyFromName(BattleInfo.SelectedEnemyGuy, true);
2377 if (not self.Ambush) then
2378 Battle:CharacterPositionButWithPersona(nil, Char.PrimaryPart.CFrame)
2379 else
2380 --PlayerGui.Reticle.Adornee = Char.PrimaryPart;
2381 ----PlayerGui.Reticle.Enabled = true;
2382 end
2383 end
2384 self:RemoveHealthbars()
2385 self:AdorneeHealth();
2386 end
2387 return true;
2388 end)
2389
2390 repeat wait() until KeyPressed == true; --strict comparison because keypressed is also assigned to strings
2391 if (InputBegan) then
2392 InputBegan:Disconnect();
2393 end
2394 Battle.FinishedAttacking = true;
2395 if (self.OneMore == true) then
2396 self.OneMore = false;
2397 end
2398 return Battle:NewTurn();
2399end
2400function RefreshPersonaList(sound)
2401 --impwarn("Sound:", sound)
2402 for i,v in pairs(PlayerGui["Persona Attacks List"].List.Frame:GetChildren()) do
2403 if (v.Name ~= "Grid") then v:Destroy() end;
2404 end
2405
2406 if (PlayerGui:WaitForChild("Persona Attacks List").Enabled) then
2407
2408
2409 local y = RichText:New(PlayerGui:WaitForChild('Persona Attacks List')['ID Background']:WaitForChild('PersonaName'), '<TextScale=1><TextScaled=true>'..personaIfy(Battle.Characters[BattleInfo.SelectedMember].Persona.Nickname or Battle.Characters[BattleInfo.SelectedMember].Persona.Name or '???'));
2410 y:Show()
2411 spawn(function()
2412 if (not sound) then
2413 pcall(function()
2414 if (BattleInfo.Waffle == 'AnimAndSound') then
2415 local SFX = ReplicatedStorage.SFX.SummonPersona:Clone();
2416 SFX.Parent = PlayerGui;
2417 SFX.PlayOnRemove = true;
2418 SFX:Destroy();
2419 elseif (not BattleInfo.Waffle) then
2420 local Humanoid = Battle:GetCharacterFromID(BattleInfo.SelectedMember):WaitForChild('Humanoid')
2421 BattleInfo.BattleStage = 'PersonaAttackList'
2422 LoadAnimation(ReplicatedStorage.AnimationAssets.Spin.Spin, Humanoid):Play();
2423 local SFX = ReplicatedStorage.SFX.SummonPersona:Clone();
2424 SFX.Parent = PlayerGui;
2425 SFX.PlayOnRemove = true;
2426 SFX:Destroy();
2427 if (math.random(1, 15) < 10) then
2428 local SelectedShouts = Shouts.PersonaShout[tostring(BattleInfo.SelectedMember or 1)]
2429 local newShout = SelectedShouts:GetChildren()[math.random(1, #SelectedShouts:GetChildren())]:Clone();
2430 newShout.Parent = PlayerGui;
2431 newShout.PlayOnRemove = true;
2432 newShout:Destroy();
2433 end
2434 end
2435 BattleInfo.Waffle = false;
2436 wait();
2437 end)
2438 end
2439 Battle:createPersona(BattleInfo.Waffle == true)
2440 end)
2441 ----
2442 for i, v in pairs(Battle.Characters[BattleInfo.SelectedMember].Persona.Attacks) do
2443 v = getAttack(v)
2444 if (v) then
2445 if (tostring(i):match('%a')) then
2446 --where the heck was I going with this?
2447 else
2448 local C = PlayerGui["Persona Attacks List"].ExampleObject:Clone();
2449 C.Name = i;
2450 C.BorderSizePixel = 0;
2451 if (C.Frame:FindFirstChild(v.Type)) then
2452 C.Frame[v.Type].Visible = true
2453 end
2454 C.AttackTitle.Text = v.Name;
2455 if (v.HPRequired) then
2456 C.HP.Visible = true;
2457 C.SP.Visible = false;
2458 C.HP.Text = tostring(modifyDamage(v.HPRequired, Battle.Characters[BattleInfo.SelectedMember].MaxHealth)).. 'HP'
2459 elseif (v.SPRequired) then
2460 C.HP.Visible = false;
2461 C.SP.Visible = true;
2462 C.SP.Text = tostring(v.SPRequired).. 'SP'
2463 end
2464
2465 for i, x in pairs(Battle.Enemies) do
2466 if (x.Weak) and x.Weak[v.Type] and x.Health > 0 then
2467 C.WeakBack.Visible = true;
2468 C.WeakFront.Visible = true
2469 end
2470 end
2471 C.Parent = PlayerGui["Persona Attacks List"].List.Frame;
2472 C.Button.Text = ''
2473
2474 C.Visible = true; end
2475 end
2476 end
2477 for i, v in pairs(PlayerGui['Persona Attacks List'].List.Frame:GetChildren()) do
2478 if (v:IsA('Frame')) then
2479 v.Button.Selected = true;
2480 game:GetService('GuiService').SelectedObject = v.Button;
2481 break;
2482 end
2483 end
2484 else
2485
2486 end
2487end
2488
2489--function Battle:EndBattle()
2490-- self.Music:Stop();
2491-- self.Music = ReplicatedStorage.Music['Persona 5 - Victory (Victory)'];
2492-- self.Music.Looped = true;
2493-- self.Music:Play();
2494-- PlayerGui.YouWinAnimation.Enabled = true;
2495-- local stuff = {};
2496-- for i, v in pairs(PlayerGui.YouWinAnimation:GetChildren()) do
2497-- stuff[v] = v.Position;
2498-- end
2499-- local e = 0;
2500-- for i,v in pairs(self.Enemies) do
2501-- e = e + v.Level;
2502-- end
2503-- e = math.ceil(e/#self.Enemies);
2504-- local c = 1;
2505---- for i, v in pairs(self.Characters) do
2506---- c = c + v.Level;
2507---- end
2508-- c = math.ceil(e/#self.Characters)
2509-- local EXPGained = math.ceil((e/c)*3.5*((e+c)*math.random(2, 3)));--*math.clamp(math.random(), 1, 1.3)));
2510-- EXPGained = EXPGained*DifficultyModifiers[self.Difficulty].Experience
2511-- local SP = {}--script.Parent:WaitForChild('YouWinAnimation');
2512-- local XYZ = PlayerGui.YouWinAnimation
2513-- for i, v in pairs(PlayerGui.YouWinAnimation:GetChildren()) do
2514-- SP[v.Name] = setmetatable({}, {__index = v;});
2515-- local x = SP[v.Name]
2516-- function x:TweenPosition(a,b,c,d, dir, style, num, override)
2517-- return v:TweenPosition(UDim2.new(a,b,c,d), dir, style, num or 1, override)
2518-- end
2519-- SP[v.Name].__newindex = function(self, i, y) v[i] = y; end;
2520-- end
2521-- --[[
2522-- Merciless={
2523-- DamageRecieved=1.6;
2524-- DamageDealt=0.8;
2525-- Experience=0.4;
2526-- Money=0.4;
2527-- };
2528-- --]]
2529-- SP.XPLabel:TweenPosition(-0.09, 0, 0.114, -3, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2530-- SP.XPFrame:TweenPosition(-0.048, 0, 0.099, -0, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2531-- SP.XPNumber:TweenPosition(0.127,0,0.124,-8, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true);
2532-- XYZ.XPNumber.Text = safetyZero(0, EXPGained)
2533-- spawn(function(y)
2534-- wait(1)
2535-- for i = 0, EXPGained, EXPGained/10 do
2536-- wait()
2537-- XYZ.XPNumber.Text = safetyZero(math.ceil(i), EXPGained);
2538-- end;
2539-- end)
2540--
2541-- game:GetService('UserInputService').InputBegan:Wait();
2542-- SP.MoneyFrame:TweenPosition(-0.012, 0, 0.297, 0, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2543-- SP.YenSign:TweenPosition(-0.848, 0, 0.279, -3, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2544-- SP.MoneyLabel:TweenPosition(0.058, 0, 0.334, 3, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true);
2545-- SP.MoneyNumber:TweenPosition(0.303, 0, 0.307, -8, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2546-- --
2547-- local Money = 0;
2548-- Money = math.ceil(((EXPGained/math.random(3, 5))*DifficultyModifiers[self.Difficulty].Money)*math.clamp(math.random(), 0.5, 1)) + (Battle.MoneyNet or 0)
2549-- --MoneyPlaceholder = MoneyPlaceholder + Money;
2550--
2551--
2552-- XYZ.MoneyNumber.Text = safetyZero(0, Money)
2553-- spawn(function(x)
2554-- wait(1)
2555-- for i = 0, Money, Money/10 do
2556-- wait()
2557-- XYZ.MoneyNumber.Text = safetyZero(math.ceil(i), Money);
2558-- end;
2559-- end)
2560-- game:GetService('UserInputService').InputBegan:Wait();
2561-- if (self.ItemsGained) then
2562-- SP.ItemFrame:TweenPosition(-0.012, 0, 0.496, 0, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2563-- SP.ItemLabel:TweenPosition(0.092, 0, 0.507, -3, Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2564-- end
2565-- local al = false;
2566-- local level = false;
2567-- for i, v in pairs(self.Characters) do
2568-- local EXPToLevelUp = v.Level^2*3;
2569-- local NowExperience = v.EXP + (EXPGained/#self.Characters);
2570-- v.EXP = NowExperience;
2571-- local levelUp = false;
2572-- for i = v.Level, math.huge, 1 do
2573-- game:GetService('RunService').RenderStepped:Wait();
2574-- if (v.EXP >= EXPToLevelUp) then
2575-- --
2576-- level = true;
2577-- levelUp = true;
2578-- v.Level = v.Level+1;
2579-- EXPToLevelUp = v.Level^2*5;
2580-- local MXH = v.MaxHealth;
2581-- local L = (v.Level^1.35)
2582-- v.MaxHealth = math.ceil(100+L);
2583-- v.MaxSP = math.ceil(v.Level*2.5 + 77.5 + 4)
2584-- else
2585-- v.EXP = v.EXP
2586-- break;
2587-- end
2588-- end
2589-- local newLevel = v.Level;
2590-- if (levelUp) then
2591-- if (level and not al) then
2592-- al = true;
2593-- PlayerGui.YouWinAnimation.RankUpFrame:TweenPosition(UDim2.new(0.665,0,0.115,0), Enum.EasingDirection.Out, Enum.EasingStyle.Back, 1, true)
2594-- end
2595-- local ecks = PlayerGui.YouWinAnimation.RankUpFrame.ScrollingFrame.itemObjectThing:Clone();
2596-- ecks.Parent = PlayerGui.YouWinAnimation.RankUpFrame.ScrollingFrame;
2597-- ecks.Name = 'LevelUp'
2598-- ecks.Visible = true;
2599-- ecks.TextLabel.Text = (v.LastName or '')..' '..(v.Name or 'Akira')..' '..' ('..v.Level..')';
2600-- game:GetService('UserInputService').InputBegan:Wait();
2601-- end
2602-- end
2603--
2604-- al = false;
2605-- local y = PlayerGui.YouWinAnimation.RankUpFrame.ScrollingFrame.UIListLayout:Clone();
2606-- wait();
2607-- PlayerGui.YouWinAnimation.RankUpFrame.ScrollingFrame.CanvasPosition = Vector2.new(0,0)
2608-- y.Parent = PlayerGui.YouWinAnimation.RankUpFrame.ScrollingFrame;
2609--
2610-- for i, v in pairs(PlayerGui.YouWinAnimation:GetChildren()) do
2611-- if (v.Name ~= 'Background') then
2612-- if (v.Name ~= 'RankUpFrame') then
2613-- v.Position = UDim2.new(v.Position.X.Scale-1, v.Position.X.Offset, v.Position.Y.Scale, v.Position.Y.Offset)
2614-- else
2615-- v.Position = UDim2.new(v.Position.X.Scale+1, v.Position.X.Offset, v.Position.Y.Scale, v.Position.Y.Offset)
2616-- end
2617-- end
2618-- end
2619-- workspace["Enemy Container"]:Destroy();
2620-- workspace["Party Container"]:Destroy();
2621-- for i, v in pairs(stuff) do
2622-- i.Position = v;
2623-- end
2624--
2625-- for i, v in pairs(PlayerGui.YouWinAnimation.RankUpFrame.ScrollingFrame:GetChildren()) do
2626-- if v:IsA('Frame') and v.Name ~= "itemObjectThing" then
2627-- v:Destroy();
2628-- end
2629-- end
2630--
2631-- for i, v in pairs(PlayerGui.YouWinAnimation.ItemFrame.ScrollingFrame:GetChildren()) do
2632-- if v:IsA('Frame') and v.Name ~= "itemObjectThing" then
2633-- v:Destroy();
2634-- end
2635-- end
2636--
2637-- for i, v in pairs(game.Lighting:GetChildren()) do
2638-- if v.ClassName:match('Effect') then
2639-- v.Enabled = false
2640-- end
2641-- end
2642--
2643-- PlayerGui.YouWinAnimation.Enabled = false;
2644--
2645--
2646-- --reset camerae by deleting it
2647-- workspace.CurrentCamera:Destroy();
2648-- wait(.1)
2649-- workspace.CurrentCamera.CameraType = Enum.CameraType.Custom;
2650-- workspace.CurrentCamera.CameraSubject = game.Players.LocalPlayer.Character.Humanoid;
2651-- --
2652-- workspace.CurrentCamera.CameraType = Enum.CameraType.Custom;
2653-- self.Music:Stop();
2654-- _G.Occupied = false;
2655-- self.BattleFinished = true;
2656-- BattleInfo.BattleStage = nil;
2657-- _G.Stage = nil;
2658-- local Sky = game:GetService('ReplicatedStorage'):FindFirstChild('TempSky');
2659-- local OSky = game:GetService('Lighting'):FindFirstChildWhichIsA('Sky');
2660--
2661-- if (Sky) then
2662-- if (OSky) then
2663-- OSky:Destroy();
2664-- end
2665-- Sky.Name = 'Sky';
2666-- Sky.Parent = game:GetService('Lighting');
2667-- end
2668-- for i, v in pairs(game:GetService('Lighting'):GetChildren()) do
2669-- if (v.Name == 'Palace' and v:IsA('PostEffect')) then
2670-- v.Enabled = true
2671-- end
2672-- end
2673-- return true;
2674--end
2675
2676function Battle:EndBattle()
2677 self.Music:Stop();
2678 self.Music = ReplicatedStorage.Music['Persona 5 - Victory (Victory)'];
2679 self.Music.Looped = true;
2680 self.Music:Play();
2681 local function Shorten(group)
2682 local Things = {};
2683 for i, v in pairs(group:GetChildren()) do
2684 if (tonumber(v.Name)) then
2685 Things[tonumber(v.Name)] = {v, v.Size};
2686 wait();
2687 v.Size = UDim2.new(0,0,v.Size.Y.Scale,v.Size.Y.Offset)
2688 end
2689 end
2690 return Things;
2691 end
2692 local newWinAnimationObject = PlayerGui:WaitForChild('YouWinAnimation')
2693 newWinAnimationObject = newWinAnimationObject:Clone();
2694 newWinAnimationObject.Parent = PlayerGui;
2695 local GuiOne = newWinAnimationObject:WaitForChild'PhaseOne';
2696 local GuiTwo = newWinAnimationObject:WaitForChild'PhaseTwo';
2697 local SetOne = Shorten(GuiOne);
2698 local SetTwo = Shorten(GuiTwo);
2699 for i, v in pairs(GuiOne:GetChildren()) do
2700 pcall(function()
2701 if (not tonumber(v.Name)) then
2702 v.Position = v.Position + UDim2.new(1)
2703 end
2704 end)
2705 end
2706 for i, v in pairs(GuiTwo:GetChildren()) do
2707 pcall(function()
2708 if (not tonumber(v.Name)) then
2709 v.Position = v.Position + UDim2.new(-1)
2710 end
2711 end)
2712 end
2713 newWinAnimationObject.Enabled = true;
2714 local UserInputService = game:GetService('UserInputService');
2715 local e = 0;
2716 for i,v in pairs(self.Enemies) do
2717 e = e + v.Level;
2718 end
2719 e = math.ceil(e/#self.Enemies);
2720 local c = 1;
2721 for i, v in pairs(self.Characters) do
2722 c = c + v.Level;
2723 end
2724 c = math.ceil(e/#self.Characters)
2725 local EXPGained = math.ceil((e/c)*3.5*((e+c)*math.random(2, 3)));--*math.clamp(math.random(), 1, 1.3)));
2726 EXPGained = EXPGained*DifficultyModifiers[self.Difficulty].Experience
2727 local Money = math.ceil(((EXPGained/math.random(3, 5))*DifficultyModifiers[self.Difficulty].Money)*math.clamp(math.random(), 0.5, 1)) + (Battle.MoneyNet or 0)
2728
2729 local function numWithCommas(amount)
2730 local formatted = amount
2731 while true do
2732 game:GetService('RunService').RenderStepped:Wait();
2733 formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
2734 if (k==0) then
2735 break
2736 end
2737 k=nil;
2738 end
2739 return formatted
2740 end
2741 local function Odometize(stringObject, value, addend)
2742 local stringValue = tostring(stringObject.Text):gsub('%D', '');
2743 local oldValue = tonumber(stringValue) or 0;
2744 --stringObject = numWithCommas(tonumber(stringObject))
2745 local currentValue = oldValue;
2746 -- script.Parent.Money.Value = script.Parent.Money.Value + (math.sign(Difference) == 1 and math.ceil or math.floor)(math.sign(Difference) * (math.sign(Difference)*Difference/20))
2747 while game:GetService('RunService').RenderStepped:Wait() do
2748 local Difference = value - oldValue;
2749 oldValue = oldValue + (math.sign(Difference) == 1 and math.ceil or math.floor)(math.sign(Difference) * (math.sign(Difference)*Difference/10))--20
2750 if (math.floor(oldValue) == math.floor(value)) then
2751 print'Broken!';
2752 break;
2753 end
2754 stringObject.Text = (addend or '')..numWithCommas(oldValue);
2755 end
2756 end
2757 for i, v in pairs(SetOne) do
2758 v[1]:TweenSize(v[2], Enum.EasingDirection.InOut, Enum.EasingStyle.Linear, 0.05);
2759 wait(0.025)
2760 end
2761 for i, v in pairs(GuiOne:GetChildren()) do
2762 pcall(function()
2763 if (not tonumber(v.Name)) then
2764 v:TweenPosition(v.Position - UDim2.new(1), Enum.EasingDirection.Out, Enum.EasingStyle.Back, 0.25)
2765 wait(0.15)
2766 end
2767 end)
2768 end
2769 GuiOne:TweenPosition(GuiOne.Position+UDim2.new(0.025,0,0,0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 5, false)
2770 spawn(function()--{0.23, 0},{0, 0}
2771 Odometize(newWinAnimationObject.PhaseOne.ExpCount, EXPGained)
2772 end)
2773 repeat until UserInputService.InputBegan:Wait().KeyCode == Enum.KeyCode.Return;
2774 GuiTwo:TweenPosition(UDim2.new(0,0,0,0), Enum.EasingDirection.InOut, Enum.EasingStyle.Linear, 1, false)
2775 GuiOne:TweenPosition(UDim2.new(1,0,0,0), Enum.EasingDirection.InOut, Enum.EasingStyle.Linear, 1, true)
2776 wait(0.9)
2777 for i, v in pairs(SetTwo) do
2778 v[1]:TweenSize(v[2], Enum.EasingDirection.InOut, Enum.EasingStyle.Linear, 0.05);
2779 wait(0.025)
2780 end
2781 for i, v in pairs(GuiTwo:GetChildren()) do
2782 pcall(function()
2783 if (not tonumber(v.Name)) then
2784 v:TweenPosition(v.Position + UDim2.new(1), Enum.EasingDirection.Out, Enum.EasingStyle.Back, 0.25)
2785 wait(0.15);
2786 end
2787 end)--{0.018, 0},{0.003, 0}
2788 end
2789 GuiTwo:TweenPosition(GuiTwo.Position+UDim2.new(0.05,0,0,0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 5, true)
2790 GuiOne:TweenPosition(GuiOne.Position+UDim2.new(0.05,0,0,0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 5, true)
2791 spawn(function()
2792 Odometize(GuiTwo.MoneyCounter, Money, '¥')
2793 end)
2794 repeat until UserInputService.InputBegan:Wait().KeyCode == Enum.KeyCode.Return;
2795 workspace["Enemy Container"]:Destroy();
2796 workspace["Party Container"]:Destroy();
2797
2798 newWinAnimationObject:Destroy();
2799
2800 --reset camerae by deleting it
2801 workspace.CurrentCamera:Destroy();
2802 wait(.1)
2803 workspace.CurrentCamera.CameraType = Enum.CameraType.Custom;
2804 workspace.CurrentCamera.CameraSubject = game.Players.LocalPlayer.Character.Humanoid;
2805 --
2806 workspace.CurrentCamera.CameraType = Enum.CameraType.Custom;
2807 self.Music:Stop();
2808 _G.Occupied = false;
2809 self.BattleFinished = true;
2810 BattleInfo.BattleStage = nil;
2811 _G.Stage = nil;
2812 self.OneMore = false;
2813 local Sky = game:GetService('ReplicatedStorage'):FindFirstChild('TempSky');
2814 local OSky = game:GetService('Lighting'):FindFirstChildWhichIsA('Sky');
2815
2816 if (Sky) then
2817 if (OSky) then
2818 OSky:Destroy();
2819 end
2820 Sky.Name = 'Sky';
2821 Sky.Parent = game:GetService('Lighting');
2822 end
2823 for i, v in pairs(game:GetService('Lighting'):GetChildren()) do
2824 if (v.Name == 'Scene' and v:IsA('PostEffect')) then
2825 v.Enabled = true
2826 end
2827 if (v.Name == 'BattleEffect') then
2828 v:Destroy();
2829 end
2830 end
2831 --PlayerGui.Reticle.Enabled = false;
2832 PlayerGui.Reticle.Adornee = nil
2833 return true;
2834end
2835
2836
2837function showLabel(text, duration)
2838 text = text or '???'
2839 duration = duration or 1
2840 local Label = PlayerGui.Statuses.Frame:Clone();
2841 Label.Name = "CopiedStatusEffect"
2842 Label.Parent = PlayerGui.Statuses;
2843 Label.Frame.TextLabel.Text = text
2844 for i = 1, 0, -0.1 do
2845 Label.BackgroundTransparency = i;
2846 game:GetService('RunService').RenderStepped:Wait();
2847 end
2848 wait(duration)
2849 for i = 0, 1, 0.1 do
2850 Label.BackgroundTransparency = i;
2851 game:GetService('RunService').RenderStepped:Wait();
2852 end
2853end
2854function Battle:showLabel(text, duration)
2855 showLabel(text, duration)
2856end
2857function Battle.new(party, enemies, ambush, difficulty, ba, music, boss)
2858 _G.Occupied = true;
2859 CurrentCameraShake = CameraShaker.new(Enum.RenderPriority.Camera.Value+1, function(shakeOffset)
2860 workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * shakeOffset;
2861 end)
2862 wait();
2863 coroutine.wrap(function()
2864 CurrentCameraShake:Start();
2865 CurrentCameraShake:ShakeSustain(CameraShaker.Presets.HandheldCamera);
2866 end)();
2867 _G.StartLoad(true)
2868 CMS:Disable()
2869 game.Players.LocalPlayer.Character.PrimaryPart.Anchored = true;
2870 EnemyAPI:Initialize() --start the enemy api
2871 for i, v in pairs(Battle) do
2872 print(i, v)
2873 end
2874
2875 local battleArea = ba:Clone()
2876 battleArea.Name = "Arena";
2877 battleArea:SetPrimaryPartCFrame(CFrame.new(0,2500,0))
2878 for i, v in pairs(game:GetService('Lighting'):GetChildren()) do
2879 if (v.Name ~= 'e' and v:IsA('PostEffect')) then
2880 v.Enabled = false
2881 end
2882 end
2883 if (battleArea:FindFirstChild('Lighting')) then
2884
2885 --preserve old lighting properties
2886
2887 local PreLighting = Instance.new('Folder', game:GetService'ReplicatedStorage');
2888 PreLighting.Name = "Previous Lighting";
2889 for i, v in pairs(battleArea.Lighting:GetChildren()) do
2890 if (v:IsA('PostEffect') and v.Name ~= 'e') then
2891 v.Enabled = false;
2892 end
2893 local NewValue = Instance.new(v.ClassName, PreLighting);
2894 local success, info = pcall(function() --put it in a protected call so any invalid properties won't break the script
2895 NewValue.Name = v.Name;
2896 NewValue.Value = game:GetService('Lighting')[v.Name];
2897 end)
2898 if (not success) then --remove the lingering variable and continue
2899 NewValue:Destroy();
2900 else
2901 warn('Setting Lighting value of', v.Name, 'to', v.Value);
2902 game:GetService('Lighting')[v.Name] = v.Value;
2903 end
2904 end
2905
2906
2907 --begin tweening properties
2908
2909
2910 end
2911 battleArea.Parent = workspace;
2912
2913
2914 local self = Battle;
2915 self.OneMore = false;
2916 BattleInfo = { --Independant turns for every character.
2917 EnemyTurns = {}; --one for the enemies
2918 PlayerTurns = {}; --one for the player. this allows for rakukaja to turn on/off not when it's Akira's turn
2919 EnemyActions = {};
2920
2921 MemberActions = {};
2922 MemberAnimations = {};
2923 SelectedPersonaAttack = nil;
2924
2925 BattleStage = 'Main'; --using general identifiers for battlestage
2926 SelectedMember = 0; --Default to 0 so we can know this is the start of the battle.
2927 }
2928
2929 self.BattleFinished = false;
2930 self.PositionBeforeBattle = Character:GetPrimaryPartCFrame();
2931 --set camera type to scriptable so we can manipulate the camera with ease
2932 workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable;
2933
2934 --defining self properties for easier access
2935 self.Difficulty = difficulty;
2936 self.Characters = party;
2937 for i, v in pairs(self.Characters) do
2938 v.Debuffs = {};
2939 v.Guard = false;
2940 end
2941 Metatable(self.Characters) --give party memberds a metatable
2942 self.Ambush = ambush;
2943 self.Enemies = {};
2944 self.EnemiesString = enemies;
2945
2946 local Keyword = ambush and 'Ambush Spawns' or 'Spawns'
2947 local Spawns = battleArea:WaitForChild(Keyword)
2948 for i, v in pairs(enemies) do
2949 if (not boss and i > #Spawns['Enemy Spawns']:GetChildren()) then
2950 break; --so overloading doesnt happen
2951 end
2952 self.Enemies[i] = getPersonaFromString(v) --convert all personas to actual tables so we can use them in battle
2953
2954
2955 self.Enemies[i].MaxHealth = v.Health; --set maxhealth property before they even spawn for ezpz work
2956
2957 wait()
2958 end
2959
2960 Metatable(self.Enemies) --give enemy members a metatable;
2961 for i, v in pairs(self.Characters) do
2962 v.Enemies = {};
2963 end
2964 self.BattleArea = battleArea;
2965 if (self.Ambush) then
2966 self:AmbushPosition();
2967 end
2968 if (self.BattleArea:FindFirstChild('Ambush Spawns')) then
2969 for i, v in next, self.BattleArea:FindFirstChild('Ambush Spawns'):GetDescendants() do
2970 if (v:IsA('BasePart')) then
2971 v.Transparency = 1;
2972 end
2973 end
2974 end
2975 if (self.BattleArea:FindFirstChild('Spawns')) then
2976 for i, v in next, self.BattleArea:FindFirstChild('Spawns'):GetDescendants() do
2977 if (v:IsA('BasePart')) then
2978 v.Transparency = 1;
2979 end
2980 end
2981 end
2982 if (self.BattleArea:FindFirstChildWhichIsA('Sky')) then
2983 local Sky = game:GetService('Lighting'):FindFirstChildWhichIsA("Sky");
2984 if (Sky) then
2985 Sky.Parent = game:GetService('ReplicatedStorage');
2986 Sky.Name = 'TempSky';
2987 end
2988 self.BattleArea:FindFirstChildWhichIsA('Sky'):Clone().Parent = game:GetService('Lighting');
2989 end
2990 self.BattleFolder = Spawns;
2991 self.PartySpawns = Spawns['Party Spawns']
2992 self.EnemySpawns = Spawns['Enemy Spawns']
2993 self.PartyContainer = workspace:FindFirstChild('Party Container') and workspace['Party Container']:ClearAllChildren() and workspace['Party Container'] or Instance.new('Folder')
2994 self.PartyContainer.Name = 'Party Container'
2995 self.PartyContainer.Parent = workspace;
2996
2997 --Begin moving the entire party to the battle area
2998
2999 for index, x in pairs(party) do
3000
3001 for i, v in pairs(ReplicatedStorage["Party Members"]:GetChildren()) do
3002 if (v.Name:lower():match(x.Name:lower())) and (x.InParty or index == 1) then --Allow case-insensitivity just to make sure I can cover my mistakes.
3003 local PartyMemberClone = v:Clone()
3004 PartyMemberClone:WaitForChild('Humanoid').HipHeight = recalculateHipHeight(PartyMemberClone);
3005 local SpawnCFrame = Spawns:WaitForChild('Party Spawns'):WaitForChild('Spawn'..index).CFrame + Vector3.new(0, math.abs(PartyMemberClone:WaitForChild("Humanoid").HipHeight), 0)
3006 PartyMemberClone.Parent = self.PartyContainer;
3007 PartyMemberClone.Humanoid:SetStateEnabled(Enum.HumanoidStateType.FallingDown, false)
3008 PartyMemberClone.Humanoid:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
3009 PartyMemberClone.Humanoid.WalkSpeed = Character.Humanoid.WalkSpeed;
3010 PartyMemberClone.PrimaryPart.Anchored = false;
3011 if (v:FindFirstChild('Animations')) then
3012-- for i, x in pairs(v.Animations:getChildren()) do
3013-- LoadAnimation(x, PartyMemberClone:WaitForChild('Humanoid')):Play();
3014-- end
3015
3016 if v.Animations:FindFirstChild("Idle") then
3017 LoadAnimation(v.Animations.Idle, PartyMemberClone:WaitForChild("Humanoid")):Play();
3018 end
3019 end
3020 PartyMemberClone:SetPrimaryPartCFrame(SpawnCFrame)
3021 end
3022 end
3023 end
3024
3025
3026 game.Players.LocalPlayer.Character.PrimaryPart.Velocity = Vector3.new();
3027 game.Players.LocalPlayer.Character:SetPrimaryPartCFrame(Spawns:WaitForChild('Party Spawns')['Spawn1'].CFrame + Vector3.new(0,game.Players.LocalPlayer.Character.Humanoid.HipHeight+.5,0)) --teleport the character to the first spawn
3028
3029
3030 if _G.Music then _G.Music:Pause() end;
3031 if (not music) then
3032 if (Keyword == 'Ambush Spawns') then
3033 self.Music = ReplicatedStorage.Music['Persona 5 - Willpower (Awakening)']
3034 else
3035 self.Music = ReplicatedStorage.Music["Persona 5 - Last Surprise (Ambush)"]
3036 end
3037 else
3038 self.Music = music;
3039 end;
3040
3041 --local sign = math.sign(self.Music.Volume - 0); local cond1 = (sign == 1 and 0 or self.Music.Volume); local cond2 = (sign == 1 and self.Music.Volume or 0); local cond3 = (sign == 1 and 0.1 or -0.1)
3042 local ms13 = 0.5;
3043 self.Music.Looped = true;
3044 self.Music.Volume = 0;
3045 self.Music:Play();
3046
3047 coroutine.wrap(function()
3048 for i = 0, ms13, ms13/10 do
3049 wait();
3050 --game:GetService('RunService').RenderStepped:Wait();
3051 print(i);
3052 self.Music.Volume = i;
3053 end
3054 end)();
3055 for i, v in pairs(game:GetService'Lighting':GetChildren()) do
3056 if v.Name:lower():match('dungeon') or v.Name:match('ambush') then
3057 if (self.Ambush and v.Name:lower():match('ambush')) then
3058 v.Enabled = true;
3059 elseif (not self.Ambush) and (not v.Name:lower():match('ambush') and v.Name:lower():match('dungeon')) then
3060 v.Enabled = true;
3061 else
3062 v.Enabled = false;
3063 end
3064 end
3065 end
3066
3067
3068 Signal = PlayerGui:WaitForChild("Persona Attacks List"):GetPropertyChangedSignal('Enabled'):Connect(function()
3069 RefreshPersonaList();
3070 end)
3071
3072 spawn(function()
3073 Battle:Failsafe()
3074 end)
3075 spawn(function(a)
3076 wait(2)
3077 game.Players.LocalPlayer.Character.PrimaryPart.Anchored = true;
3078 end)
3079 local EnemySpawns = Spawns:WaitForChild('Enemy Spawns')
3080 local EnemyContainer = workspace:FindFirstChild('Enemy Container') and workspace['Enemy Container']:ClearAllChildren() and workspace['Enemy Container'] or Instance.new('Folder')
3081 EnemyContainer.Name = 'Enemy Container'
3082 EnemyContainer.Parent = workspace;
3083 self.EnemyContainer = EnemyContainer;
3084 self.Boss = boss;
3085 local ChosenMember = Battle:selectViableMember(true);
3086 if (tonumber(ChosenMember)) then
3087 Battle:CharacterPosition(ChosenMember, nil, true);
3088 end
3089 for index, x in pairs(enemies) do
3090 if (not boss and index > #EnemySpawns:GetChildren()) then
3091 break; --prevent any infinite yields / errors
3092 end
3093 for i, v in pairs(ReplicatedStorage["Personas"]:GetChildren()) do
3094 if (v.Name:lower():match(x:lower())) then --enemies will be string values. their models will be taken from Persona List
3095 v = v:Clone();
3096 for i, v in pairs(v:GetDescendants()) do
3097 if v:IsA("BasePart") then
3098 local Trans = Instance.new('NumberValue', v);
3099 Trans.Value = v.Value;
3100 Trans.Name = 'OriginalTransparency';
3101
3102 v.Transparency = 1;
3103 end
3104 end
3105 local n = self.Enemies[index] and self.Enemies[index].CustomSize or {};
3106 local H = v:WaitForChild('Humanoid')
3107 H.BodyDepthScale.Value = n.Depth or 1.25;
3108 H.BodyHeightScale.Value = n.Height or 1.35;
3109 H.BodyProportionScale.Value = n.Proportions or 1.2;
3110 H.BodyTypeScale.Value = n.Type or 1.75;
3111 H.BodyWidthScale.Value = n.Width or 1.2;
3112 H.HeadScale.Value = n.Head or 1.3;
3113 wait()
3114 H.HipHeight = recalculateHipHeight(H.Parent);
3115 spawn(function(a)
3116 wait(1.5)
3117 v.PrimaryPart.Anchored = true;
3118 end)
3119 local Indicator = Instance.new('StringValue', v)
3120 Indicator.Name = 'PersonaName'
3121 Indicator.Value = v.Name;
3122 v.Name = index
3123 v.Parent = EnemyContainer;
3124 --v:WaitForChild('Humanoid').HipHeight = 2.462;
3125 local Selector = not boss and Spawns:WaitForChild('Enemy Spawns'):WaitForChild('Spawn'..index) or battleArea:WaitForChild('BossSpawn')
3126 v:SetPrimaryPartCFrame(Selector.CFrame + Vector3.new(0,v.Humanoid.HipHeight + Selector.Size.Y/2, 0))
3127 spawn(function()
3128 local Sp = ReplicatedStorage.EffectStorage.Spawn:Clone();
3129 Sp.Parent = workspace;
3130 Sp:SetPrimaryPartCFrame(v:GetPrimaryPartCFrame() + Vector3.new(0,0,2.5));
3131 for i, v in pairs(Sp:GetDescendants()) do
3132
3133 if (v:IsA('ParticleEmitter')) then
3134 v:Emit(150)
3135
3136 end
3137 end
3138 ReplicatedStorage.EffectStorage.Sounds.EnemySpawn:Play();
3139 wait(.4);
3140 for i, v in pairs(v:GetDescendants()) do
3141 if v:IsA("BasePart") and v.Name:lower() ~= 'humanoidrootpart' then
3142 if v:findFirstChild('OriginalTransparency') then
3143 Tween(v, TweenInfo.new(.1), {Transparency = v.OriginalTransparency.Value}):Play();
3144 end
3145 end
3146 end
3147 end)
3148 game:GetService('RunService').RenderStepped:Wait() --prevent any bad things
3149 wait(1/#enemies)
3150 end
3151 end
3152 end
3153 _G.EndLoad()
3154 return Battle:NewTurn() --call the battle's new turn function
3155end
3156ospawn = spawn;
3157spawn = function(f, ...)
3158 local a = {...};
3159 return ospawn(function()
3160 f(unpack(a))
3161 end)
3162end
3163function Effect(e, t, attack, targetIsEnemy, isEnemy, why, self, ia)
3164 --target, attack used, is target enemy?, (if t is enemy) target character's id, Battle (self), IgnoreAnimation
3165 --if (targetIsEnemy) then
3166 print(e, t)
3167 for i, v in pairs(attack) do
3168 print(i, v)
3169 end
3170 if (attack.Effect) then
3171 --badeffect
3172
3173 if (isEnemy) then
3174 --local Char = self:GetCharacterFromID(BattleInfo.SelectedEnemyGuy);
3175 if (why) then
3176
3177 local Char = self:GetCharacterFromID(why);
3178 if (typeof(attack.Effect) == 'function') then
3179 --Accepts a table with the following args: {PrimaryPart, IgnoreAnimation, TargetPart};
3180 Effects[attack.Effect]({PrimaryPart = Char.PrimaryPart,
3181 IgnoreAnimation = ia,
3182 TargetPart = Battle:GetEnemyFromName(e.ID).PrimaryPart,
3183 TargetFolder = self.PartyContainer,
3184 EnemySpawn = self.PartySpawns}, Battle)
3185 elseif Effects[attack.Effect] then
3186 Effects[attack.Effect]({PrimaryPart = Char.PrimaryPart,
3187 IgnoreAnimation = ia,
3188 TargetPart = Battle:GetEnemyFromName(e.ID).PrimaryPart,
3189 EnemySpawn = self.PartySpawns,
3190 TargetFolder = self.PartyContainer
3191 }, Battle)
3192 end
3193 end
3194 else
3195 local Char = self.EnemyContainer:FindFirstChild(t.ID)
3196 local Me = Battle:GetCharacterFromID(e.Name)
3197 if (Char and Me) then
3198
3199 if (typeof(attack.Effect) == 'function') then
3200 Attacks[attack.Effect]({PrimaryPart = Char.PrimaryPart,
3201 IgnoreAnimation = ia,
3202 TargetPart = Me.PrimaryPart,
3203 EnemySpawn = self.EnemySpawns
3204 }, Battle)
3205 elseif Effects[attack.Effect] then
3206 Effects[attack.Effect]({PrimaryPart = Char.PrimaryPart, --enemy's part
3207 IgnoreAnimation = ia, --ignore animation?
3208 TargetPart = Me.PrimaryPart, --my primary part
3209 TargetFolder = self.EnemyContainer, --enemy's folder? WHAT
3210 EnemySpawn = self.EnemySpawns
3211 }, Battle)
3212 end
3213 else
3214 warn('Me: ', Me);
3215 end
3216 end
3217 elseif (Effects[attack.Type..'Effect']) then
3218
3219 if (isEnemy) then
3220 if (why) then
3221
3222 local Char = self:GetCharacterFromID(why);
3223 Effects[attack.Type..'Effect'](
3224 {PrimaryPart = Char.PrimaryPart,
3225 IgnoreAnimation = ia, TargetPart =
3226 Battle:GetEnemyFromName(e.ID).PrimaryPart,
3227 TargetFolder = self.PartyContainer,
3228 EnemySpawn = self.PartySpawns
3229 }, Battle)
3230 end
3231 else
3232 local Char = self.EnemyContainer:WaitForChild(t.ID)
3233 local Me = Battle:GetCharacterFromID(e.Name)
3234 if (Char and Me) then
3235 Effects[attack.Type..'Effect']({
3236 PrimaryPart = Char.PrimaryPart,
3237 IgnoreAnimation = ia,
3238 TargetPart = Me.PrimaryPart,
3239 TargetFolder = self.PartyContainer,
3240 EnemySpawn = self.EnemySpawns
3241 }, Battle)
3242 else
3243 warn('Char:', Char, 'Me:', Me)
3244 end
3245 end
3246 end
3247 --end
3248end
3249local BigAttackHappening = false;
3250
3251function Battle:Damage(attacker, target, attack, silent)
3252 local DownExclusionBecauseScrewThisStupidCodebase = nil;
3253 local Yield = attack.Yield
3254 local isEnemy = (not attacker.Persona and true) or false;
3255 local targetIsEnemy = (not target.Persona) or false
3256 local isHeal = attack.Type:lower() == "buff" or attack.Type:lower() == "kaja"
3257 local isMultiHit = attack.Damages or attack.Heals;
3258 local PositionOfCharacterAttacked;
3259 for i, v in pairs(self.Characters) do
3260 if (v.Name == (isEnemy and target.Name or attacker.Name)) then
3261 PositionOfCharacterAttacked = i;
3262 end
3263 end
3264
3265 if (not silent) then
3266 coroutine.wrap(function()
3267 showLabel(attack.Name, 1.5)
3268 end)();
3269 end
3270 target.Debuffs = target.Debuffs or {};
3271 attacker.Debuffs = attacker.Debuffs or {};
3272 local AttackerDebuffTable = attacker and attacker.Debuffs;
3273 local TargetDebuffTable = target and target.Debuffs;
3274 if (attack.SPRequired) then
3275 attacker:SubtractSP(attack.SPRequired)
3276 elseif (attack.HPRequired) then
3277 attacker:SubtractHealth(modifyDamage(attack.HPRequired, attacker.MaxHealth))
3278 end
3279 local toggleOneMore;
3280 local HealingTarget = isEnemy and self.Enemies or self.Characters;
3281 if (isHeal) then
3282 if (attack.CustomMessage) then
3283 coroutine.wrap(showLabel)(attack.CustomMessage, 2.5);
3284 end
3285 if (isMultiHit) then
3286 for i, target in pairs(HealingTarget) do
3287 if (isEnemy) then
3288 Battle:MoveCameraToEnemy(i, {yield = true})
3289 else
3290 Battle:MoveCameraToCharacter(i, {yield = true})
3291 end
3292-- for i, v in pairs(attack.Debuffs or {}) do
3293-- local x = {};
3294-- for i, v in pairs(v) do
3295-- x[i] = v;
3296-- end
3297-- BattleInfo.PlayerTurns[PositionOfCharacterAttacked] = BattleInfo.PlayerTurns[PositionOfCharacterAttacked] or 1;
3298-- x.TurnAdded = isEnemy and BattleInfo.PlayerTurns[PositionOfCharacterAttacked] or BattleInfo.EnemyTurns[target.ID];
3299-- target:AddDebuff(x)
3300-- end
3301 if (attack.Type2 == 'Revive' or target.Health > 0) then target:Heal(attack.Heal) end
3302 end
3303 else
3304 if (attack.CustomMessage) then
3305 coroutine.wrap(showLabel)(attack.CustomMessage, 2.5);
3306 end
3307-- for i, v in pairs(attack.Debuffs or {}) do
3308-- local x = {};
3309-- for i, v in pairs(v) do
3310-- x[i] = v;
3311-- end
3312-- BattleInfo.PlayerTurns[PositionOfCharacterAttacked] = BattleInfo.PlayerTurns[PositionOfCharacterAttacked] or 1;
3313-- x.TurnAdded = isEnemy and BattleInfo.PlayerTurns[PositionOfCharacterAttacked] or BattleInfo.EnemyTurns[target.ID];
3314-- target:AddDebuff(x)
3315-- end
3316 if (isEnemy) then
3317 Battle:MoveCameraToEnemy(target.ID, {yield = true})
3318 if (attack.Type2 == 'Revive' or target.Health > 0) then target:Heal(attack.Heal) end
3319 else
3320 Battle:MoveCameraToCharacter(PositionOfCharacterAttacked, {yield = true})
3321 if (attack.Type2 == 'Revive' or target.Health > 0) then self.Characters[BattleInfo.SelectedEnemyGuy]:Heal(attack.Heal) end
3322 end
3323 end
3324 return 0; --finish the turn and healing.
3325 end
3326 if (attack.SelfHeal) then
3327 attacker:Heal(attack.SelfHeal);
3328 end
3329 if (attack.SPRecovered or attack.AddSP) then
3330 attacker:AddSP(attack.SPRecovered or attack.AddSP)
3331 end
3332
3333 --Temporary Stats and Flags for Attacking
3334
3335 local Evasion = 0;
3336 local Technical = false;
3337 local Hunger = false;
3338 local Def = 1;
3339 local Atk = 1;
3340
3341 local a;
3342 --local d = (e.Equipped and not isEnemy) and (t.Equipped.Accessory.Defense or 0) or t.Defense or 85;
3343
3344
3345 local d = 0;
3346
3347 if (target.Equipped and target.Equipped.Defense) then
3348 local EquippedDefense = Items[target.Equipped.Defense];
3349 d = EquippedDefense.Defense or 0;
3350 end
3351
3352 d = d+ ((isEnemy and target.Persona.Stats.Endurance or target.EnemyStats.Endurance or 0)*1.25)
3353 d = d * Def
3354
3355
3356
3357 local l = attacker.Level; --note: later down the line, we will be relying on persona stats and not level-based damage.
3358
3359 if (not attack.Type:lower() == "physical") then
3360
3361 if (isEnemy) then
3362 a = (attacker.EnemyStats or attacker.Stats).Magic+(attack.Damage)
3363 else
3364 a = attacker.Persona.Stats.Magic*1.25+attack.Damage*1.45
3365 a = a+(attack.Damage or 0)
3366 end
3367
3368 else --if it IS physical
3369 --note: don't use a strict system, rely on strings so modifying data post-release will be easier (FINISHED)
3370 local AttackerEquipped = attacker.Equipped and Items[attacker.Equipped.Melee]
3371 if isEnemy == false and (AttackerEquipped and AttackerEquipped.Damage) then
3372 a = attacker.Persona.Stats.Strength*1.25+(AttackerEquipped.Damage)
3373 elseif (isEnemy) then
3374 a = (attacker.EnemyStats or attacker.Stats).Strength*1.25+(attacker.EnemyStats or attacker.Stats).Strength*1.45
3375 else
3376 a = attacker.Persona.Stats.Strength*1.25 + attack.Damage*1.25
3377 end
3378 end
3379
3380
3381 local Weak = target.Weak or (target.Persona and target.Persona.Weak or nil) or {}
3382 local Strong = target.Strong or (target.Persona and target.Persona.Strong or nil) or {}
3383 local WeakVar = Weak[attack.Type];
3384 local StrongVar = Strong[attack.Type];
3385
3386 --
3387 if (target and target.Equipped and Items[target.Equipped.Defense]) then
3388 local ec = Items[target.Equipped.Defense]
3389 if ec.Evasion then
3390 Evasion = Evasion - ec.Evasion; --subtract the evasion from the thing --45
3391 end
3392 end
3393
3394 if (attacker and attacker.Equipped and Items[attacker.Equipped.Defense]) then
3395 local ec = Items[attacker.Equipped.Defense] --incase brainwash is in effect
3396 if (ec.Evasion) then
3397 Evasion = Evasion + ec.Evasion
3398 end
3399 end
3400
3401 if (attacker and attacker.Debuffs and attacker.Debuffs.EvasionUp) then
3402 Evasion = Evasion + 30;
3403 elseif (attacker and attacker.Debuffs and attacker.Debuffs.EvasionDown) then
3404 Evasion = Evasion - 30; --70
3405 end --get the attacker's evasion
3406
3407
3408 --add or subtract evasion points for attacker/defender benefit
3409 Evasion = Evasion - ((not target.Persona and target.EnemyStats) or target.Persona.Stats or {}).Agility or 0;
3410 Evasion = Evasion + ((not attacker.Persona and attacker.EnemyStats) or attacker.Persona.Stats or {}).Agility or 0;
3411 Evasion = math.abs(Evasion);
3412
3413 local Divisor = 300; --divide the Evasion value by Divisor.
3414
3415 local GroupToAttack, Type = (targetIsEnemy and self.Enemies) or self.Characters, (targetIsEnemy and "Enemies") or "Characters"
3416
3417 --Stat Modification
3418 if (attacker and attacker.Debuffs and attacker.Debuffs.Hunger) then
3419 Hunger = true;
3420 --
3421 end
3422 if (target and target.Debuffs and target.Debuffs.DefenseDown) then
3423 Def = 0.7
3424 --
3425 end
3426 if (target and target.Debuffs and target.Debuffs.DefenseUp) then
3427 Def = 1.5
3428 --
3429 end
3430 if (attacker and attacker.Debuffs and attacker.Debuffs.AttackUp) then
3431 Atk = 1.2
3432 --
3433 end
3434 if (attacker and attacker.Debuffs and attacker.Debuffs.AttackDown) then
3435 Atk = 0.7
3436 --
3437 end
3438
3439
3440
3441-- if (attack.Type2 == 'Revive' or value.Health > 0) then
3442-- value:Heal(attack.Heal)
3443-- end
3444-- if (attack.Debuffs) then
3445-- for i, v in pairs(attack.Debuff) do
3446-- value:AddDebuff(v)
3447-- end
3448-- end
3449
3450
3451 if (typeof(attack.Damage) == 'string') then
3452 target:SubtractHealth(target.Health / 2);
3453 return true;
3454 end
3455
3456 local constant = .6969
3457
3458 local dif = DifficultyModifiers[self.Difficulty];
3459 local DamageMod = 1;
3460 if (isEnemy) then
3461 DamageMod = dif.DamageRecieved
3462 else
3463 DamageMod = dif.DamageDealt
3464 end
3465
3466 local Guard = target.Guard and 0.45 or 1;
3467 if Difficulty == 'Satanic' then
3468 Guard = Guard==0.45 and 0.1 or Guard;
3469 end
3470
3471 local BTNCount = not isEnemy and (1 + (self.BatonCount and self.BatonCount/1.75 or 0)) or 1;
3472
3473 print('BATON PASS!', BTNCount)
3474
3475
3476 a = a*Atk
3477 local AlreadyAttacked;
3478 local AlreadyCritNotif;
3479 local AlreadyAnimated;
3480 local CameraMoved;
3481 local CritStorage = {}; --Store criticals beforehand so we only show the animation once at the start of the animation;
3482 local CritCounter = 0;
3483 if (not isEnemy) then
3484 for i, v in pairs(self.Enemies) do
3485 if (attack.Damages) or v.ID == target.ID then
3486 local Luck = isEnemy and attacker.EnemyStats.Luck or attacker.Persona.Stats.Luck
3487 local Formula = math.clamp((Luck/100+(Luck and Luck/100 or 0)+(Luck/1000)+(attack.CritChance and attack.CritChance/1000 or 0/1000))/1.5, 0, 1000)/(math.pi);
3488 local crit = (tonumber(v.ID) == 2) or ((not v.Uncritable) and math.random() < Formula)
3489 if (v.Weak and v.Weak[attack.Type] or crit) and (not (v.Null and v.Null[attack.Type])) then
3490 CritCounter = CritCounter+1;
3491 CritStorage[tonumber(v.ID or i)] = {v.ID, i};
3492 --impwarn('CritStorage Length:', #CritStorage)
3493 end
3494 end
3495 end
3496 end
3497 if (not AlreadyAnimated) and (not isEnemy) and (CritCounter > 0) and (not self.OneMore) then
3498 AlreadyAnimated=true;
3499 local Audio = ReplicatedStorage:WaitForChild('SFX'):WaitForChild('Weak');
3500 Audio = Audio:Clone();
3501 Audio.Parent = PlayerGui;
3502 Audio.PlayOnRemove = true;
3503 Audio:Destroy();
3504 self:CharacterPosition(nil, true, true)
3505 local Animations = ReplicatedStorage:WaitForChild('AnimationAssets'):WaitForChild('CritAnim'):GetChildren()
3506 local Animation = LoadAnimation(Animations[math.random(1, #Animations)], Battle:GetCharacterFromID(BattleInfo.SelectedMember):FindFirstChild('Humanoid', true))
3507 Animation:AdjustWeight(1, 2)
3508 Animation:Play();
3509 wait(2);
3510 if (self.Ambush) then
3511 self:AmbushPosition()
3512 end
3513 end
3514 local attackFunction = function(target, attack, Iterator)
3515 local randomValue = math.random();
3516 if (not game:GetService'RunService':IsStudio()) and Evasion ~= 0 and (randomValue < math.abs(Evasion/Divisor)*0.9) and attack.Type ~= 'Buff' and attack.Type ~= 'Kaja' and attack.Type2 ~= 'Debuff' then
3517 impwarn('Missed! Raw Evasion Chance:', Evasion, 'Modified Evasion Change:', Evasion/Divisor, "Random value:", randomValue);
3518 ReplicatedStorage.Music:WaitForChild('Miss'):Play();
3519 else
3520 local crit;
3521 if (isEnemy) then
3522 local Luck = isEnemy and attacker.EnemyStats.Luck or attacker.Persona.Stats.Luck
3523 local Formula = math.clamp((Luck/100+(Luck and Luck/100 or 0)+(Luck/1000)+(attack.CritChance and attack.CritChance/1000 or 0/1000))/1.5, 0, 1000)/(math.pi);
3524 warn('Formula:', Formula)
3525 crit = ((not target.Uncritable) and math.random() < Formula)
3526 else
3527 crit = CritStorage[tonumber(target.ID)] ~= nil
3528 impwarn('Critical Status:', crit)
3529 end
3530 if (TargetDebuffTable) then
3531 for i, v in pairs(TargetDebuffTable) do
3532 local affinity = tostring(attack.Type):lower()
3533 if (Technicals[affinity] and Technicals[affinity][v.Name:lower()]) or (v.Name:lower() == 'dizzy' or v.Name:lower() == 'sleep') then
3534 Technical = true;
3535 if (v.Name ~= 'sleep' and v.Name ~= 'dizzy') then
3536 TargetDebuffTable[i] = nil;
3537 end
3538 end
3539 end
3540 end
3541 if (not CameraMoved) and (not silent) and (not isHeal) and (not self.Ambush) then
3542 CameraMoved=true;
3543 if (isEnemy) then
3544 if (isMultiHit and not isHeal) then
3545 Battle:PartyAttacked()
3546 else
3547 Battle:CharacterAttacked(PositionOfCharacterAttacked)
3548 end
3549 elseif (not isEnemy) then
3550 local Char = self.EnemyContainer:WaitForChild(target.ID)
3551 Battle:CharacterAttacking(BattleInfo.SelectedMember, Char.PrimaryPart, CritCounter>0, attack.Damages or attack.Heals)
3552 wait(0.25)
3553 end
3554 end
3555 if (target.Health > 0) then
3556 if (attack.Yield and not AlreadyAttacked) or (((not attack.Damages) and (not attack.Heals))) then
3557 AlreadyAttacked = true;
3558 Effect(attacker, target, attack, targetIsEnemy, isEnemy, PositionOfCharacterAttacked, Battle);
3559 elseif (not attack.Yield) then
3560 coroutine.wrap(Effect)(attacker, target, attack, targetIsEnemy, isEnemy, PositionOfCharacterAttacked, Battle);
3561 end
3562 end
3563 print('damage guy called', target)
3564 if (crit or WeakVar) and not (target.Null and target.Null[attack.Type]) then
3565 local HeavyHit = ReplicatedStorage.Music:WaitForChild('HeavyHit')
3566 HeavyHit = HeavyHit:Clone()
3567 HeavyHit.Parent = game.Players.LocalPlayer.PlayerGui;
3568 HeavyHit.PlayOnRemove = true;
3569 HeavyHit:Destroy();
3570 if (not AlreadyCritNotif) and (not target.Guard) then
3571 if ((WeakVar or crit) and not isEnemy) then --so morgana doesn't shout HAHA LOOKING COOL JOKER when i get murdered'
3572 if (target.Debuffs) then
3573 if (not target.Debuffs.Down) and (not self.OneMore) and (not target.Guard) then --check for self.onemore so i don't play the stupid sound over and over and over and over and over again'
3574 AlreadyCritNotif = true;
3575 local HeavyHit = ReplicatedStorage.Music:WaitForChild('Looking Cool Joker!') --what have i done
3576 HeavyHit = HeavyHit:Clone()
3577 HeavyHit.Parent = game.Players.LocalPlayer.PlayerGui;
3578 HeavyHit.PlayOnRemove = true;
3579 HeavyHit:Destroy();
3580
3581 local Name = attacker.Name:lower();
3582 local RandomDownAwareness = {};
3583
3584 if (Name == "ryuji") then
3585 RandomDownAwareness = {
3586
3587 "Wow, Skull. You really showed me..",
3588 "Nice one, Skull!",
3589 "Wow, Skull! You're actually good at something for once!",
3590 "Great, Skull! Pass the baton and follow up!",
3591 "Awesome, Skull! You wiped a few enemies off their feet!"
3592
3593 };
3594 elseif (Name == "Yuki") then
3595 RandomDownAwareness = {
3596
3597 "Wow, Blizzard! You got them!",
3598 "Huh, for a shut-in chick, you have some skills! Good job, Blizzard!",
3599 "Great job, Blizzard! You knocked a few enemies off their feet!",
3600 "Nice exhibition of those \"magical powers\", Blizzard!",
3601 "Exemplary job, Blizzard! Pass the baton and follow up!"
3602
3603 }
3604
3605 elseif (Name == "akira") then
3606 RandomDownAwareness = {
3607
3608 "Woah, Joker! You did it!",
3609 "Woaaah, looking cool Joker!",
3610 "For a quite uncharming messy-haired troublemaker, you're good at fighting! Good job, Joker!",
3611 "Nice job, Joker! You knocked a few enemies off their feet!",
3612 "Your powers are incredible, Joker!",
3613 }
3614 elseif (Name == "ann") then
3615 RandomDownAwareness = {
3616
3617 "Panther knocked them down with style and grace!",
3618 "Great job, Panther! Keep it up!",
3619 "From one female to another, you're beautiful, Panther!",
3620 "Nice one, Panther! Pass the baton and follow up!",
3621 "A beautiful rose has thorns!",
3622 "Nice one, Panther!"
3623
3624 }
3625 end
3626
3627 local availableSpeakers = {}; --get a random list of the characters
3628 for i, v in pairs(self.Characters) do
3629 if (v.Name:lower() ~= Name) and i ~= 1 then --so 1. the downer can't congratulate themselves (downer lol)
3630 availableSpeakers[#availableSpeakers+1] = v.Name;
3631 else
3632 print(v.Name:lower(), Name, self.Characters[1].Name:lower(), #availableSpeakers);
3633 end
3634 end
3635 local Member = availableSpeakers[math.random(1, #availableSpeakers)];
3636 Member = Member:sub(1,1):upper()..Member:sub(2); --capitalize first letter of names
3637 Member = ReplicatedStorage:WaitForChild('Party Members'):WaitForChild(Member);
3638 local Chosen = RandomDownAwareness[math.random(1, #RandomDownAwareness)];
3639 warn'hrmm'
3640 toggleOneMore = "W"
3641 _G.BattleAnnouncement(Chosen, Member, true);
3642 end
3643 end
3644 elseif ((WeakVar or crit) and isEnemy) then --so morgana doesn't shout HAHA LOOKING COOL JOKER when i get murdered'
3645 if (target.Debuffs) then
3646 if (not target.Debuffs.Down) and (not self.knockedChar) and (not target.Guard) then --check for self.onemore so i don't play the stupid sound over and over and over and over and over again'
3647 self.knockedChar = true;
3648
3649 local Name = target.Name:lower();
3650
3651 local RandomDownAwareness = {};
3652
3653 if (Name == "ryuji") then
3654 RandomDownAwareness = {
3655 "Skull, you're biting off more than what you can chew! Stay calm!",
3656 "Everyone, Skull is down! Be careful!",
3657 "One of the strongest in our team is knocked out! Watch out, everyone!",
3658 "If they can take down Skull, they can take down Joker! Protect them both at all costs!",
3659 "Come on, Skull! Get up!"
3660 }
3661 elseif (Name == "yuki") then
3662 RandomDownAwareness = {
3663 "Everyone, the most u- I mean, a party member is down! Take care of them!",
3664 "King's been knocked off their feet! Protect her at all costs!",
3665 "Guys, Ice-Girl has been knocked off her last leg! Watch out, everyone!",
3666 "They took down Ice-Girl! Everyone, be careful!",
3667 "King, get up! We need you!"
3668 }
3669 elseif (Name == "akira") then
3670 RandomDownAwareness = {
3671 "Joker? Hey, stop playing games! Get up!",
3672 "Joker! This isn't the time to be playing around!",
3673 "Everyone, Joker's been knocked off his feet! Take some time to tend to his wounds!",
3674 "Uh, guys! Joker's not doing too well!",
3675 "Joker, hurry and rise like a phoenix!",
3676 }
3677 elseif (Name == "ann") then
3678 RandomDownAwareness = {
3679 -- "Alright, Panther! Strike them down with style and grace!",
3680 -- "Alright, Panther! Time to start the counter-attack!"
3681 "Everyone, Panther has been downed! Watch her carefully!",
3682 "Discount K- I mean, Panther has been knocked off of her feet! Stay cautious, everyone!",
3683 "Guys, keep your guard up! Panther is down!",
3684 "Everyone, protect Panther until she gets up!",
3685 "Panther, now is definitely not the time! Get back up!",
3686 }
3687 end
3688 local Chosen = RandomDownAwareness[math.random(1, #RandomDownAwareness)] or "undefined";
3689 _G.BattleAnnouncement(Chosen, nil, true);
3690 end
3691 end
3692 end
3693 end
3694 --impwarn('Pass One:', target.Guard, target.Debuffs.Down, target.Health)
3695 elseif CritCounter < 1 then
3696 local HeavyHit = ReplicatedStorage.Music:WaitForChild('NormalHit')
3697 HeavyHit = HeavyHit:Clone()
3698 HeavyHit.Parent = game.Players.LocalPlayer.PlayerGui;
3699 HeavyHit.PlayOnRemove = true;
3700 HeavyHit:Destroy();
3701 toggleOneMore=false;
3702 self.OneMore = false;
3703 end
3704 local damage = math.floor(attack.Damage*constant^(d/a))
3705 --impwarn(damage, WeakVar, StrongVar, crit, d, a)
3706 damage = math.ceil(damage * (WeakVar and 1.35 or 1) * (StrongVar and 0.45 or 1) * (crit and 1.25 or 1))--l*math.floor(attack.Damage*constant^(d/a) * (WeakVar and 1.15 or 1) * (StrongVar and 0.55 or 1) * (crit and 1.15 or 1))
3707 local Formula = ((damage * DamageMod)*Atk)*(Hunger and 0.4 or 1)*(Technical and 1.25 or 1)*Guard*BTNCount;
3708
3709 if (isEnemy) and (target.Persona.Drain and target.Persona.Drain[attack.Type]) then
3710 local SFX = ReplicatedStorage.SFX.Drain:Clone();
3711 SFX.Parent = PlayerGui;
3712 SFX.PlayOnRemove = true;
3713 SFX:Destroy();
3714 target:Heal(Formula, true)
3715 elseif (target.Drain and target.Drain[attack.Type]) then
3716 local SFX = ReplicatedStorage.SFX.Drain:Clone();
3717 SFX.Parent = PlayerGui;
3718 SFX.PlayOnRemove = true;
3719 SFX:Destroy();
3720 target:Heal(Formula, true)
3721 elseif (isEnemy) and (target.Null and target.Null[attack.Type]) then
3722 target:SubtractHealth(0)
3723 return 'NULL'
3724 elseif (target.Null and target.Null[attack.Type]) then
3725 target:SubtractHealth(0)
3726 return 'NULL'
3727 else
3728 target:SubtractHealth(Formula);--(object, shakeFactor, magnitude, dampeningFactor)
3729 if (target.Health <= 0) then
3730 target.Debuffs = {};
3731 local Humanoid = isEnemy and Battle:GetCharacterFromID(PositionOfCharacterAttacked).Humanoid or Battle:GetEnemyFromName(target.ID).Humanoid;
3732 local Anim = LoadAnimation(ReplicatedStorage.AnimationAssets.Death.Fall, Humanoid)
3733 local Anim2 = LoadAnimation(ReplicatedStorage.AnimationAssets.Death.Stay, Humanoid);
3734 spawn(function(a)
3735 Anim:Play();
3736 Anim.Stopped:Wait()
3737 Anim2:Play()
3738 end)
3739 else
3740 target.Debuffs = target.Debuffs or {};
3741 for i, v in pairs(attack.Debuffs or {}) do
3742 if (((not Strong) or ((not Weak[attack.Type]) and (not crit) and Strong and (not Strong[attack.Type]) and (not Strong[attack.Type:lower()])) and (not target.Guard) and (not target.Debuffs[v.Name])) and target.Health > 0) or game:GetService('RunService'):IsStudio() then --do thing
3743 if (v.Chance/100 >= math.random()) then
3744
3745 local zyrf = v.Name == "Down" and impprint'downed... added'
3746 local x = {};
3747 for i, v in pairs(v) do
3748 x[i] = v;
3749 end
3750 if (target.ID) then
3751 BattleInfo.EnemyTurns[target.ID] = BattleInfo.EnemyTurns[target.ID] or 1
3752 end
3753 BattleInfo.PlayerTurns[PositionOfCharacterAttacked] = BattleInfo.PlayerTurns[PositionOfCharacterAttacked] or 1;
3754 x.TurnAdded = isEnemy and BattleInfo.PlayerTurns[PositionOfCharacterAttacked] or BattleInfo.EnemyTurns[target.ID];
3755 target:AddDebuff(x)
3756 coroutine.wrap(showLabel)(('%s has been inflicted with %s'):format(target.Name or '???', x.Name and x.Name..'!' or 'Unknown Debuff..?'), 2);
3757 end
3758 end
3759 end
3760 if not (DownExclusionBecauseScrewThisStupidCodebase == target) then
3761 impwarn("WTJASFJNASF??")
3762 if ((not target.Guard) and (not target.Debuffs.Down)) or (math.floor(target.Health) <= 0) then
3763 impwarn("WHAT????")
3764 if (( (not isEnemy) and ( not (target.Null and target.Null[attack.Type] ))) or ( (isEnemy) and not (target.Persona.Null and target.Persona.Null[attack.Type]))) then
3765 impwarn("WHY???")
3766 toggleOneMore = 'W';
3767 local Humanoid = isEnemy and Battle:GetCharacterFromID(PositionOfCharacterAttacked).Humanoid or Battle:GetEnemyFromName(target.ID).Humanoid;
3768 local Anim = LoadAnimation(ReplicatedStorage.AnimationAssets.Death.Fall, Humanoid)
3769 local Anim2 = LoadAnimation(ReplicatedStorage.AnimationAssets.Death.Stay, Humanoid);
3770 DownExclusionBecauseScrewThisStupidCodebase = target;
3771 spawn(function(a)
3772 Anim:Play();
3773 impwarn("Down.");
3774 Anim.Stopped:Wait()
3775 Anim2:Play()
3776 end)
3777 local x = math.floor(target.Health) > 0 and target:AddDebuff({Name = "Down", TurnAdded = (not isEnemy and BattleInfo.EnemyTurns[target.ID] or BattleInfo.PlayerTurns[PositionOfCharacterAttacked] or 1), Length = math.random(1, 2)+(target.TurnCount and target.TurnCount/2 or 0), Chance = 100});
3778 elseif CritCounter < 1 then
3779 toggleOneMore = false;
3780 self.OneMore=false;
3781 end
3782 elseif (target.Guard) then
3783 imppwarn("wat du hek", target.Name)
3784 end
3785 else
3786 impprint(DownExclusionBecauseScrewThisStupidCodebase, target, DownExclusionBecauseScrewThisStupidCodebase == target)
3787 end
3788 end
3789 if (PositionOfCharacterAttacked) then
3790 local newShake = Shake.new():setShake(PlayerGui:WaitForChild('Statuses').PartyIndicator:WaitForChild(tostring(PositionOfCharacterAttacked)), 0.5, 0):initShake(1);
3791 end
3792 end
3793
3794
3795
3796 --print('Dealt', Formula,'damage.', target.Name.."'s health is now", tostring(target.Health)..'.')
3797 --print("Damage:", damage, "\nDamageMod:", DamageMod, "\nDamage*DamageMod:", damage*DamageMod, "\nAtk:", Atk, "\nDamage*DamageMod*Atk:", damage*DamageMod*Atk, "\nHunger:", Hunger, "\nGuard:", Guard, "\nBTNCount:", BTNCount, "\na:", a, "\nd:", d, "\nattack.Damage:", attack.Damage)
3798 Battle:TweenHealth(0.25)
3799 end
3800 end
3801 if (isMultiHit) then
3802 if (attack.AttackCount) then
3803 --impwarn('Has several hits.')
3804 local tab = typeof(attack.AttackCount) == "number" and {0, attack.AttackCount} or {attack.AttackCount[1], math.random(attack.AttackCount[1]+1, attack.AttackCount[2])};
3805 for i = tab[1], tab[2] do
3806 for i, v in pairs(GroupToAttack) do
3807 if (v.Health > 0) then
3808 if (attack.Yield and not AlreadyAttacked) then
3809 (attackFunction)(v, attack, nil)
3810 end
3811 coroutine.wrap(attackFunction)(v, attack, nil)
3812 wait(0.25)
3813 end
3814 end
3815 wait(0.175)
3816 end
3817 else
3818 for i, v in pairs(GroupToAttack) do
3819 if (v.Health > 0) then
3820 if (attack.Yield and not AlreadyAttacked) then
3821 (attackFunction)(v, attack, nil)
3822 end
3823 coroutine.wrap(attackFunction)(v, attack, nil)
3824 wait(0.25)
3825 end
3826 end
3827 end
3828 else
3829 if (attack.AttackCount) then
3830 --impwarn('Has several hits. (singular attack)')
3831 local tab = typeof(attack.AttackCount) == "number" and {0, attack.AttackCount[2]} or {attack.AttackCount[1], math.random(attack.AttackCount[1]+1, attack.AttackCount[2])};
3832 for i = tab[1], tab[2] do
3833 (attackFunction)(target, attack, PositionOfCharacterAttacked or target.ID)
3834 wait(0.175)
3835 end
3836 else
3837 (attackFunction)(target, attack, PositionOfCharacterAttacked or target.ID)
3838 end
3839 end
3840 self.OneMore = toggleOneMore;
3841 wait(1.25);
3842end
3843
3844
3845
3846
3847
3848--battle input functionfd
3849
3850
3851
3852function Battle:Failsafe()
3853 Player.Chatted:Connect(function(c)
3854 c = c:match('giveattack:%s?(.*)');
3855
3856 local C = _G.Characters[1].Persona.Attacks;
3857 for i, v in pairs(C) do
3858 if (v:lower() == c:lower()) then
3859 return false;
3860 end
3861 end
3862
3863 for i, v in pairs(Attacks) do
3864 if (i:lower() == c:lower()) then
3865 C[#C+1] = i;
3866 print("Given attack:", i);
3867 return true;
3868 end
3869 end
3870 return false;
3871 end)
3872 print('Failsafe Started!')
3873 local DebugAndUi
3874 DebugAndUi = game:GetService('RunService').RenderStepped:Connect(function(DebugAndUI)
3875 --partyspawns, enemyspawns, partycontainer, enemycontainer
3876 --impwarn(self.Characters[1].Guard, self.Characters[2].Guard, self.Characters[3].Guard, self.Characters[4].Guard);
3877 pcall(function()
3878 PlayerGui:WaitForChild('Persona Attacks List').List.Description.Text = getAttack(game:GetService('GuiService').SelectedObject.Parent.AttackTitle.Text).Description
3879 end)
3880 --Used to make debug functions and for UI progression.
3881 if (self.BattleFinished) then
3882 if (Signal) then
3883 print'disconnected signal'
3884 Signal:Disconnect();
3885 Signal = nil;
3886 end
3887 DebugAndUi:Disconnect();
3888 DebugAndUi = nil;
3889 PlayerGui:WaitForChild('Persona Attacks List').Enabled = false;
3890 PlayerGui:WaitForChild('PersonaListR').Enabled = false;
3891 PlayerGui:WaitForChild('Change Persona').Enabled = false;
3892 BattleInfo.BattleStage = nil;
3893 _G.Stage = nil;
3894 CMS:Enable();
3895 script:Destroy();
3896 warn('Finished failsafe.')
3897 return nil;
3898 else
3899 _G.Occupied = true;
3900 _G.Stage = BattleInfo.BattleStage
3901 end
3902 _G.Occupied = true;
3903 if (tonumber(BattleInfo.SelectedMember) and not self.BattleFinished) then
3904 -- print(BattleInfo.BattleStage);
3905
3906 PlayerGui:WaitForChild('Persona Attacks List').Enabled = BattleInfo.BattleStage == 'PersonaAttackList'
3907 PlayerGui:WaitForChild('PersonaListR').Enabled = BattleInfo.BattleStage == 'Main'
3908 PlayerGui.PersonaListR['BATON PASS'].Visible = self.OneMore
3909 PlayerGui:WaitForChild('Change Persona').Enabled = BattleInfo.BattleStage == 'PersonaChange' or BattleInfo.BattleStage == 'Analysis'
3910 pcall(function()
3911 PlayerGui.PersonaListR.StudsOffset = Vector3.new(
3912 self:
3913 GetCharacterFromID(BattleInfo.SelectedMember)
3914 .PrimaryPart.Size.X + 0.75,
3915 self:
3916 GetCharacterFromID(BattleInfo.SelectedMember)
3917 .PrimaryPart.Size.X/1.75,
3918 0
3919 )
3920
3921 end)
3922
3923 local MovementStatus = (not self.BattleFinished) and CMS:Disable() or CMS:Enable()
3924 end
3925
3926
3927
3928 end)
3929
3930 if (self.Ambush) then
3931 while wait(2.5) do
3932 if (self.BattleFinished) then
3933 game:GetService('Lighting').ambusheffectpulse.Enabled = false;
3934
3935 break;
3936 end
3937 --pulse if ambush
3938 Tween(game:GetService('Lighting').ambusheffectpulse, TweenInfo.new(0.35, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, true, 0.5), {TintColor = Color3.fromRGB(255,114,114)}):Play()
3939 local CMFOV = workspace.CurrentCamera.FieldOfView;
3940 wait(0.65)
3941 Tween(workspace.CurrentCamera, TweenInfo.new(0.1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0, false, 0), {FieldOfView = CMFOV-15}):Play();
3942 wait()
3943 Tween(workspace.CurrentCamera, TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0, false, 0), {FieldOfView = CMFOV}):Play();
3944 wait(0.5);
3945 end
3946 end
3947end
3948
3949
3950
3951--debug
3952
3953local function getCharFromPartName(s)
3954 for i, v in pairs(Battle.Characters) do
3955 if (v.Name:lower():match(s:lower())) then
3956 return v;
3957 end
3958 end
3959end
3960local function getSonaFromPartName(s)
3961 for i, v in pairs(game:GetService'ReplicatedStorage':WaitForChild('Personas'):GetChildren()) do
3962 if (v.Name:lower():match(s:lower())) then
3963 return v;
3964 end
3965 end
3966end
3967
3968return Battle;