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    global_actors.cpp
12 *** \author  Tyler Olsen, roots@allacrost.org
13 *** \brief   Source file for global game actors
14 *** ***************************************************************************/
15 
16 #include "video.h"
17 #include "global_actors.h"
18 #include "global_objects.h"
19 #include "global_effects.h"
20 #include "global_skills.h"
21 
22 using namespace std;
23 
24 using namespace hoa_utils;
25 using namespace hoa_video;
26 using namespace hoa_script;
27 
28 namespace hoa_global {
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 // GlobalAttackPoint class
32 ////////////////////////////////////////////////////////////////////////////////
33 
GlobalAttackPoint(GlobalActor * owner)34 GlobalAttackPoint::GlobalAttackPoint(GlobalActor* owner) :
35 	_actor_owner(owner),
36 	_x_position(0),
37 	_y_position(0),
38 	_fortitude_modifier(0.0f),
39 	_protection_modifier(0.0f),
40 	_evade_modifier(0.0f),
41 	_total_physical_defense(0),
42 	_total_metaphysical_defense(0),
43 	_total_evade_rating(0)
44 {}
45 
46 
47 
LoadData(ReadScriptDescriptor & script)48 bool GlobalAttackPoint::LoadData(ReadScriptDescriptor& script) {
49 	if (script.IsFileOpen() == false) {
50 		return false;
51 	}
52 
53 	_name = MakeUnicodeString(script.ReadString("name"));
54 	_x_position = script.ReadInt("x_position");
55 	_y_position = script.ReadInt("y_position");
56 	_fortitude_modifier = script.ReadFloat("fortitude_modifier");
57 	_protection_modifier = script.ReadFloat("protection_modifier");
58 	_evade_modifier = script.ReadFloat("evade_modifier");
59 
60 	if (script.IsErrorDetected()) {
61 		if (GLOBAL_DEBUG) {
62 			PRINT_WARNING << "one or more errors occurred while reading the save game file - they are listed below" << endl;
63 			cerr << script.GetErrorMessages() << endl;
64 		}
65 		return false;
66 	}
67 
68 	return true;
69 }
70 
71 
72 
CalculateTotalDefense(const GlobalArmor * equipped_armor)73 void GlobalAttackPoint::CalculateTotalDefense(const GlobalArmor* equipped_armor) {
74 	if (_actor_owner == NULL) {
75 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "attack point has no owning actor" << endl;
76 		return;
77 	}
78 
79 	// Calculate defense ratings from owning actor's base stat properties and the attack point modifiers
80 	if (_fortitude_modifier <= -1.0f) // If the modifier is less than or equal to -100%, set the total defense to zero
81 		_total_physical_defense = 0;
82 	else
83 		_total_physical_defense = _actor_owner->GetFortitude() + static_cast<int32>(_actor_owner->GetFortitude() * _fortitude_modifier);
84 
85 	if (_protection_modifier <= -1.0f) // If the modifier is less than or equal to -100%, set the total defense to zero
86 		_total_metaphysical_defense = 0;
87 	else
88 		_total_metaphysical_defense = _actor_owner->GetProtection() + static_cast<int32>(_actor_owner->GetProtection() * _protection_modifier);
89 
90 	// If present, add defense ratings from the armor equipped
91 	if (equipped_armor != NULL) {
92 		_total_physical_defense += equipped_armor->GetPhysicalDefense();
93 		_total_metaphysical_defense += equipped_armor->GetMetaphysicalDefense();
94 	}
95 }
96 
97 
98 
CalculateTotalEvade()99 void GlobalAttackPoint::CalculateTotalEvade() {
100 	if (_actor_owner == NULL) {
101 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "attack point has no owning actor" << endl;
102 		return;
103 	}
104 
105 	// Calculate evade ratings from owning actor's base evade stat and the evade modifier
106 	if (_fortitude_modifier <= -1.0f) // If the modifier is less than or equal to -100%, set the total evade to zero
107 		_total_evade_rating = 0.0f;
108 	else
109 		_total_evade_rating = _actor_owner->GetEvade() + (_actor_owner->GetEvade() * _evade_modifier);
110 }
111 
112 ////////////////////////////////////////////////////////////////////////////////
113 // GlobalActor class
114 ////////////////////////////////////////////////////////////////////////////////
115 
GlobalActor()116 GlobalActor::GlobalActor() :
117 	_id(0),
118 	_experience_level(0),
119 	_experience_points(0),
120 	_hit_points(0),
121 	_max_hit_points(0),
122 	_skill_points(0),
123 	_max_skill_points(0),
124 	_strength(0),
125 	_vigor(0),
126 	_fortitude(0),
127 	_protection(0),
128 	_agility(0),
129 	_evade(0.0f),
130 	_total_physical_attack(0),
131 	_total_metaphysical_attack(0),
132 	_weapon_equipped(NULL)
133 {}
134 
135 
136 
~GlobalActor()137 GlobalActor::~GlobalActor() {
138 	// Delete all attack points
139 	for (uint32 i = 0; i < _attack_points.size(); i++) {
140 		delete _attack_points[i];
141 	}
142 	_attack_points.clear();
143 
144 	// Delete all equipment
145 	if (_weapon_equipped != NULL)
146 		delete _weapon_equipped;
147 	for (uint32 i = 0; i < _armor_equipped.size(); i++) {
148 		if (_armor_equipped[i] != NULL)
149 			delete _armor_equipped[i];
150 	}
151 	_armor_equipped.clear();
152 
153 	// Delete all skills
154 	for (map<uint32, GlobalSkill*>::iterator i = _skills.begin(); i != _skills.end(); i++) {
155 		delete i->second;
156 	}
157 	_skills.clear();
158 }
159 
160 
161 
GlobalActor(const GlobalActor & copy)162 GlobalActor::GlobalActor(const GlobalActor& copy) {
163 	_id = copy._id;
164 	_name = copy._name;
165 	_filename = copy._filename;
166 	_experience_level = copy._experience_level;
167 	_experience_points = copy._experience_points;
168 	_hit_points = copy._hit_points;
169 	_max_hit_points = copy._max_hit_points;
170 	_skill_points = copy._skill_points;
171 	_max_skill_points = copy._max_skill_points;
172 	_strength = copy._strength;
173 	_vigor = copy._vigor;
174 	_fortitude = copy._fortitude;
175 	_protection = copy._protection;
176 	_agility = copy._agility;
177 	_evade = copy._evade;
178 	_total_physical_attack = copy._total_physical_attack;
179 	_total_metaphysical_attack = copy._total_metaphysical_attack;
180 
181 	// Copy all attack points
182 	for (uint32 i = 0; i < copy._attack_points.size(); i++) {
183 		_attack_points.push_back(new GlobalAttackPoint(*copy._attack_points[i]));
184 		_attack_points[i]->SetActorOwner(this);
185 	}
186 
187 	// Copy all equipment
188 	if (copy._weapon_equipped == NULL)
189 		_weapon_equipped = NULL;
190 	else
191 		_weapon_equipped = new GlobalWeapon(*copy._weapon_equipped);
192 
193 	for (uint32 i = 0; i < _armor_equipped.size(); i++) {
194 		if (_armor_equipped[i] == NULL)
195 			_armor_equipped.push_back(NULL);
196 		else
197 			_armor_equipped.push_back(new GlobalArmor(*copy._armor_equipped[i]));
198 	}
199 
200 	// Copy all skills
201 	for (map<uint32, GlobalSkill*>::const_iterator i = copy._skills.begin(); i != copy._skills.end(); i++) {
202 		_skills.insert(make_pair(i->first, new GlobalSkill(*(i->second))));
203 	}
204 }
205 
206 
207 
operator =(const GlobalActor & copy)208 GlobalActor& GlobalActor::operator=(const GlobalActor& copy) {
209 	if (this == &copy) // Handle self-assignment case
210 		return *this;
211 
212 	_id = copy._id;
213 	_name = copy._name;
214 	_filename = copy._filename;
215 	_experience_level = copy._experience_level;
216 	_experience_points = copy._experience_points;
217 	_hit_points = copy._hit_points;
218 	_max_hit_points = copy._max_hit_points;
219 	_skill_points = copy._skill_points;
220 	_max_skill_points = copy._max_skill_points;
221 	_strength = copy._strength;
222 	_vigor = copy._vigor;
223 	_fortitude = copy._fortitude;
224 	_protection = copy._protection;
225 	_agility = copy._agility;
226 	_evade = copy._evade;
227 	_total_physical_attack = copy._total_physical_attack;
228 	_total_metaphysical_attack = copy._total_metaphysical_attack;
229 
230 	// Copy all attack points
231 	for (uint32 i = 0; i < copy._attack_points.size(); i++) {
232 		_attack_points.push_back(new GlobalAttackPoint(*_attack_points[i]));
233 		_attack_points[i]->SetActorOwner(this);
234 	}
235 
236 	// Copy all equipment
237 	if (copy._weapon_equipped == NULL)
238 		_weapon_equipped = NULL;
239 	else
240 		_weapon_equipped = new GlobalWeapon(*copy._weapon_equipped);
241 
242 	for (uint32 i = 0; i < _armor_equipped.size(); i++) {
243 		if (_armor_equipped[i] == NULL)
244 			_armor_equipped.push_back(NULL);
245 		else
246 			_armor_equipped.push_back(new GlobalArmor(*copy._armor_equipped[i]));
247 	}
248 
249 	// Copy all skills
250 	for (map<uint32, GlobalSkill*>::const_iterator i = copy._skills.begin(); i != copy._skills.end(); i++) {
251 		_skills.insert(make_pair(i->first, new GlobalSkill(*(i->second))));
252 	}
253 	return *this;
254 }
255 
256 
257 
EquipWeapon(GlobalWeapon * weapon)258 GlobalWeapon* GlobalActor::EquipWeapon(GlobalWeapon* weapon) {
259 	GlobalWeapon* old_weapon = _weapon_equipped;
260 	_weapon_equipped = weapon;
261 	_CalculateAttackRatings();
262 	return old_weapon;
263 }
264 
265 
266 
EquipArmor(GlobalArmor * armor,uint32 index)267 GlobalArmor* GlobalActor::EquipArmor(GlobalArmor* armor, uint32 index) {
268 	if (index >= _armor_equipped.size()) {
269 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded number of pieces of armor equipped: " << index << endl;
270 		return armor;
271 	}
272 
273 	GlobalArmor* old_armor = _armor_equipped[index];
274 	_armor_equipped[index] = armor;
275 
276 	if (old_armor != NULL && armor != NULL) {
277 		if (old_armor->GetObjectType() != armor->GetObjectType()) {
278 			IF_PRINT_WARNING(GLOBAL_DEBUG) << "old armor was replaced with a different type of armor" << endl;
279 		}
280 	}
281 
282 	_attack_points[index]->CalculateTotalDefense(_armor_equipped[index]);
283 	return old_armor;
284 }
285 
286 
287 
GetTotalPhysicalDefense(uint32 index) const288 uint32 GlobalActor::GetTotalPhysicalDefense(uint32 index) const {
289 	if (index >= _attack_points.size()) {
290 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded number of attack points: " << index << endl;
291 		return 0;
292 	}
293 
294 	return _attack_points[index]->GetTotalPhysicalDefense();
295 }
296 
297 
298 
GetTotalMetaphysicalDefense(uint32 index) const299 uint32 GlobalActor::GetTotalMetaphysicalDefense(uint32 index) const {
300 	if (index >= _attack_points.size()) {
301 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded number of attack points: " << index << endl;
302 		return 0;
303 	}
304 
305 	return _attack_points[index]->GetTotalMetaphysicalDefense();
306 }
307 
308 
309 
GetTotalEvadeRating(uint32 index) const310 float GlobalActor::GetTotalEvadeRating(uint32 index) const {
311 	if (index >= _attack_points.size()) {
312 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded number of attack points: " << index << endl;
313 		return 0.0f;
314 	}
315 
316 	return _attack_points[index]->GetTotalEvadeRating();
317 }
318 
319 
320 
GetArmorEquipped(uint32 index) const321 GlobalArmor* GlobalActor::GetArmorEquipped(uint32 index) const {
322 	if (index >= _armor_equipped.size()) {
323 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded number of pieces of armor equipped: " << index << endl;
324 		return NULL;
325 	}
326 
327 	return _armor_equipped[index];
328 }
329 
330 
331 
GetAttackPoint(uint32 index) const332 GlobalAttackPoint* GlobalActor::GetAttackPoint(uint32 index) const {
333 	if (index >= _attack_points.size()) {
334 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded number of attack points: " << index << endl;
335 		return NULL;
336 	}
337 
338 	return _attack_points[index];
339 }
340 
341 
342 
GetSkill(uint32 skill_id) const343 GlobalSkill* GlobalActor::GetSkill(uint32 skill_id) const {
344 	map<uint32, GlobalSkill*>::const_iterator skill_location = _skills.find(skill_id);
345 	if (skill_location == _skills.end()) {
346 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "actor did not have a skill with the requested skill_id: " << skill_id << endl;
347 		return NULL;
348 	}
349 
350 	return skill_location->second;
351 }
352 
353 
354 
GetSkill(const GlobalSkill * skill) const355 GlobalSkill* GlobalActor::GetSkill(const GlobalSkill* skill) const {
356 	if (skill == NULL) {
357 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received a NULL pointer argument" << endl;
358 		return NULL;
359 	}
360 
361 	return GetSkill(skill->GetID());
362 }
363 
364 
365 
AddHitPoints(uint32 amount)366 void GlobalActor::AddHitPoints(uint32 amount) {
367 	if ((0xFFFFFFFF - amount) < _hit_points) {
368 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
369 		_hit_points = 0xFFFFFFFF;
370 	}
371 	else {
372 		_hit_points += amount;
373 	}
374 
375 	if (_hit_points > _max_hit_points)
376 		_hit_points = _max_hit_points;
377 }
378 
379 
380 
SubtractHitPoints(uint32 amount)381 void GlobalActor::SubtractHitPoints(uint32 amount) {
382 	if (amount >= _hit_points)
383 		_hit_points = 0;
384 	else
385 		_hit_points -= amount;
386 }
387 
388 
389 
AddMaxHitPoints(uint32 amount)390 void GlobalActor::AddMaxHitPoints(uint32 amount) {
391 	if ((0xFFFFFFFF - amount) < _max_hit_points) {
392 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
393 		_max_hit_points = 0xFFFFFFFF;
394 	}
395 	else {
396 		_max_hit_points += amount;
397 	}
398 }
399 
400 
401 
SubtractMaxHitPoints(uint32 amount)402 void GlobalActor::SubtractMaxHitPoints(uint32 amount) {
403 	if (amount > _max_hit_points) {
404 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "argument value will cause max hit points to decrease to zero: " << amount << endl;
405 		_max_hit_points = 0;
406 		_hit_points = 0;
407 	}
408 	else {
409 		_max_hit_points -= amount;
410 		if (_hit_points > _max_hit_points)
411 			_hit_points = _max_hit_points;
412 	}
413 }
414 
415 
416 
AddSkillPoints(uint32 amount)417 void GlobalActor::AddSkillPoints(uint32 amount) {
418 	if ((0xFFFFFFFF - amount) < _skill_points) {
419 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
420 		_skill_points = 0xFFFFFFFF;
421 	}
422 	else {
423 		_skill_points += amount;
424 	}
425 
426 	if (_skill_points > _max_skill_points)
427 		_skill_points = _max_skill_points;
428 }
429 
430 
431 
SubtractSkillPoints(uint32 amount)432 void GlobalActor::SubtractSkillPoints(uint32 amount) {
433 	if (amount >= _skill_points)
434 		_skill_points = 0;
435 	else
436 		_skill_points -= amount;
437 }
438 
439 
440 
AddMaxSkillPoints(uint32 amount)441 void GlobalActor::AddMaxSkillPoints(uint32 amount) {
442 	if ((0xFFFFFFFF - amount) < _max_skill_points) {
443 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
444 		_max_skill_points = 0xFFFFFFFF;
445 	}
446 	else {
447 		_max_skill_points += amount;
448 	}
449 }
450 
451 
452 
SubtractMaxSkillPoints(uint32 amount)453 void GlobalActor::SubtractMaxSkillPoints(uint32 amount) {
454 	if (amount > _max_skill_points) {
455 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "argument value will cause max skill points to decrease to zero: " << amount << endl;
456 		_max_skill_points = 0;
457 		_skill_points = 0;
458 	}
459 	else {
460 		_max_skill_points -= amount;
461 		if (_skill_points > _max_skill_points)
462 			_skill_points = _max_skill_points;
463 	}
464 }
465 
466 
467 
AddStrength(uint32 amount)468 void GlobalActor::AddStrength(uint32 amount) {
469 	if ((0xFFFFFFFF - amount) < _strength) {
470 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
471 		_strength = 0xFFFFFFFF;
472 	}
473 	else {
474 		_strength += amount;
475 	}
476 
477 	_CalculateAttackRatings();
478 }
479 
480 
481 
SubtractStrength(uint32 amount)482 void GlobalActor::SubtractStrength(uint32 amount) {
483 	if (amount >= _strength)
484 		_strength = 0;
485 	else
486 		_strength -= amount;
487 
488 	_CalculateAttackRatings();
489 }
490 
491 
492 
AddVigor(uint32 amount)493 void GlobalActor::AddVigor(uint32 amount) {
494 	if ((0xFFFFFFFF - amount) < _vigor) {
495 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
496 		_vigor = 0xFFFFFFFF;
497 	}
498 	else {
499 		_vigor += amount;
500 	}
501 
502 	_CalculateAttackRatings();
503 }
504 
505 
506 
SubtractVigor(uint32 amount)507 void GlobalActor::SubtractVigor(uint32 amount) {
508 	if (amount >= _vigor)
509 		_vigor = 0;
510 	else
511 		_vigor -= amount;
512 
513 	_CalculateAttackRatings();
514 }
515 
516 
517 
AddFortitude(uint32 amount)518 void GlobalActor::AddFortitude(uint32 amount) {
519 	if ((0xFFFFFFFF - amount) < _fortitude) {
520 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
521 		_fortitude = 0xFFFFFFFF;
522 	}
523 	else {
524 		_fortitude += amount;
525 	}
526 
527 	_CalculateDefenseRatings();
528 }
529 
530 
531 
SubtractFortitude(uint32 amount)532 void GlobalActor::SubtractFortitude(uint32 amount) {
533 	if (amount >= _fortitude)
534 		_fortitude = 0;
535 	else
536 		_fortitude -= amount;
537 
538 	_CalculateDefenseRatings();
539 }
540 
541 
542 
AddProtection(uint32 amount)543 void GlobalActor::AddProtection(uint32 amount) {
544 	if ((0xFFFFFFFF - amount) < _protection) {
545 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
546 		_protection = 0xFFFFFFFF;
547 	}
548 	else {
549 		_protection += amount;
550 	}
551 
552 	_CalculateDefenseRatings();
553 }
554 
555 
556 
SubtractProtection(uint32 amount)557 void GlobalActor::SubtractProtection(uint32 amount) {
558 	if (amount >= _protection)
559 		_protection = 0;
560 	else
561 		_protection -= amount;
562 
563 	_CalculateDefenseRatings();
564 }
565 
566 
567 
AddAgility(uint32 amount)568 void GlobalActor::AddAgility(uint32 amount)  {
569 	if ((0xFFFFFFFF - amount) < _agility) {
570 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "integer overflow condition detected: " << amount << endl;
571 		_agility = 0xFFFFFFFF;
572 	}
573 	else {
574 		_agility += amount;
575 	}
576 }
577 
578 
579 
SubtractAgility(uint32 amount)580 void GlobalActor::SubtractAgility(uint32 amount) {
581 	if (amount >= _agility)
582 		_agility = 0;
583 	else
584 		_agility -= amount;
585 }
586 
587 
588 
AddEvade(float amount)589 void GlobalActor::AddEvade(float amount) {
590 	if (amount < 0.0f) {
591 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received negative argument value: " << amount << endl;
592 		return;
593 	}
594 
595 	float new_evade = _evade + amount;
596 	if (new_evade < _evade) {
597 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "floating point overflow condition detected: " << amount << endl;
598 		_evade = 1.0f;
599 	}
600 	else if (new_evade > 1.0f) {
601 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "evade rating increased above 1.0f: " << amount << endl;
602 		_evade = 1.0f;
603 	}
604 	else {
605 		_evade = new_evade;
606 	}
607 
608 	_CalculateEvadeRatings();
609 }
610 
611 
612 
SubtractEvade(float amount)613 void GlobalActor::SubtractEvade(float amount) {
614 	if (amount > 0.0f) {
615 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received positive argument value: " << amount << endl;
616 		return;
617 	}
618 
619 	float new_evade = _evade + amount;
620 	if (new_evade > _evade) {
621 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "floating point overflow condition detected: " << amount << endl;
622 		_evade = 0.0f;
623 	}
624 	else if (new_evade < 0.0f) {
625 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "evade rating decreased below 0.0f: " << amount << endl;
626 		_evade = 0.0f;
627 	}
628 	else {
629 		_evade = new_evade;
630 	}
631 
632 	_CalculateEvadeRatings();
633 }
634 
635 
636 
_CalculateAttackRatings()637 void GlobalActor::_CalculateAttackRatings() {
638 	_total_physical_attack = _strength;
639 	_total_metaphysical_attack = _vigor;
640 
641 	if (_weapon_equipped != NULL) {
642 		_total_physical_attack += _weapon_equipped->GetPhysicalAttack();
643 		_total_metaphysical_attack += _weapon_equipped->GetMetaphysicalAttack();
644 	}
645 }
646 
647 
648 
_CalculateDefenseRatings()649 void GlobalActor::_CalculateDefenseRatings() {
650 	// Re-calculate the defense ratings for all attack points
651 	for (uint32 i = 0; i < _attack_points.size(); i++) {
652 		if ((i < _armor_equipped.size()) && (_armor_equipped[i] != NULL))
653 			_attack_points[i]->CalculateTotalDefense(_armor_equipped[i]);
654 		else
655 			_attack_points[i]->CalculateTotalDefense(NULL);
656 	}
657 }
658 
659 
660 
_CalculateEvadeRatings()661 void GlobalActor::_CalculateEvadeRatings() {
662 	// Re-calculate the evade ratings for all attack points
663 	for (uint32 i = 0; i < _attack_points.size(); i++) {
664 		_attack_points[i]->CalculateTotalEvade();
665 	}
666 }
667 
668 ////////////////////////////////////////////////////////////////////////////////
669 // GlobalCharacterGrowth class
670 ////////////////////////////////////////////////////////////////////////////////
671 
GlobalCharacterGrowth(GlobalCharacter * owner)672 GlobalCharacterGrowth::GlobalCharacterGrowth(GlobalCharacter* owner) :
673 	_character_owner(owner),
674 	_experience_level_gained(false),
675 	_growth_detected(false),
676 	_experience_for_next_level(0),
677 	_experience_for_last_level(0),
678 	_hit_points_growth(0),
679 	_skill_points_growth(0),
680 	_strength_growth(0),
681 	_vigor_growth(0),
682 	_fortitude_growth(0),
683 	_protection_growth(0),
684 	_agility_growth(0),
685 	_evade_growth(0.0f)
686 {}
687 
688 
689 
~GlobalCharacterGrowth()690 GlobalCharacterGrowth::~GlobalCharacterGrowth() {
691 	for (uint32 i = 0; i < _skills_learned.size(); i++)
692 		delete _skills_learned[i];
693 	_skills_learned.clear();
694 }
695 
696 
697 
AcknowledgeGrowth()698 void GlobalCharacterGrowth::AcknowledgeGrowth() {
699 	if (_growth_detected == false) {
700 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function was invoked when there was no character growth detected" << endl;
701 		return;
702 	}
703 
704 	_growth_detected = false;
705 
706 	// Add all growth stats to the character actor
707 	if (_hit_points_growth != 0) {
708 		_character_owner->AddMaxHitPoints(_hit_points_growth);
709 		_character_owner->AddHitPoints(_hit_points_growth);
710 	}
711 	if (_skill_points_growth != 0) {
712 		_character_owner->AddMaxSkillPoints(_skill_points_growth);
713 		_character_owner->AddSkillPoints(_skill_points_growth);
714 	}
715 	if (_strength_growth != 0)
716 		_character_owner->AddStrength(_strength_growth);
717 	if (_vigor_growth != 0)
718 		_character_owner->AddVigor(_vigor_growth);
719 	if (_fortitude_growth != 0)
720 		_character_owner->AddFortitude(_fortitude_growth);
721 	if (_protection_growth != 0)
722 		_character_owner->AddProtection(_protection_growth);
723 	if (_agility_growth != 0)
724 		_character_owner->AddAgility(_agility_growth);
725 	if (IsFloatEqual(_evade_growth, 0.0f) == false)
726 		_character_owner->AddEvade(_evade_growth);
727 
728 	_hit_points_growth = 0;
729 	_skill_points_growth = 0;
730 	_strength_growth = 0;
731 	_vigor_growth = 0;
732 	_fortitude_growth = 0;
733 	_protection_growth = 0;
734 	_agility_growth = 0;
735 	_evade_growth = 0.0f;
736 
737 	// If a new experience level has been gained, we must retrieve the growth data for the new experience level
738 	if (_experience_level_gained) {
739 		_character_owner->_experience_level += 1;
740 		_experience_level_gained = false;
741 		_DetermineNextLevelExperience();
742 
743 		string filename = "dat/actors/characters.lua";
744 		ReadScriptDescriptor character_script;
745 		if (character_script.OpenFile(filename) == false) {
746 			IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to open character data file: " << filename << endl;
747 			return;
748 		}
749 
750 		try {
751 			ScriptCallFunction<void>(character_script.GetLuaState(), "DetermineGrowth", _character_owner);
752 			_ConstructPeriodicGrowth();
753 			_CheckForGrowth();
754 		}
755 		catch (luabind::error e) {
756 			ScriptManager->HandleLuaError(e);
757 		}
758 		catch (luabind::cast_failed e) {
759 			ScriptManager->HandleCastError(e);
760 		}
761 
762 		character_script.CloseFile();
763 
764 		// Add any newly learned skills
765 		for (uint32 i = 0; i < _skills_learned.size(); i++) {
766 			GlobalSkill* skill = _skills_learned[i];
767 			if (_character_owner->_skills.find(skill->GetID()) != _character_owner->_skills.end()) {
768 				IF_PRINT_WARNING(GLOBAL_DEBUG) << "character had already learned the skill with the id: " << skill->GetID() << endl;
769 				delete _skills_learned[i];
770 				continue;
771 			}
772 
773 			// Insert the pointer to the new skill inside of the global skills map and the skill type vector
774 			_character_owner->_skills.insert(make_pair(skill->GetID(), skill));
775 			switch (skill->GetType()) {
776 				case GLOBAL_SKILL_ATTACK:
777 					_character_owner->_attack_skills.push_back(skill);
778 					break;
779 				case GLOBAL_SKILL_DEFEND:
780 					_character_owner->_defense_skills.push_back(skill);
781 					break;
782 				case GLOBAL_SKILL_SUPPORT:
783 					_character_owner->_support_skills.push_back(skill);
784 					break;
785 				default:
786 					IF_PRINT_WARNING(GLOBAL_DEBUG) << "newly learned skill had an unknown skill type: " << skill->GetType() << endl;
787 					break;
788 			}
789 		}
790 		// skills have been given out, clean out the vector
791 		//CD: Negatory!  Leeave the vector as is.  I need it in order to display the
792 		// correct stuff in the skills learned window in FinishWindow.  I will clear it
793 		// myself from there.  Not only that, but if they level up multiple times, I need
794 		// to save the whole list so I can show all the skills they learned across
795 		// multiple levels.  If this were called, they would never know they learned a skill
796 		// at level 3 because they jumped to level 4 in the same battle
797 		//_skills_learned.clear();
798 	} // if (_experience_level_gained)
799 } // void GlobalCharacterGrowth::AcknowledgeGrowth()
800 
801 
802 
_AddSkill(uint32 skill_id)803 void GlobalCharacterGrowth::_AddSkill(uint32 skill_id) {
804 	if (skill_id == 0) {
805 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received an invalid skill_id argument: " << skill_id << endl;
806 		return;
807 	}
808 	// Make sure we don't add a skill to learn more than once
809 	for (vector<GlobalSkill*>::iterator i = _skills_learned.begin(); i != _skills_learned.end(); i++) {
810 		if (skill_id == (*i)->GetID()) {
811 			IF_PRINT_WARNING(GLOBAL_DEBUG) << "the skill to add was already present in the list of skills to learn: " << skill_id << endl;
812 			return;
813 		}
814 	}
815 
816 	GlobalSkill* skill = new GlobalSkill(skill_id);
817 	if (skill->IsValid() == false) {
818 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "the skill to add failed to load: " << skill_id << endl;
819 		delete skill;
820 	}
821 	else {
822 		_skills_learned.push_back(skill);
823 	}
824 }
825 
826 
827 
_CheckForGrowth()828 void GlobalCharacterGrowth::_CheckForGrowth() {
829 	// ----- (1): If a new experience level is gained, empty the periodic growth containers into the growth members
830 	if (_character_owner->GetExperiencePoints() >= _experience_for_next_level) {
831 		_experience_level_gained = true;
832 		_growth_detected = true;
833 
834 		for (uint32 i = 0; i < _hit_points_periodic_growth.size(); i++)
835 			_hit_points_growth += _hit_points_periodic_growth[i].second;
836 		_hit_points_periodic_growth.clear();
837 
838 		for (uint32 i = 0; i < _skill_points_periodic_growth.size(); i++)
839 			_skill_points_growth += _skill_points_periodic_growth[i].second;
840 		_skill_points_periodic_growth.clear();
841 
842 		for (uint32 i = 0; i < _strength_periodic_growth.size(); i++)
843 			_strength_growth += _strength_periodic_growth[i].second;
844 		_strength_periodic_growth.clear();
845 
846 		for (uint32 i = 0; i < _vigor_periodic_growth.size(); i++)
847 			_vigor_growth += _vigor_periodic_growth[i].second;
848 		_vigor_periodic_growth.clear();
849 
850 		for (uint32 i = 0; i < _fortitude_periodic_growth.size(); i++)
851 			_fortitude_growth += _fortitude_periodic_growth[i].second;
852 		_fortitude_periodic_growth.clear();
853 
854 		for (uint32 i = 0; i < _protection_periodic_growth.size(); i++)
855 			_protection_growth += _protection_periodic_growth[i].second;
856 		_protection_periodic_growth.clear();
857 
858 		for (uint32 i = 0; i < _agility_periodic_growth.size(); i++)
859 			_agility_growth += _agility_periodic_growth[i].second;
860 		_agility_periodic_growth.clear();
861 
862 		for (uint32 i = 0; i < _evade_periodic_growth.size(); i++)
863 			_evade_growth += _evade_periodic_growth[i].second;
864 		_evade_periodic_growth.clear();
865 
866 
867 		return;
868 	} // if (_actor_ower->GetExperiencePoints() >= _experience_for_next_level)
869 
870 	// ----- (2): If there is no growth detected, check all periodic growth containers
871 	switch (_growth_detected) { // switch statement used instead of if statement here so we can break out of it early
872 		case true:
873 			break;
874 		case false:
875 			if (_hit_points_periodic_growth.empty() == false) {
876 				if (_character_owner->GetExperiencePoints() >= _hit_points_periodic_growth.front().first) {
877 					_growth_detected = true;
878 					break;
879 				}
880 			}
881 
882 			if (_skill_points_periodic_growth.empty() == false) {
883 				if (_character_owner->GetExperiencePoints() >= _skill_points_periodic_growth.front().first) {
884 					_growth_detected = true;
885 					break;
886 				}
887 			}
888 
889 			if (_strength_periodic_growth.empty() == false) {
890 				if (_character_owner->GetExperiencePoints() >= _strength_periodic_growth.front().first) {
891 					_growth_detected = true;
892 					break;
893 				}
894 			}
895 
896 			if (_vigor_periodic_growth.empty() == false) {
897 				if (_character_owner->GetExperiencePoints() >= _vigor_periodic_growth.front().first) {
898 					_growth_detected = true;
899 					break;
900 				}
901 			}
902 
903 			if (_fortitude_periodic_growth.empty() == false) {
904 				if (_character_owner->GetExperiencePoints() >= _fortitude_periodic_growth.front().first) {
905 					_growth_detected = true;
906 					break;
907 				}
908 			}
909 
910 			if (_protection_periodic_growth.empty() == false) {
911 				if (_character_owner->GetExperiencePoints() >= _protection_periodic_growth.front().first) {
912 					_growth_detected = true;
913 					break;
914 				}
915 			}
916 
917 			if (_agility_periodic_growth.empty() == false) {
918 				if (_character_owner->GetExperiencePoints() >= _agility_periodic_growth.front().first) {
919 					_growth_detected = true;
920 					break;
921 				}
922 			}
923 
924 			if (_evade_periodic_growth.empty() == false) {
925 				if (_character_owner->GetExperiencePoints() >= _evade_periodic_growth.front().first) {
926 					_growth_detected = true;
927 					break;
928 				}
929 			}
930 			break;
931 	} // switch (_growth_detected)
932 
933 	// ----- (3): If there is growth detected update all periodic growth containers
934 	if (_growth_detected == true) {
935 		while (_hit_points_periodic_growth.begin() != _hit_points_periodic_growth.end()) {
936 			if (_character_owner->GetExperiencePoints() >= _hit_points_periodic_growth.begin()->first) {
937 				_hit_points_growth += _hit_points_periodic_growth.begin()->second;
938 				_hit_points_periodic_growth.pop_front();
939 			}
940 			else {
941 				break;
942 			}
943 		}
944 
945 		while (_skill_points_periodic_growth.begin() != _skill_points_periodic_growth.end()) {
946 			if (_character_owner->GetExperiencePoints() >= _skill_points_periodic_growth.begin()->first) {
947 				_skill_points_growth += _skill_points_periodic_growth.begin()->second;
948 				_skill_points_periodic_growth.pop_front();
949 			}
950 			else {
951 				break;
952 			}
953 		}
954 
955 		while (_strength_periodic_growth.begin() != _strength_periodic_growth.end()) {
956 			if (_character_owner->GetExperiencePoints() >= _strength_periodic_growth.begin()->first) {
957 				_strength_growth += _strength_periodic_growth.begin()->second;
958 				_strength_periodic_growth.pop_front();
959 			}
960 			else {
961 				break;
962 			}
963 		}
964 
965 		while (_vigor_periodic_growth.begin() != _vigor_periodic_growth.end()) {
966 			if (_character_owner->GetExperiencePoints() >= _vigor_periodic_growth.begin()->first) {
967 				_vigor_growth += _vigor_periodic_growth.begin()->second;
968 				_vigor_periodic_growth.pop_front();
969 			}
970 			else {
971 				break;
972 			}
973 		}
974 
975 		while (_fortitude_periodic_growth.begin() != _fortitude_periodic_growth.end()) {
976 			if (_character_owner->GetExperiencePoints() >= _fortitude_periodic_growth.begin()->first) {
977 				_fortitude_growth += _fortitude_periodic_growth.begin()->second;
978 				_fortitude_periodic_growth.pop_front();
979 			}
980 			else {
981 				break;
982 			}
983 		}
984 
985 		while (_protection_periodic_growth.begin() != _protection_periodic_growth.end()) {
986 			if (_character_owner->GetExperiencePoints() >= _protection_periodic_growth.begin()->first) {
987 				_protection_growth += _protection_periodic_growth.begin()->second;
988 				_protection_periodic_growth.pop_front();
989 			}
990 			else {
991 				break;
992 			}
993 		}
994 
995 		while (_agility_periodic_growth.begin() != _agility_periodic_growth.end()) {
996 			if (_character_owner->GetExperiencePoints() >= _agility_periodic_growth.begin()->first) {
997 				_agility_growth += _agility_periodic_growth.begin()->second;
998 				_agility_periodic_growth.pop_front();
999 			}
1000 			else {
1001 				break;
1002 			}
1003 		}
1004 
1005 		while (_evade_periodic_growth.begin() != _evade_periodic_growth.end()) {
1006 			if (_character_owner->GetExperiencePoints() >= _evade_periodic_growth.begin()->first) {
1007 				_evade_growth += _evade_periodic_growth.begin()->second;
1008 				_evade_periodic_growth.pop_front();
1009 			}
1010 			else {
1011 				break;
1012 			}
1013 		}
1014 	} // if (_growth_detected == true)
1015 } // void GlobalCharacterGrowth::_CheckForGrowth()
1016 
1017 
1018 
_ConstructPeriodicGrowth()1019 void GlobalCharacterGrowth::_ConstructPeriodicGrowth() {
1020 	// TODO: Implement a gradual growth algorithm
1021 
1022 	// TEMP: all growth is done when the experience level is gained
1023 	_hit_points_periodic_growth.push_back(make_pair(_experience_for_next_level, _hit_points_growth));
1024 	_skill_points_periodic_growth.push_back(make_pair(_experience_for_next_level, _skill_points_growth));
1025 	_strength_periodic_growth.push_back(make_pair(_experience_for_next_level, _strength_growth));
1026 	_vigor_periodic_growth.push_back(make_pair(_experience_for_next_level, _vigor_growth));
1027 	_fortitude_periodic_growth.push_back(make_pair(_experience_for_next_level, _fortitude_growth));
1028 	_protection_periodic_growth.push_back(make_pair(_experience_for_next_level, _protection_growth));
1029 	_agility_periodic_growth.push_back(make_pair(_experience_for_next_level, _agility_growth));
1030 	_evade_periodic_growth.push_back(make_pair(_experience_for_next_level, _evade_growth));
1031 
1032 	_hit_points_growth = 0;
1033 	_skill_points_growth = 0;
1034 	_strength_growth = 0;
1035 	_vigor_growth = 0;
1036 	_fortitude_growth = 0;
1037 	_protection_growth = 0;
1038 	_agility_growth = 0;
1039 	_evade_growth = 0.0f;
1040 }
1041 
1042 
1043 
_DetermineNextLevelExperience()1044 void GlobalCharacterGrowth::_DetermineNextLevelExperience() {
1045 	uint32 base_xp = 0;
1046 	uint32 new_xp = 0;
1047 
1048 	// TODO: implement a real algorithm for determining the next experience goal
1049 	base_xp = _character_owner->GetExperienceLevel() * 40;
1050 	new_xp = GaussianRandomValue(base_xp, base_xp / 10.0f);
1051 
1052 	_experience_for_last_level = _experience_for_next_level;
1053 	_experience_for_next_level = new_xp;
1054 }
1055 
1056 ////////////////////////////////////////////////////////////////////////////////
1057 // GlobalCharacter class
1058 ////////////////////////////////////////////////////////////////////////////////
1059 
GlobalCharacter(uint32 id,bool initial)1060 GlobalCharacter::GlobalCharacter(uint32 id, bool initial) :
1061 	_growth(this)
1062 {
1063 	_id = id;
1064 
1065 	// ----- (1): Open the characters script file
1066 	string filename = "dat/actors/characters.lua";
1067 	ReadScriptDescriptor char_script;
1068 	if (char_script.OpenFile(filename) == false) {
1069 		PRINT_ERROR << "failed to open character data file: " << filename << endl;
1070 		return;
1071 	}
1072 
1073 	// ----- (2): Retrieve their basic character property data
1074 	char_script.OpenTable("characters");
1075 	char_script.OpenTable(_id);
1076 	_name = MakeUnicodeString(char_script.ReadString("name"));
1077 	_filename = char_script.ReadString("filename");
1078 
1079 	// ----- (3): Construct the character from the initial stats if necessary
1080 	if (initial == true) {
1081 		char_script.OpenTable("initial_stats");
1082 		_experience_level = char_script.ReadUInt("experience_level");
1083 		_experience_points = char_script.ReadUInt("experience_points");
1084 		_max_hit_points = char_script.ReadUInt("max_hit_points");
1085 		_hit_points = _max_hit_points;
1086 		_max_skill_points = char_script.ReadUInt("max_skill_points");
1087 		_skill_points = _max_skill_points;
1088 		_strength = char_script.ReadUInt("strength");
1089 		_vigor = char_script.ReadUInt("vigor");
1090 		_fortitude = char_script.ReadUInt("fortitude");
1091 		_protection = char_script.ReadUInt("protection");
1092 		_agility = char_script.ReadUInt("agility");
1093 		_evade = char_script.ReadFloat("evade");
1094 
1095 		// Add the character's initial equipment. If any equipment ids are zero, that indicates nothing is to be equipped.
1096 		uint32 equipment_id = 0;
1097 		equipment_id = char_script.ReadUInt("weapon");
1098 		if (equipment_id != 0)
1099 			_weapon_equipped = new GlobalWeapon(equipment_id);
1100 		else
1101 			_weapon_equipped = NULL;
1102 
1103 		equipment_id = char_script.ReadUInt("head_armor");
1104 		if (equipment_id != 0)
1105 			_armor_equipped.push_back(new GlobalArmor(equipment_id));
1106 		else
1107 			_armor_equipped.push_back(NULL);
1108 
1109 		equipment_id = char_script.ReadUInt("torso_armor");
1110 		if (equipment_id != 0)
1111 			_armor_equipped.push_back(new GlobalArmor(equipment_id));
1112 		else
1113 			_armor_equipped.push_back(NULL);
1114 
1115 		equipment_id = char_script.ReadUInt("arm_armor");
1116 		if (equipment_id != 0)
1117 			_armor_equipped.push_back(new GlobalArmor(equipment_id));
1118 		else
1119 			_armor_equipped.push_back(NULL);
1120 
1121 		equipment_id = char_script.ReadUInt("leg_armor");
1122 		if (equipment_id != 0)
1123 			_armor_equipped.push_back(new GlobalArmor(equipment_id));
1124 		else
1125 			_armor_equipped.push_back(NULL);
1126 
1127 		char_script.CloseTable();
1128 		if (char_script.IsErrorDetected()) {
1129 			if (GLOBAL_DEBUG) {
1130 				PRINT_WARNING << "one or more errors occurred while reading initial data - they are listed below" << endl;
1131 				cerr << char_script.GetErrorMessages() << endl;
1132 			}
1133 		}
1134 	} // if (initial == true)
1135 	else {
1136 		 // Make sure the _armor_equipped vector is sized appropriately
1137 		_armor_equipped.resize(4, NULL);
1138 	}
1139 
1140 	// ----- (4): Setup the character's attack points
1141 	char_script.OpenTable("attack_points");
1142 	for (uint32 i = GLOBAL_POSITION_HEAD; i <= GLOBAL_POSITION_LEGS; i++) {
1143 		_attack_points.push_back(new GlobalAttackPoint(this));
1144 		char_script.OpenTable(i);
1145 		if (_attack_points[i]->LoadData(char_script) == false) {
1146 			IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to succesfully load data for attack point: " << i << endl;
1147 		}
1148 		char_script.CloseTable();
1149 	}
1150 	char_script.CloseTable();
1151 
1152 	if (char_script.IsErrorDetected()) {
1153 		if (GLOBAL_DEBUG) {
1154 			PRINT_WARNING << "one or more errors occurred while reading attack point data - they are listed below" << endl;
1155 			cerr << char_script.GetErrorMessages() << endl;
1156 		}
1157 	}
1158 
1159 	// ----- (5): Construct the character's initial skill set if necessary
1160 	if (initial) {
1161 		// The skills table contains key/value pairs. The key indicate the level required to learn the skill and the value is the skill's id
1162 		uint32 skill_id;
1163 		vector<uint32> skill_levels;
1164 		char_script.OpenTable("skills");
1165 		char_script.ReadTableKeys(skill_levels);
1166 
1167 		// Only add the skills for which the experience level requirements are met
1168 		for (uint32 i = 0; i < skill_levels.size(); i++) {
1169 			skill_id = char_script.ReadUInt(skill_levels[i]);
1170 			if (skill_levels[i] <= _experience_level) {
1171 				AddSkill(skill_id);
1172 			}
1173 		}
1174 
1175 		char_script.CloseTable();
1176 		if (char_script.IsErrorDetected()) {
1177 			if (GLOBAL_DEBUG) {
1178 				PRINT_WARNING << "one or more errors occurred while reading skill data - they are listed below" << endl;
1179 				cerr << char_script.GetErrorMessages() << endl;
1180 			}
1181 		}
1182 	} // if (initial)
1183 
1184 	char_script.CloseTable(); // "characters[id]"
1185 	char_script.CloseTable(); // "characters"
1186 
1187 	// ----- (6): Determine the character's initial growth if necessary
1188 	if (initial) {
1189 		// Initialize the experience level milestones
1190 		_growth._experience_for_last_level = _experience_points;
1191 		_growth._experience_for_next_level = _experience_points;
1192 		_growth._DetermineNextLevelExperience();
1193 		try {
1194 			ScriptCallFunction<void>(char_script.GetLuaState(), "DetermineGrowth", this);
1195 			_growth._ConstructPeriodicGrowth();
1196 		}
1197 		catch (luabind::error e) {
1198 			ScriptManager->HandleLuaError(e);
1199 		}
1200 		catch (luabind::cast_failed e) {
1201 			ScriptManager->HandleCastError(e);
1202 		}
1203 	}
1204 
1205 	// ----- (7): Close the script file and calculate all rating totals
1206 	if (char_script.IsErrorDetected()) {
1207 		if (GLOBAL_DEBUG) {
1208 			PRINT_WARNING << "one or more errors occurred while reading final data - they are listed below" << endl;
1209 			cerr << char_script.GetErrorMessages() << endl;
1210 		}
1211 	}
1212 	char_script.CloseFile();
1213 
1214 	_CalculateAttackRatings();
1215 	_CalculateDefenseRatings();
1216 	_CalculateEvadeRatings();
1217 
1218 	// ----- (8) Load character sprite and portrait images
1219 	// NOTE: The code below is all TEMP and is subject to great change or removal in the future
1220 	// TEMP: load standard map sprite walking frames
1221 	if (ImageDescriptor::LoadMultiImageFromElementGrid(_map_frames_standard, "img/sprites/map/" + _filename + "_walk.png", 4, 6) == false) {
1222 		exit(1);
1223 	}
1224 
1225 	// TEMP: Load the character's idle animation
1226 	AnimatedImage idle;
1227 	idle.SetDimensions(96, 96);
1228 	vector<uint32> idle_timings(4, 15);
1229 
1230 	if (idle.LoadFromFrameGrid("img/sprites/map/" + _filename + "_idle.png", idle_timings, 1, 4) == false) {
1231 		exit(1);
1232 	}
1233 	_battle_animation["idle"] = idle;
1234 
1235 	// TEMP: Load the character's attack animation
1236 	AnimatedImage attack;
1237 	attack.SetDimensions(96, 96);
1238 	vector<uint32> attack_timings(5, 5);
1239 
1240 	if (attack.LoadFromFrameGrid("img/sprites/map/" + _filename + "_attack.png", attack_timings, 1, 5) == false) {
1241 		exit(1);
1242 	}
1243 	_battle_animation["attack"] = attack;
1244 
1245 	// TEMP: Load the character's battle portraits from a multi image
1246 	_battle_portraits.assign(5, StillImage());
1247 	for (uint32 i = 0; i < _battle_portraits.size(); i++) {
1248 		_battle_portraits[i].SetDimensions(100, 100);
1249 	}
1250 	if (ImageDescriptor::LoadMultiImageFromElementGrid(_battle_portraits, "img/portraits/battle/" + _filename + "_damage.png", 1, 5) == false)
1251 		exit(1);
1252 } // GlobalCharacter::GlobalCharacter(uint32 id, bool initial)
1253 
1254 
1255 
AddExperiencePoints(uint32 xp)1256 bool GlobalCharacter::AddExperiencePoints(uint32 xp) {
1257 	_experience_points += xp;
1258 	_growth._CheckForGrowth();
1259 	return _growth.IsGrowthDetected();
1260 }
1261 
1262 
1263 
AddSkill(uint32 skill_id)1264 void GlobalCharacter::AddSkill(uint32 skill_id) {
1265 	if (skill_id == 0) {
1266 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received an invalid skill_id argument: " << skill_id << endl;
1267 		return;
1268 	}
1269 	if (_skills.find(skill_id) != _skills.end()) {
1270 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to add skill because the character already knew this skill: " << skill_id << endl;
1271 		return;
1272 	}
1273 
1274 	GlobalSkill* skill = new GlobalSkill(skill_id);
1275 	if (skill->IsValid() == false) {
1276 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "the skill to add failed to load: " << skill_id << endl;
1277 		delete skill;
1278 		return;
1279 	}
1280 
1281 	// Insert the pointer to the new skill inside of the global skills map and the skill type vector
1282 	_skills.insert(make_pair(skill_id, skill));
1283 	switch (skill->GetType()) {
1284 		case GLOBAL_SKILL_ATTACK:
1285 			_attack_skills.push_back(skill);
1286 			break;
1287 		case GLOBAL_SKILL_DEFEND:
1288 			_defense_skills.push_back(skill);
1289 			break;
1290 		case GLOBAL_SKILL_SUPPORT:
1291 			_support_skills.push_back(skill);
1292 			break;
1293 		default:
1294 			IF_PRINT_WARNING(GLOBAL_DEBUG) << "loaded a new skill with an unknown skill type: " << skill->GetType() << endl;
1295 			break;
1296 	}
1297 }
1298 
1299 ////////////////////////////////////////////////////////////////////////////////
1300 // GlobalEnemy class
1301 ////////////////////////////////////////////////////////////////////////////////
1302 
GlobalEnemy(uint32 id)1303 GlobalEnemy::GlobalEnemy(uint32 id) :
1304 	GlobalActor(),
1305 	_growth_hit_points(0.0f),
1306 	_growth_skill_points(0.0f),
1307 	_growth_experience_points(0.0f),
1308 	_growth_strength(0.0f),
1309 	_growth_vigor(0.0f),
1310 	_growth_fortitude(0.0f),
1311 	_growth_protection(0.0f),
1312 	_growth_agility(0.0f),
1313 	_growth_evade(0.0f),
1314 	_growth_drunes(0.0f),
1315 	_drunes_dropped(0),
1316 	_sprite_width(0),
1317 	_sprite_height(0)
1318 {
1319 	_id = id;
1320 
1321 	// ----- (1): Use the id member to determine the name of the data file that the enemy is defined in
1322 	string file_ext;
1323 	string filename;
1324 
1325 	if (_id == 0)
1326 		PRINT_ERROR << "invalid id for loading enemy data: " << _id << endl;
1327 	else if ((_id > 0) && (_id <= 100))
1328 		file_ext = "01";
1329 	else if ((_id > 100) && (_id <= 200))
1330 		file_ext = "02";
1331 
1332 	filename = "dat/actors/enemies_set_" + file_ext + ".lua";
1333 
1334 	// ----- (2): Open the script file and table that store the enemy data
1335 	ReadScriptDescriptor enemy_data;
1336 	if (enemy_data.OpenFile(filename) == false) {
1337 		PRINT_ERROR << "failed to open enemy data file: " << filename << endl;
1338 		return;
1339 	}
1340 
1341 	enemy_data.OpenTable("enemies");
1342 	enemy_data.OpenTable(_id);
1343 
1344 	// ----- (3): Load the enemy's name and sprite data
1345 	_name = MakeUnicodeString(enemy_data.ReadString("name"));
1346 	_filename = enemy_data.ReadString("filename");
1347 	_sprite_width = enemy_data.ReadInt("sprite_width");
1348 	_sprite_height = enemy_data.ReadInt("sprite_height");
1349 
1350 	// ----- (4): Attempt to load the MultiImage for the sprite's frames, which should contain one row and four columns of images
1351 	_battle_sprite_frames.assign(4, StillImage());
1352 	string sprite_filename = "img/sprites/battle/enemies/" + _filename + ".png";
1353 	if (ImageDescriptor::LoadMultiImageFromElementGrid(_battle_sprite_frames, sprite_filename, 1, 4) == false) {
1354 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to load sprite frames for enemy: " << sprite_filename << endl;
1355 	}
1356 
1357 	// ----- (5): Load the enemy's initial stats
1358 	enemy_data.OpenTable("initial_stats");
1359 	_max_hit_points = enemy_data.ReadUInt("hit_points");
1360 	_hit_points = _max_hit_points;
1361 	_max_skill_points = enemy_data.ReadUInt("skill_points");
1362 	_skill_points = _max_skill_points;
1363 	_experience_points = enemy_data.ReadUInt("experience_points");
1364 	_strength = enemy_data.ReadUInt("strength");
1365 	_vigor = enemy_data.ReadUInt("vigor");
1366 	_fortitude = enemy_data.ReadUInt("fortitude");
1367 	_protection = enemy_data.ReadUInt("protection");
1368 	_agility = enemy_data.ReadUInt("agility");
1369 	_evade = enemy_data.ReadFloat("evade");
1370 	_drunes_dropped = enemy_data.ReadUInt("drunes");
1371 	enemy_data.CloseTable();
1372 
1373 	// ----- (6): Load the enemy's growth statistics
1374 	enemy_data.OpenTable("growth_stats");
1375 	_growth_hit_points = enemy_data.ReadFloat("hit_points");
1376 	_growth_skill_points = enemy_data.ReadFloat("skill_points");
1377 	_growth_experience_points = enemy_data.ReadFloat("experience_points");
1378 	_growth_strength = enemy_data.ReadFloat("strength");
1379 	_growth_vigor = enemy_data.ReadFloat("vigor");
1380 	_growth_fortitude = enemy_data.ReadFloat("fortitude");
1381 	_growth_protection = enemy_data.ReadFloat("protection");
1382 	_growth_agility = enemy_data.ReadFloat("agility");
1383 	_growth_evade = enemy_data.ReadFloat("evade");
1384 	_growth_drunes = enemy_data.ReadFloat("drunes");
1385 	enemy_data.CloseTable();
1386 
1387 	// ----- (7): Create the attack points for the enemy
1388 	enemy_data.OpenTable("attack_points");
1389 	uint32 ap_size = enemy_data.GetTableSize();
1390 	for (uint32 i = 1; i <= ap_size; i++) {
1391 		_attack_points.push_back(new GlobalAttackPoint(this));
1392 		enemy_data.OpenTable(i);
1393 		if (_attack_points.back()->LoadData(enemy_data) == false) {
1394 			IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to load data for an attack point: " << i << endl;
1395 		}
1396 		enemy_data.CloseTable();
1397 	}
1398 	enemy_data.CloseTable();
1399 
1400 	// ----- (8): Add the set of skills to the enemy
1401 	vector<int32> skill_levels;
1402 	enemy_data.OpenTable("skills");
1403 	enemy_data.ReadTableKeys(skill_levels);
1404 	for (uint32 i = 0; i < skill_levels.size(); i++) {
1405 		uint32 skill_id = enemy_data.ReadUInt(skill_levels[i]);
1406 		_skill_set[skill_id] = skill_levels[i];
1407 	}
1408 	enemy_data.CloseTable();
1409 
1410 	// ----- (9): Load the possible items that the enemy may drop
1411 	enemy_data.OpenTable("drop_objects");
1412 	for (uint32 i = 1; i <= enemy_data.GetTableSize(); i++) {
1413 		enemy_data.OpenTable(i);
1414 		_dropped_objects.push_back(enemy_data.ReadUInt(1));
1415 		_dropped_chance.push_back(enemy_data.ReadFloat(2));
1416 		_dropped_level_required.push_back(enemy_data.ReadUInt(3));
1417 		enemy_data.CloseTable();
1418 	}
1419 	enemy_data.CloseTable();
1420 
1421 	enemy_data.CloseTable(); // enemies[_id]
1422 	enemy_data.CloseTable(); // enemies
1423 
1424 	if (enemy_data.IsErrorDetected()) {
1425 		if (GLOBAL_DEBUG) {
1426 			PRINT_WARNING << "one or more errors occurred while reading the enemy data - they are listed below" << endl;
1427 			cerr << enemy_data.GetErrorMessages() << endl;
1428 		}
1429 	}
1430 
1431 	enemy_data.CloseFile();
1432 
1433 	_CalculateAttackRatings();
1434 	_CalculateDefenseRatings();
1435 	_CalculateEvadeRatings();
1436 } // GlobalEnemy::GlobalEnemy(uint32 id)
1437 
1438 
1439 
AddSkill(uint32 skill_id)1440 void GlobalEnemy::AddSkill(uint32 skill_id) {
1441 	if (skill_id == 0) {
1442 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received an invalid skill_id argument: " << skill_id << endl;
1443 		return;
1444 	}
1445 	if (_skills.find(skill_id) != _skills.end()) {
1446 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to add skill because the enemy already knew this skill: " << skill_id << endl;
1447 		return;
1448 	}
1449 
1450 	GlobalSkill* skill = new GlobalSkill(skill_id);
1451 	if (skill->IsValid() == false) {
1452 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "the skill to add failed to load: " << skill_id << endl;
1453 		delete skill;
1454 		return;
1455 	}
1456 
1457 	// Insert the pointer to the new skill inside of the global skills map and the skill type vector
1458 	_skills.insert(make_pair(skill_id, skill));
1459 }
1460 
1461 
1462 
Initialize(uint32 xp_level)1463 void GlobalEnemy::Initialize(uint32 xp_level) {
1464 	if (xp_level == 0) {
1465 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received an invalid xp_level argument of 0: " << _id << endl;
1466 		return;
1467 	}
1468 	if (_skills.empty() == false) { // Indicates that the enemy has already been initialized
1469 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function was invoked for an already initialized enemy: " << _id << endl;
1470 		return;
1471 	}
1472 
1473 	_experience_level = xp_level;
1474 
1475 	// ----- (1): Add all new skills that should be available at the current experience level
1476 	for (map<uint32, uint32>::iterator i = _skill_set.begin(); i != _skill_set.end(); i++) {
1477 		if (_experience_level >= i->second)
1478 			AddSkill(i->first);
1479 	}
1480 
1481 	if (_skills.empty()) {
1482 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "no skills were added for the enemy: " << _id << endl;
1483 	}
1484 
1485 	// ----- (2): Add the new stats to the growth rate multiplied by the experience level
1486 	_max_hit_points    += static_cast<uint32>(_growth_hit_points * _experience_level);
1487 	_max_skill_points  += static_cast<uint32>(_growth_skill_points * _experience_level);
1488 	_experience_points += static_cast<uint32>(_growth_experience_points * _experience_level);
1489 	_strength          += static_cast<uint32>(_growth_strength * _experience_level);
1490 	_vigor             += static_cast<uint32>(_growth_vigor * _experience_level);
1491 	_fortitude         += static_cast<uint32>(_growth_fortitude * _experience_level);
1492 	_protection        += static_cast<uint32>(_growth_protection * _experience_level);
1493 	_agility           += static_cast<uint32>(_growth_agility * _experience_level);
1494 	_evade             += static_cast<float>(_growth_evade * _experience_level);
1495 	_drunes_dropped    += static_cast<uint32>(_growth_drunes * _experience_level);
1496 
1497 	// ----- (3): Randomize the new stats by using a guassian random variable
1498 	// Use the inital stats as the means and a standard deviation of 10% of the mean
1499 	_max_hit_points     = GaussianRandomValue(_max_hit_points, _max_hit_points / 10.0f);
1500 	_max_skill_points   = GaussianRandomValue(_max_skill_points, _max_skill_points / 10.0f);
1501 	_experience_points  = GaussianRandomValue(_experience_points, _experience_points / 10.0f);
1502 	_strength           = GaussianRandomValue(_strength, _strength / 10.0f);
1503 	_vigor              = GaussianRandomValue(_strength, _strength / 10.0f);
1504 	_fortitude          = GaussianRandomValue(_fortitude, _fortitude / 10.0f);
1505 	_protection         = GaussianRandomValue(_protection, _protection / 10.0f);
1506 	_agility            = GaussianRandomValue(_agility, _agility / 10.0f);
1507 	// TODO: need a gaussian random var function that takes a float arg
1508 	//_evade              = static_cast<float>(GaussianRandomValue(_evade, _evade / 10.0f));
1509 	_drunes_dropped     = GaussianRandomValue(_drunes_dropped, _drunes_dropped / 10.0f);
1510 
1511 	// ----- (4): Set the current hit points and skill points to their new maximum values
1512 	_hit_points = _max_hit_points;
1513 	_skill_points = _max_skill_points;
1514 } // void GlobalEnemy::Initialize(uint32 xp_level)
1515 
1516 
1517 
DetermineDroppedObjects(vector<GlobalObject * > & objects)1518 void GlobalEnemy::DetermineDroppedObjects(vector<GlobalObject*>& objects) {
1519 	objects.clear();
1520 
1521 	for (uint32 i = 0; i < _dropped_objects.size(); i++) {
1522 		if (_experience_level >= _dropped_level_required[i]) {
1523 			if (RandomFloat() < _dropped_chance[i]) {
1524 				objects.push_back(GlobalCreateNewObject(_dropped_objects[i]));
1525 			}
1526 		}
1527 	}
1528 }
1529 
1530 ////////////////////////////////////////////////////////////////////////////////
1531 // GlobalParty class
1532 ////////////////////////////////////////////////////////////////////////////////
1533 
AddActor(GlobalActor * actor,int32 index)1534 void GlobalParty::AddActor(GlobalActor* actor, int32 index) {
1535 	if (actor == NULL) {
1536 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received a NULL actor argument" << endl;
1537 		return;
1538 	}
1539 
1540 	if (_allow_duplicates == false) {
1541 		// Check that this actor is not already in the party
1542 		for (uint32 i = 0; i < _actors.size(); i++) {
1543 			if (actor->GetID() == _actors[i]->GetID()) {
1544 				IF_PRINT_WARNING(GLOBAL_DEBUG) << "attempted to add an actor that was already in the party "
1545 					<< "when duplicates were not allowed: " << actor->GetID() << endl;
1546 				return;
1547 			}
1548 		}
1549 	}
1550 
1551 	// Add actor to the end of the party if index is negative
1552 	if (index < 0) {
1553 		_actors.push_back(actor);
1554 		return;
1555 	}
1556 
1557 	// Check that the requested index does not exceed the size of the container
1558 	if (static_cast<uint32>(index) >= _actors.size()) {
1559 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded the current party size: " << index << endl;
1560 		_actors.push_back(actor); // Add the actor to the end of the party instead
1561 		return;
1562 	}
1563 	else {
1564 		vector<GlobalActor*>::iterator position = _actors.begin();
1565 		for (int32 i = 0; i < index; i++, position++);
1566 		_actors.insert(position, actor);
1567 	}
1568 }
1569 
1570 
1571 
RemoveActorAtIndex(uint32 index)1572 GlobalActor* GlobalParty::RemoveActorAtIndex(uint32 index) {
1573 	if (index >= _actors.size()) {
1574 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded current party size: " << index << endl;
1575 		return NULL;
1576 	}
1577 
1578 	GlobalActor* removed_actor = _actors[index];
1579 	vector<GlobalActor*>::iterator position = _actors.begin();
1580 	for (uint32 i = 0; i < index; i++, position++);
1581 	_actors.erase(position);
1582 
1583 	return removed_actor;
1584 }
1585 
1586 
1587 
RemoveActorByID(uint32 id)1588 GlobalActor* GlobalParty::RemoveActorByID(uint32 id) {
1589 	if (_allow_duplicates) {
1590 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "tried to remove actor when duplicates were allowed in the party: " << id << endl;
1591 		return NULL;
1592 	}
1593 
1594 	GlobalActor* removed_actor = NULL;
1595 	for (vector<GlobalActor*>::iterator position = _actors.begin(); position != _actors.end(); position++) {
1596 		if (id == (*position)->GetID()) {
1597 			removed_actor = *position;
1598 			_actors.erase(position);
1599 			break;
1600 		}
1601 	}
1602 
1603 	if (removed_actor == NULL) {
1604 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to find an actor in the party with the requested id: " << id << endl;
1605 	}
1606 
1607 	return removed_actor;
1608 }
1609 
1610 
1611 
GetActorAtIndex(uint32 index) const1612 GlobalActor* GlobalParty::GetActorAtIndex(uint32 index) const {
1613 	if (index >= _actors.size()) {
1614 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded current party size: " << index << endl;
1615 		return NULL;
1616 	}
1617 
1618 	return _actors[index];
1619 }
1620 
1621 
1622 
GetActorByID(uint32 id) const1623 GlobalActor* GlobalParty::GetActorByID(uint32 id) const {
1624 	if (_allow_duplicates) {
1625 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "tried to retrieve actor when duplicates were allowed in the party: " << id << endl;
1626 		return NULL;
1627 	}
1628 
1629 	for (uint32 i = 0; i < _actors.size(); i++) {
1630 		if (_actors[i]->GetID() == id) {
1631 			return _actors[i];
1632 		}
1633 	}
1634 
1635 	IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to find an actor in the party with the requested id: " << id << endl;
1636 	return NULL;
1637 }
1638 
1639 
1640 
SwapActorsByIndex(uint32 first_index,uint32 second_index)1641 void GlobalParty::SwapActorsByIndex(uint32 first_index, uint32 second_index) {
1642 	if (first_index == second_index) {
1643 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "first_index and second_index arguments had the same value: " << first_index << endl;
1644 		return;
1645 	}
1646 	if (first_index >= _actors.size()) {
1647 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "first_index argument exceeded current party size: " << first_index << endl;
1648 		return;
1649 	}
1650 	if (second_index >= _actors.size()) {
1651 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "second_index argument exceeded current party size: " << second_index << endl;
1652 		return;
1653 	}
1654 
1655 	GlobalActor* tmp = _actors[first_index];
1656 	_actors[first_index] = _actors[second_index];
1657 	_actors[second_index] = tmp;
1658 }
1659 
1660 
1661 
SwapActorsByID(uint32 first_id,uint32 second_id)1662 void GlobalParty::SwapActorsByID(uint32 first_id, uint32 second_id) {
1663 	if (first_id == second_id) {
1664 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "first_id and second_id arguments had the same value: " << first_id << endl;
1665 		return;
1666 	}
1667 	if (_allow_duplicates) {
1668 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "tried to swap actors when duplicates were allowed in the party: " << first_id << endl;
1669 		return;
1670 	}
1671 
1672 	vector<GlobalActor*>::iterator first_position;
1673 	vector<GlobalActor*>::iterator second_position;
1674 	for (first_position = _actors.begin(); first_position != _actors.end(); first_position++) {
1675 		if ((*first_position)->GetID() == first_id)
1676 			break;
1677 	}
1678 	for (second_position = _actors.begin(); second_position != _actors.end(); second_position++) {
1679 		if ((*second_position)->GetID() == second_id)
1680 			break;
1681 	}
1682 
1683 	if (first_position == _actors.end()) {
1684 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to find an actor in the party with the requested first_id: " << first_id << endl;
1685 		return;
1686 	}
1687 	if (second_position == _actors.end()) {
1688 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to find an actor in the party with the requested second_id: " << second_id << endl;
1689 		return;
1690 	}
1691 
1692 	GlobalActor* tmp = *first_position;
1693 	*first_position = *second_position;
1694 	*second_position = tmp;
1695 }
1696 
1697 
1698 
ReplaceActorByIndex(uint32 index,GlobalActor * new_actor)1699 GlobalActor* GlobalParty::ReplaceActorByIndex(uint32 index, GlobalActor* new_actor) {
1700 	if (new_actor == NULL) {
1701 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received a NULL new_actor argument" << endl;
1702 		return NULL;
1703 	}
1704 	if (index >= _actors.size()) {
1705 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "index argument exceeded current party size: " << index << endl;
1706 		return NULL;
1707 	}
1708 
1709 	GlobalActor* tmp = _actors[index];
1710 	_actors[index] = new_actor;
1711 	return tmp;
1712 }
1713 
1714 
1715 
ReplaceActorByID(uint32 id,GlobalActor * new_actor)1716 GlobalActor* GlobalParty::ReplaceActorByID(uint32 id, GlobalActor* new_actor) {
1717 	if (_allow_duplicates) {
1718 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "tried to replace actor when duplicates were allowed in the party: " << id << endl;
1719 		return NULL;
1720 	}
1721 	if (new_actor == NULL) {
1722 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "function received a NULL new_actor argument" << endl;
1723 		return NULL;
1724 	}
1725 
1726 	GlobalActor* removed_actor = NULL;
1727 	for (vector<GlobalActor*>::iterator position = _actors.begin(); position != _actors.end(); position++) {
1728 		if ((*position)->GetID() == id) {
1729 			removed_actor = *position;
1730 			*position = new_actor;
1731 			break;
1732 		}
1733 	}
1734 
1735 	if (removed_actor == NULL) {
1736 		IF_PRINT_WARNING(GLOBAL_DEBUG) << "failed to find an actor in the party with the requested id: " << id << endl;
1737 	}
1738 
1739 	return removed_actor;
1740 }
1741 
1742 
1743 
AverageExperienceLevel() const1744 float GlobalParty::AverageExperienceLevel() const {
1745 	if (_actors.empty())
1746 		return 0.0f;
1747 
1748 	float xp_level_sum = 0.0f;
1749 	for (uint32 i = 0; i < _actors.size(); i++)
1750 		xp_level_sum += static_cast<float>(_actors[i]->GetExperienceLevel());
1751 	return (xp_level_sum / static_cast<float>(_actors.size()));
1752 }
1753 
1754 
1755 
AddHitPoints(uint32 hp)1756 void GlobalParty::AddHitPoints(uint32 hp) {
1757 	for (vector<GlobalActor*>::iterator i = _actors.begin(); i != _actors.end(); i++) {
1758 		(*i)->AddHitPoints(hp);
1759 	}
1760 }
1761 
1762 } // namespace hoa_global
1763