1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2010 by The Allacrost Project
3 // All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 /** ****************************************************************************
11 *** \file battle_utils.cpp
12 *** \author Tyler Olsen, roots@allacrost.org
13 *** \brief Source file for battle mode utility code
14 ***
15 *** This file contains utility code that is shared among the various battle mode
16 *** classes.
17 *** ***************************************************************************/
18
19 #include "defs.h"
20 #include "utils.h"
21
22 #include "global.h"
23
24 #include "system.h"
25
26 #include "battle.h"
27 #include "battle_actors.h"
28 #include "battle_utils.h"
29
30 using namespace std;
31
32 using namespace hoa_utils;
33
34 using namespace hoa_system;
35
36 using namespace hoa_global;
37
38 namespace hoa_battle {
39
40 namespace private_battle {
41
42 ////////////////////////////////////////////////////////////////////////////////
43 // Standard battle calculation functions
44 ////////////////////////////////////////////////////////////////////////////////
45
CalculateStandardEvasion(BattleTarget * target)46 bool CalculateStandardEvasion(BattleTarget* target) {
47 return CalculateStandardEvasion(target, 0.0f);
48 }
49
50
51
CalculateStandardEvasion(BattleTarget * target,float add_evade)52 bool CalculateStandardEvasion(BattleTarget* target, float add_evade) {
53 if (target == NULL) {
54 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL target argument" << endl;
55 return false;
56 }
57 if (IsTargetParty(target->GetType()) == true) {
58 IF_PRINT_WARNING(BATTLE_DEBUG) << "target was a party type: " << target->GetType() << endl;
59 return false;
60 }
61
62 float evasion = 0.0f;
63 if (IsTargetPoint(target->GetType()) == true) {
64 evasion = target->GetActor()->GetAttackPoint(target->GetPoint())->GetTotalEvadeRating();
65 }
66 else if (IsTargetActor(target->GetType()) == true) {
67 evasion = target->GetActor()->TotalEvadeRating();
68 }
69 else {
70 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << target->GetType() << endl;
71 return false;
72 }
73
74 evasion += add_evade;
75
76 // Check for absolute hit/miss conditions
77 if (evasion < 0.0f)
78 return false;
79 else if (evasion > 100.0f)
80 return true;
81
82 if (RandomFloat(0.0f, 100.0f) > evasion)
83 return false;
84 else
85 return true;
86 }
87
88
89
CalculateStandardEvasionMultiplier(BattleTarget * target,float mul_evade)90 bool CalculateStandardEvasionMultiplier(BattleTarget* target, float mul_evade) {
91 if (target == NULL) {
92 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL target argument" << endl;
93 return false;
94 }
95 if (IsTargetParty(target->GetType()) == true) {
96 IF_PRINT_WARNING(BATTLE_DEBUG) << "target was a party type: " << target->GetType() << endl;
97 return false;
98 }
99
100 float evasion = 0.0f;
101 if (IsTargetPoint(target->GetType()) == true) {
102 evasion = target->GetActor()->GetAttackPoint(target->GetPoint())->GetTotalEvadeRating();
103 }
104 else if (IsTargetActor(target->GetType()) == true) {
105 evasion = target->GetActor()->TotalEvadeRating();
106 }
107 else {
108 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << target->GetType() << endl;
109 return false;
110 }
111
112 // Apply the multiplier and either reduce or subtract the delta evasion amount
113 float delta = evasion * fabs(mul_evade);
114 if (mul_evade < 0.0f)
115 evasion -= delta;
116 else
117 evasion += delta;
118
119 // Check for absolute hit/miss conditions
120 if (evasion < 0.0f)
121 return false;
122 else if (evasion > 100.0f)
123 return true;
124
125 if (RandomFloat(0.0f, 100.0f) > evasion)
126 return false;
127 else
128 return true;
129 }
130
131
132
CalculateStandardDamage(BattleActor * attacker,BattleTarget * target)133 uint32 CalculateStandardDamage(BattleActor* attacker, BattleTarget* target) {
134 return CalculateStandardDamage(attacker, target, 0, 0, .10f);
135 }
136
137
138
CalculateStandardDamage(BattleActor * attacker,BattleTarget * target,int32 add_phys,int32 add_meta)139 uint32 CalculateStandardDamage(BattleActor* attacker, BattleTarget* target, int32 add_phys, int32 add_meta) {
140 return CalculateStandardDamage(attacker, target, add_phys, add_meta, .10f);
141 }
142
143
144
CalculateStandardDamage(BattleActor * attacker,BattleTarget * target,float std_dev)145 uint32 CalculateStandardDamage(BattleActor* attacker, BattleTarget* target, float std_dev) {
146 return CalculateStandardDamage(attacker, target, 0, 0, std_dev);
147 }
148
149
150
CalculateStandardDamage(BattleActor * attacker,BattleTarget * target,int32 add_phys,int32 add_meta,float std_dev)151 uint32 CalculateStandardDamage(BattleActor* attacker, BattleTarget* target, int32 add_phys, int32 add_meta, float std_dev) {
152 if (attacker == NULL) {
153 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL attacker argument" << endl;
154 return 0;
155 }
156 if (target == NULL) {
157 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL target argument" << endl;
158 return 0;
159 }
160 if (IsTargetParty(target->GetType()) == true) {
161 IF_PRINT_WARNING(BATTLE_DEBUG) << "target was a party type: " << target->GetType() << endl;
162 return 0;
163 }
164
165 // Holds the total physical/metaphysical attack of the attacker and modifier
166 int32 total_phys_atk = 0, total_meta_atk = 0;
167 total_phys_atk = attacker->GetTotalPhysicalAttack() + add_phys;
168 total_meta_atk = attacker->GetTotalMetaphysicalAttack() + add_meta;
169 if (total_phys_atk < 0)
170 total_phys_atk = 0;
171 if (total_meta_atk < 0)
172 total_meta_atk = 0;
173
174 // Holds the total physical/metaphysical defense of the target
175 int32 total_phys_def = 0, total_meta_def = 0;
176
177 if (IsTargetPoint(target->GetType()) == true) {
178 total_phys_def = target->GetActor()->GetAttackPoint(target->GetPoint())->GetTotalPhysicalDefense();
179 total_meta_def = target->GetActor()->GetAttackPoint(target->GetPoint())->GetTotalMetaphysicalDefense();
180 }
181 else if (IsTargetActor(target->GetType()) == true) {
182 total_phys_def = target->GetActor()->TotalPhysicalDefense();
183 total_meta_def = target->GetActor()->TotalMetaphysicalDefense();
184 }
185 else {
186 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << target->GetType() << endl;
187 return 0;
188 }
189
190 // Holds the physical and metaphysical damage dealt
191 int32 total_phys_dmg = 0, total_meta_dmg = 0;
192 total_phys_dmg = total_phys_atk - total_phys_def;
193 total_meta_dmg = total_meta_atk - total_meta_def;
194 if (total_phys_dmg < 0)
195 total_phys_dmg = 0;
196 if (total_meta_dmg < 0)
197 total_meta_dmg = 0;
198
199 // Holds the total damage dealt
200 uint32 total_dmg = 0;
201 total_dmg = total_phys_dmg + total_meta_dmg;
202
203 // If the total damage is zero, fall back to causing a small non-zero damage value
204 if (total_dmg <= 0)
205 return static_cast<uint32>(RandomBoundedInteger(1, 5));
206
207 // Holds the absolute standard deviation used in the GaussianRandomValue function
208 float abs_std_dev = 0.0f;
209 // A value of "0.075f" means the standard deviation should be 7.5% of the mean (the total damage)
210 abs_std_dev = static_cast<float>(total_dmg) * std_dev;
211 total_dmg = GaussianRandomValue(total_dmg, abs_std_dev, false);
212
213 // If the total damage came to a value less than or equal to zero after the gaussian randomization,
214 // fall back to returning a small non-zero damage value
215 if (total_dmg <= 0)
216 return static_cast<uint32>(RandomBoundedInteger(1, 5));
217
218 return static_cast<uint32>(total_dmg);
219 } // uint32 CalculateStandardDamage(BattleActor* attacker, BattleTarget* target, int32 add_phys, int32 add_meta, float std_dev)
220
221
222
CalculateStandardDamageMultiplier(BattleActor * attacker,BattleTarget * target,float mul_phys,float mul_meta)223 uint32 CalculateStandardDamageMultiplier(BattleActor* attacker, BattleTarget* target, float mul_phys, float mul_meta) {
224 return CalculateStandardDamageMultiplier(attacker, target, mul_phys, mul_meta, 10.0f);
225 }
226
227
228
CalculateStandardDamageMultiplier(BattleActor * attacker,BattleTarget * target,float mul_phys,float mul_meta,float std_dev)229 uint32 CalculateStandardDamageMultiplier(BattleActor* attacker, BattleTarget* target, float mul_phys, float mul_meta, float std_dev) {
230 if (attacker == NULL) {
231 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL attacker argument" << endl;
232 return 0;
233 }
234 if (target == NULL) {
235 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL target argument" << endl;
236 return 0;
237 }
238 if (IsTargetParty(target->GetType()) == true) {
239 IF_PRINT_WARNING(BATTLE_DEBUG) << "target was a party type: " << target->GetType() << endl;
240 return 0;
241 }
242
243 // Holds the total physical/metaphysical attack of the attacker and modifier
244 int32 total_phys_atk = 0, total_meta_atk = 0;
245 total_phys_atk = attacker->GetTotalPhysicalAttack();
246 total_meta_atk = attacker->GetTotalMetaphysicalAttack();
247
248 // Apply the multipliers and either reduce or subtract the delta evasion amount
249 float phys_delta = 0.0f, meta_delta = 0.0f;
250 phys_delta = static_cast<float>(total_phys_atk) * fabs(mul_phys);
251 meta_delta = static_cast<float>(total_meta_atk) * fabs(mul_meta);
252
253 if (mul_phys < 0.0f)
254 total_phys_atk -= static_cast<int32>(phys_delta);
255 else
256 total_phys_atk += static_cast<int32>(phys_delta);
257 if (mul_meta < 0.0f)
258 total_meta_atk -= static_cast<int32>(meta_delta);
259 else
260 total_meta_atk += static_cast<int32>(meta_delta);
261
262 if (total_phys_atk < 0)
263 total_phys_atk = 0;
264 if (total_meta_atk < 0)
265 total_meta_atk = 0;
266
267 // Holds the total physical/metaphysical defense of the target
268 int32 total_phys_def = 0, total_meta_def = 0;
269
270 if (IsTargetPoint(target->GetType()) == true) {
271 total_phys_def = target->GetActor()->GetAttackPoint(target->GetPoint())->GetTotalPhysicalDefense();
272 total_meta_def = target->GetActor()->GetAttackPoint(target->GetPoint())->GetTotalMetaphysicalDefense();
273 }
274 else if (IsTargetActor(target->GetType()) == true) {
275 total_phys_def = target->GetActor()->TotalPhysicalDefense();
276 total_meta_def = target->GetActor()->TotalMetaphysicalDefense();
277 }
278 else {
279 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << target->GetType() << endl;
280 return 0;
281 }
282
283
284 // Holds the physical and metaphysical damage dealt
285 int32 total_phys_dmg = 0, total_meta_dmg = 0;
286 total_phys_dmg = total_phys_atk - total_phys_def;
287 total_meta_dmg = total_meta_atk - total_meta_def;
288 if (total_phys_dmg < 0)
289 total_phys_dmg = 0;
290 if (total_meta_dmg < 0)
291 total_meta_dmg = 0;
292
293 // Holds the total damage dealt
294 uint32 total_dmg = 0;
295 total_dmg = total_phys_dmg + total_meta_dmg;
296
297 // If the total damage is zero, fall back to causing a small non-zero damage value
298 if (total_dmg <= 0)
299 return static_cast<uint32>(RandomBoundedInteger(1, 5));
300
301 // Holds the absolute standard deviation used in the GaussianRandomValue function
302 float abs_std_dev = 0.0f;
303 // A value of "0.075f" means the standard deviation should be 7.5% of the mean (the total damage)
304 abs_std_dev = static_cast<float>(total_dmg) * std_dev;
305 total_dmg = GaussianRandomValue(total_dmg, abs_std_dev, false);
306
307 // If the total damage came to a value less than or equal to zero after the gaussian randomization,
308 // fall back to returning a small non-zero damage value
309 if (total_dmg <= 0)
310 return static_cast<uint32>(RandomBoundedInteger(1, 5));
311
312 return static_cast<uint32>(total_dmg);
313 } // uint32 CalculateStandardDamageMultiplier(BattleActor* attacker, BattleTarget* target, float mul_phys, float mul_meta, float std_dev)
314
315 ////////////////////////////////////////////////////////////////////////////////
316 // BattleTimer class
317 ////////////////////////////////////////////////////////////////////////////////
318
BattleTimer()319 BattleTimer::BattleTimer() :
320 SystemTimer(),
321 _time_multiplier_active(false),
322 _time_multiplier(0.0f)
323 {}
324
325
326
BattleTimer(uint32 duration,int32 loops)327 BattleTimer::BattleTimer(uint32 duration, int32 loops) :
328 SystemTimer(duration, loops),
329 _time_multiplier_active(false),
330 _time_multiplier(0.0f)
331 {}
332
333
334
Update()335 void BattleTimer::Update() {
336 Update(SystemManager->GetUpdateTime());
337 }
338
339
340
Update(uint32 time)341 void BattleTimer::Update(uint32 time) {
342 if (_time_multiplier_active == false)
343 SystemTimer::Update(time);
344 else
345 SystemTimer::Update(_ApplyMultiplier(time));
346 }
347
348
349
SetTimeExpired(uint32 time)350 void BattleTimer::SetTimeExpired(uint32 time) {
351 _time_expired = time;
352
353 if ((_time_expired == 0) && (_times_completed == 0)) {
354 _state = SYSTEM_TIMER_INITIAL;
355 }
356
357 else if (_time_expired >= _duration) {
358 _time_expired = 0;
359 _times_completed++;
360
361 // Check if the timer has finished the final loop and should reach the finished state
362 if ((_number_loops >= 0) && (_times_completed >= static_cast<uint32>(_number_loops))) {
363 _state = SYSTEM_TIMER_FINISHED;
364 }
365 }
366 }
367
368
369
ActivateTimeMultiplier(bool activate,float multiplier)370 void BattleTimer::ActivateTimeMultiplier(bool activate, float multiplier) {
371 _time_multiplier_active = activate;
372
373 if (activate == true) {
374 if (multiplier < 0.0f) {
375 IF_PRINT_WARNING(BATTLE_DEBUG) << "tried to activate a negative multiplier: " << multiplier << endl;
376 _time_multiplier_active = false;
377 }
378 else {
379 _time_multiplier = multiplier;
380 }
381 }
382 }
383
384
385
_AutoUpdate()386 void BattleTimer::_AutoUpdate() {
387 if (_time_multiplier_active == false) {
388 SystemTimer::_AutoUpdate();
389 return;
390 }
391
392 if (_auto_update == false) {
393 IF_PRINT_WARNING(SYSTEM_DEBUG) << "tried to automatically update a timer that does not have auto updates enabled" << endl;
394 return;
395 }
396 if (IsRunning() == false) {
397 return;
398 }
399
400 _UpdateTimer(_ApplyMultiplier(SystemManager->GetUpdateTime()));
401 }
402
403
404
_ApplyMultiplier(uint32 time)405 uint32 BattleTimer::_ApplyMultiplier(uint32 time) {
406 // NOTE: This static cast doesn't round the float to the nearest whole integer, it uses a floor
407 // function instead. So 24.99 would return 24 instead of 25. This should probably be changed to
408 // use a standard rounding function (didn't see anything available in utils.h for this).
409 return static_cast<uint32>(_time_multiplier * time);
410 }
411
412 ////////////////////////////////////////////////////////////////////////////////
413 // BattleTarget class
414 ////////////////////////////////////////////////////////////////////////////////
415
BattleTarget()416 BattleTarget::BattleTarget() :
417 _type(GLOBAL_TARGET_INVALID),
418 _point(0),
419 _actor(NULL),
420 _party(NULL)
421 {}
422
423
424
InvalidateTarget()425 void BattleTarget::InvalidateTarget() {
426 _type = GLOBAL_TARGET_INVALID;
427 _point = 0;
428 _actor = NULL;
429 _party = NULL;
430 }
431
432
433
SetInitialTarget(BattleActor * user,GLOBAL_TARGET type)434 void BattleTarget::SetInitialTarget(BattleActor* user, GLOBAL_TARGET type) {
435 InvalidateTarget();
436
437 if (user == NULL) {
438 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL argument" << endl;
439 return;
440 }
441 if ((type <= GLOBAL_TARGET_INVALID) || (type >= GLOBAL_TARGET_TOTAL)) {
442 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type argument: " << type << endl;
443 return;
444 }
445
446 // Determine what party the initial target will exist in
447 deque<BattleActor*>* target_party;
448 if ((type == GLOBAL_TARGET_ALLY_POINT) || (type == GLOBAL_TARGET_ALLY) || (type == GLOBAL_TARGET_ALL_ALLIES)) {
449 if (user->IsEnemy() == false)
450 target_party = &BattleMode::CurrentInstance()->GetCharacterParty();
451 else
452 target_party = &BattleMode::CurrentInstance()->GetEnemyParty();
453 }
454 else if ((type == GLOBAL_TARGET_FOE_POINT) || (type == GLOBAL_TARGET_FOE) || (type == GLOBAL_TARGET_ALL_FOES)) {
455 if (user->IsEnemy() == false)
456 target_party = &BattleMode::CurrentInstance()->GetEnemyParty();
457 else
458 target_party = &BattleMode::CurrentInstance()->GetCharacterParty();
459 }
460 else {
461 target_party = NULL;
462 }
463
464 // Set the actor/party according to the target type
465 switch (type) {
466 case GLOBAL_TARGET_SELF_POINT:
467 case GLOBAL_TARGET_SELF:
468 _actor = user;
469 break;
470 case GLOBAL_TARGET_ALLY_POINT:
471 case GLOBAL_TARGET_FOE_POINT:
472 case GLOBAL_TARGET_ALLY:
473 case GLOBAL_TARGET_FOE:
474 _actor = target_party->at(0);
475 break;
476 case GLOBAL_TARGET_ALL_ALLIES:
477 case GLOBAL_TARGET_ALL_FOES:
478 _party = target_party;
479 break;
480 default:
481 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid type: " << type << endl;
482 return;
483 }
484
485 _type = type;
486
487 // If the target is not a party and not the user themselves, select the first valid actor
488 if ((_actor != NULL) && (_actor != user)) {
489 if (IsValid() == false) {
490 if (SelectNextActor(user, true, true) == false)
491 IF_PRINT_WARNING(BATTLE_DEBUG) << "could not find an initial actor that was a valid target" << endl;
492 }
493 }
494 }
495
496
497
SetPointTarget(GLOBAL_TARGET type,uint32 attack_point,BattleActor * actor)498 void BattleTarget::SetPointTarget(GLOBAL_TARGET type, uint32 attack_point, BattleActor* actor) {
499 if (IsTargetPoint(type) == false) {
500 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received invalid type argument: " << type << endl;
501 return;
502 }
503 if ((actor == NULL) && (_actor == NULL)) {
504 IF_PRINT_WARNING(BATTLE_DEBUG) << "attempted to set an attack point with no valid actor selected" << endl;
505 return;
506 }
507 else if ((actor == NULL) && (attack_point >= _actor->GetAttackPoints().size())) {
508 IF_PRINT_WARNING(BATTLE_DEBUG) << "attack point index was out-of-range: " << attack_point << endl;
509 return;
510 }
511 else if ((_actor == NULL) && (attack_point >= actor->GetAttackPoints().size())) {
512 IF_PRINT_WARNING(BATTLE_DEBUG) << "attack point index was out-of-range: " << attack_point << endl;
513 return;
514 }
515
516 _type = type;
517 _point = attack_point;
518 if (actor != NULL)
519 _actor = actor;
520 _party = NULL;
521 }
522
523
524
SetActorTarget(GLOBAL_TARGET type,BattleActor * actor)525 void BattleTarget::SetActorTarget(GLOBAL_TARGET type, BattleActor* actor) {
526 if (IsTargetActor(type) == false) {
527 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received invalid type argument: " << type << endl;
528 return;
529 }
530 if (actor == NULL) {
531 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL argument" << endl;
532 return;
533 }
534
535 _type = type;
536 _point = 0;
537 _actor = actor;
538 _party = NULL;
539 }
540
541
542
SetPartyTarget(GLOBAL_TARGET type,deque<BattleActor * > * party)543 void BattleTarget::SetPartyTarget(GLOBAL_TARGET type, deque<BattleActor*>* party) {
544 if (IsTargetParty(type) == false) {
545 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received invalid type argument: " << type << endl;
546 return;
547 }
548 if (party == NULL) {
549 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL argument" << endl;
550 return;
551 }
552
553 _type = type;
554 _point = 0;
555 _actor = NULL;
556 _party = party;
557 }
558
559
560
IsValid()561 bool BattleTarget::IsValid() {
562 if (IsTargetPoint(_type) == true) {
563 if (_actor == NULL)
564 return false;
565 else if (_point >= _actor->GetAttackPoints().size())
566 return false;
567 else if (_actor->IsAlive() == false)
568 return false;
569 else
570 return true;
571 }
572 else if (IsTargetActor(_type) == true) {
573 if (_actor == NULL)
574 return false;
575 else if (_actor->IsAlive() == false)
576 return false;
577 else
578 return true;
579 }
580 else if (IsTargetParty(_type) == true) {
581 if (_party == NULL)
582 return false;
583 else
584 return true;
585 }
586 else {
587 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << _type << endl;
588 return false;
589 }
590 }
591
592
593
SelectNextPoint(BattleActor * user,bool direction,bool valid_criteria)594 bool BattleTarget::SelectNextPoint(BattleActor* user, bool direction, bool valid_criteria) {
595 if (user == NULL) {
596 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL argument" << endl;
597 return false;
598 }
599 if (IsTargetPoint(_type) == false) {
600 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << _type << endl;
601 return false;
602 }
603 if (_actor == NULL) {
604 IF_PRINT_WARNING(BATTLE_DEBUG) << "no valid actor target" << endl;
605 return false;
606 }
607
608 // First check for the case where we need to select a new actor
609 if (valid_criteria == true && IsValid() == false) {
610 _point = 0;
611 return SelectNextActor(user, direction, valid_criteria);
612 }
613
614 // If the actor has only a single attack point, there's no way to select another attack point
615 uint32 num_points = _actor->GetAttackPoints().size();
616 if (num_points == 1) {
617 return false;
618 }
619
620 if (direction == true) {
621 _point++;
622 if (_point >= num_points)
623 _point = 0;
624 }
625 else {
626 if (_point == 0)
627 _point = num_points - 1;
628 else
629 _point--;
630 }
631 return true;
632 }
633
634
635
SelectNextActor(BattleActor * user,bool direction,bool valid_criteria)636 bool BattleTarget::SelectNextActor(BattleActor* user, bool direction, bool valid_criteria) {
637 if (user == NULL) {
638 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL argument" << endl;
639 return false;
640 }
641 if ((IsTargetPoint(_type) == false) && (IsTargetActor(_type) == false)) {
642 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << _type << endl;
643 return false;
644 }
645 if (_actor == NULL) {
646 IF_PRINT_WARNING(BATTLE_DEBUG) << "no valid actor target" << endl;
647 return false;
648 }
649
650 // ----- (1): Retrieve the proper party container that contains the actors we would like to select from
651 deque<BattleActor*>* target_party = NULL;
652 if ((_type == GLOBAL_TARGET_SELF_POINT) || (_type == GLOBAL_TARGET_SELF)) {
653 return false; // Self type targets do not have multiple actors to select from
654 }
655 else if ((_type == GLOBAL_TARGET_ALLY_POINT) || (_type == GLOBAL_TARGET_ALLY)) {
656 if (user->IsEnemy() == false)
657 target_party = &BattleMode::CurrentInstance()->GetCharacterParty();
658 else
659 target_party = &BattleMode::CurrentInstance()->GetEnemyParty();
660 }
661 else if ((_type == GLOBAL_TARGET_FOE_POINT) || (_type == GLOBAL_TARGET_FOE)) {
662 if (user->IsEnemy() == false)
663 target_party = &BattleMode::CurrentInstance()->GetEnemyParty();
664 else
665 target_party = &BattleMode::CurrentInstance()->GetCharacterParty();
666 }
667 else {
668 // This should never be reached because the target type was already determined to be a point or actor above
669 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid target type: " << _type << endl;
670 return false;
671 }
672
673 // ----- (2): Check the target party for early exit conditions
674 if (target_party->empty() == true) {
675 IF_PRINT_WARNING(BATTLE_DEBUG) << "actor target's party was empty" << endl;
676 return false;
677 }
678 if (target_party->size() == 1) {
679 return false; // No more actors to select from in the party
680 }
681
682 // ----- (3): Determine the index of the current actor in the target party
683 uint32 original_target_index = 0xFFFFFFFF; // Initially set to an impossibly high index for error checking
684 for (uint32 i = 0; i < target_party->size(); i++) {
685 if (target_party->at(i) == _actor) {
686 original_target_index = i;
687 break;
688 }
689 }
690 if (original_target_index == 0xFFFFFFFF) {
691 IF_PRINT_WARNING(BATTLE_DEBUG) << "actor target was not found in party" << endl;
692 return false;
693 }
694
695 // ----- (4): Starting from the index of the original actor, select the next available actor
696 BattleActor* original_actor = _actor;
697 uint32 new_target_index = original_target_index;
698 while (true) {
699 // Increment or decrement the target index based on the direction argument
700 if (direction == true) {
701 new_target_index = (new_target_index >= target_party->size() - 1) ? 0 : new_target_index + 1;
702 }
703 else {
704 new_target_index = (new_target_index == 0) ? target_party->size() - 1 : new_target_index - 1;
705 }
706
707 // If we've reached the original target index then we were unable to select another actor target
708 if (new_target_index == original_target_index) {
709 _actor = original_actor;
710 return false;
711 }
712
713 // Set the new actor target and if required, ascertain the new target's validity. If the new target
714 // must be valid and this new actor is not, the loop will continue and will try again with the next actor
715 _actor = target_party->at(new_target_index);
716 if (valid_criteria == false) {
717 return true;
718 }
719 else if (IsValid() == true){
720 return true;
721 }
722 }
723 } // bool BattleTarget::SelectNextActor(BattleActor* user, bool direction, bool valid_criteria)
724
725 ////////////////////////////////////////////////////////////////////////////////
726 // BattleItem class
727 ////////////////////////////////////////////////////////////////////////////////
728
BattleItem(hoa_global::GlobalItem item)729 BattleItem::BattleItem(hoa_global::GlobalItem item) :
730 _item(item),
731 _available_count(item.GetCount())
732 {
733 if (item.GetID() == 0)
734 IF_PRINT_WARNING(BATTLE_DEBUG) << "constructor received invalid item argument" << endl;
735 }
736
737
738
~BattleItem()739 BattleItem::~BattleItem() {
740 if (_available_count != _item.GetCount())
741 IF_PRINT_WARNING(BATTLE_DEBUG) << "actual count was not equal to available count upon destruction" << endl;
742 }
743
744
745
IncrementAvailableCount()746 void BattleItem::IncrementAvailableCount() {
747 _available_count++;
748 if (_available_count > _item.GetCount()) {
749 IF_PRINT_WARNING(BATTLE_DEBUG) << "attempted to increment available count above actual count: " << _available_count << endl;
750 _available_count--;
751 }
752 }
753
754
755
DecrementAvailableCount()756 void BattleItem::DecrementAvailableCount() {
757 if (_available_count == 0) {
758 IF_PRINT_WARNING(BATTLE_DEBUG) << "attempted to decrement available count below zero" << endl;
759 return;
760 }
761 _available_count--;
762 }
763
764
765
IncrementCount()766 void BattleItem::IncrementCount() {
767 _item.IncrementCount();
768 _available_count++;
769 }
770
771
772
DecrementCount()773 void BattleItem::DecrementCount() {
774 if (_item.GetCount() == 0) {
775 IF_PRINT_WARNING(BATTLE_DEBUG) << "item count was zero when function was called" << endl;
776 return;
777 }
778
779 _item.DecrementCount();
780
781 if (_available_count > _item.GetCount()) {
782 IF_PRINT_WARNING(BATTLE_DEBUG) << "available count was greater than actual count: " << _available_count << endl;
783 _available_count = _item.GetCount();
784 }
785 }
786
787 } // namespace private_shop
788
789 } // namespace hoa_shop
790