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