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 and
6 // 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_actors.cpp
12 *** \author Viljami Korhonen, mindflayer@allacrost.org
13 *** \author Corey Hoffstein, visage@allacrost.org
14 *** \author Andy Gardner, chopperdave@allacrost.org
15 *** \brief Source file for actors present in battles.
16 *** ***************************************************************************/
17
18 #include "input.h"
19 #include "script.h"
20
21 #include "battle.h"
22 #include "battle_actions.h"
23 #include "battle_actors.h"
24 #include "battle_effects.h"
25 #include "battle_indicators.h"
26 #include "battle_utils.h"
27
28 using namespace std;
29
30 using namespace hoa_utils;
31 using namespace hoa_audio;
32 using namespace hoa_video;
33 using namespace hoa_input;
34 using namespace hoa_system;
35 using namespace hoa_global;
36 using namespace hoa_script;
37
38 namespace hoa_battle {
39
40 namespace private_battle {
41
42 ////////////////////////////////////////////////////////////////////////////////
43 // BattleActor class
44 ////////////////////////////////////////////////////////////////////////////////
45
BattleActor(GlobalActor * actor)46 BattleActor::BattleActor(GlobalActor* actor) :
47 GlobalActor(*actor),
48 _state(ACTOR_STATE_INVALID),
49 _global_actor(actor),
50 _action(NULL),
51 _x_origin(0.0f),
52 _y_origin(0.0f),
53 _x_location(0.0f),
54 _y_location(0.0f),
55 _execution_finished(false),
56 _idle_state_time(0),
57 _effects_supervisor(new EffectsSupervisor(this)),
58 _indicator_supervisor(new IndicatorSupervisor(this))
59 {
60 if (actor == NULL) {
61 IF_PRINT_WARNING(BATTLE_DEBUG) << "constructor received NULL argument" << endl;
62 return;
63 }
64
65 // TODO: I have concerns about the copy constructor for GlobalActor. Currently it creates a copy
66 // of every single attack point, weapon, armor, and skill. I wonder if perhaps we should only
67 // create a copy of the attack point
68 }
69
70
71
~BattleActor()72 BattleActor::~BattleActor() {
73 // If the actor did not get a chance to execute their action, delete it
74 if (_action != NULL) {
75 delete _action;
76 _action = NULL;
77 }
78
79 delete _effects_supervisor;
80 delete _indicator_supervisor;
81 }
82
83
84
ChangeState(ACTOR_STATE new_state)85 void BattleActor::ChangeState(ACTOR_STATE new_state) {
86 if (_state == new_state) {
87 IF_PRINT_WARNING(BATTLE_DEBUG) << "actor was already in new state: " << new_state << endl;
88 return;
89 }
90
91 _state = new_state;
92 _state_timer.Reset();
93 switch (_state) {
94 case ACTOR_STATE_IDLE:
95 if (_action != NULL) {
96 delete _action;
97 _action = NULL;
98 }
99 _state_timer.Initialize(_idle_state_time);
100 _state_timer.Run();
101 break;
102 case ACTOR_STATE_WARM_UP:
103 if (_action == NULL) {
104 IF_PRINT_WARNING(BATTLE_DEBUG) << "no action available during state change: " << _state << endl;
105 }
106 else {
107 _state_timer.Initialize(_action->GetWarmUpTime());
108 _state_timer.Run();
109 }
110 break;
111 case ACTOR_STATE_READY:
112 if (_action == NULL) {
113 IF_PRINT_WARNING(BATTLE_DEBUG) << "no action available during state change: " << _state << endl;
114 }
115 else {
116 BattleMode::CurrentInstance()->NotifyActorReady(this);
117 }
118 break;
119 case ACTOR_STATE_COOL_DOWN:
120 _execution_finished = false;
121 if (_action == NULL) {
122 IF_PRINT_WARNING(BATTLE_DEBUG) << "no action available during state change: " << _state << endl;
123 }
124 else {
125 _state_timer.Initialize(_action->GetCoolDownTime());
126 _state_timer.Run();
127 }
128 break;
129 case ACTOR_STATE_DEAD:
130 BattleMode::CurrentInstance()->NotifyActorDeath(this);
131 break;
132 default:
133 break;
134 }
135 }
136
137
138
RegisterDamage(uint32 amount)139 void BattleActor::RegisterDamage(uint32 amount) {
140 if (amount == 0) {
141 IF_PRINT_WARNING(BATTLE_DEBUG) << "function called with a zero value argument" << endl;
142 RegisterMiss();
143 return;
144 }
145 if (_state == ACTOR_STATE_DEAD) {
146 IF_PRINT_WARNING(BATTLE_DEBUG) << "function called when actor state was dead" << endl;
147 RegisterMiss();
148 return;
149 }
150
151 SubtractHitPoints(amount);
152 _indicator_supervisor->AddDamageIndicator(amount);
153
154 if (GetHitPoints() == 0)
155 ChangeState(ACTOR_STATE_DEAD);
156 }
157
158
159
RegisterHealing(uint32 amount)160 void BattleActor::RegisterHealing(uint32 amount) {
161 if (amount == 0) {
162 IF_PRINT_WARNING(BATTLE_DEBUG) << "function called with a zero value argument" << endl;
163 RegisterMiss();
164 return;
165 }
166 if (_state == ACTOR_STATE_DEAD) {
167 IF_PRINT_WARNING(BATTLE_DEBUG) << "function called when actor state was dead" << endl;
168 RegisterMiss();
169 return;
170 }
171
172 AddHitPoints(amount);
173 _indicator_supervisor->AddHealingIndicator(amount);
174 }
175
176
177
RegisterMiss()178 void BattleActor::RegisterMiss() {
179 _indicator_supervisor->AddMissIndicator();
180 }
181
182
183
RegisterStatusChange(GLOBAL_STATUS status,GLOBAL_INTENSITY intensity)184 void BattleActor::RegisterStatusChange(GLOBAL_STATUS status, GLOBAL_INTENSITY intensity) {
185 GLOBAL_INTENSITY old_intensity = GLOBAL_INTENSITY_INVALID;
186 GLOBAL_INTENSITY new_intensity = intensity;
187
188 // TODO: determine if an opposite status effect is active and account for it
189
190 old_intensity = _effects_supervisor->ChangeStatus(status, new_intensity);
191
192 // If the return value was invalid, no status was changed so do not create any indicator
193 if (old_intensity == GLOBAL_INTENSITY_INVALID) {
194 return;
195 }
196 _indicator_supervisor->AddStatusIndicator(status, old_intensity, status, new_intensity);
197 }
198
199
200
ChangeSkillPoints(int32 amount)201 void BattleActor::ChangeSkillPoints(int32 amount) {
202 uint32 unsigned_amount = static_cast<uint32>(amount);
203
204 // Modify actor's skill points accordingly
205 if (amount > 0)
206 AddSkillPoints(unsigned_amount);
207 else if (amount < 0)
208 SubtractSkillPoints(unsigned_amount);
209
210 // TODO: SP change text needs to be implemented
211 }
212
213
214
Update()215 void BattleActor::Update() {
216 _state_timer.Update();
217 _effects_supervisor->Update();
218 _indicator_supervisor->Update();
219
220 if (_state == ACTOR_STATE_IDLE) {
221 if (_state_timer.IsFinished() == true)
222 ChangeState(ACTOR_STATE_COMMAND);
223 }
224 else if (_state == ACTOR_STATE_WARM_UP) {
225 if (_state_timer.IsFinished() == true)
226 ChangeState(ACTOR_STATE_READY);
227 }
228 else if (_state == ACTOR_STATE_COOL_DOWN) {
229 if (_state_timer.IsFinished() == true)
230 ChangeState(ACTOR_STATE_IDLE);
231 }
232 }
233
234
235
DrawIndicators() const236 void BattleActor::DrawIndicators() const {
237 _indicator_supervisor->Draw();
238 }
239
240
241
SetAction(BattleAction * action)242 void BattleActor::SetAction(BattleAction* action) {
243 if (action == NULL) {
244 IF_PRINT_WARNING(BATTLE_DEBUG) << "function received NULL argument" << endl;
245 return;
246 }
247 if (_state != ACTOR_STATE_COMMAND) {
248 IF_PRINT_WARNING(BATTLE_DEBUG) << "actor was not in the command state when function was called" << endl;
249 delete action;
250 return;
251 }
252 if (_action != NULL) {
253 IF_PRINT_WARNING(BATTLE_DEBUG) << "actor already had another action set -- overridding" << endl;
254 delete _action;
255 }
256
257 _action = action;
258 }
259
260
261
TotalPhysicalDefense()262 uint32 BattleActor::TotalPhysicalDefense() {
263 uint32 phys_defense = 0;
264
265 for (uint32 i = 0; i < _attack_points.size(); i++)
266 phys_defense += _attack_points[i]->GetTotalPhysicalDefense();
267 phys_defense /= _attack_points.size();
268
269 return phys_defense;
270 }
271
272
273
TotalMetaphysicalDefense()274 uint32 BattleActor::TotalMetaphysicalDefense() {
275 uint32 meta_defense = 0;
276
277 for (uint32 i = 0; i < _attack_points.size(); i++)
278 meta_defense += _attack_points[i]->GetTotalMetaphysicalDefense();
279 meta_defense /= _attack_points.size();
280
281 return meta_defense;
282 }
283
284
285
TotalEvadeRating()286 float BattleActor::TotalEvadeRating() {
287 float evade = 0.0f;
288
289 for (uint32 i = 0; i < _attack_points.size(); i++)
290 evade += _attack_points[i]->GetTotalEvadeRating();
291 evade /= static_cast<float>(_attack_points.size());
292
293 return evade;
294 }
295
296 ////////////////////////////////////////////////////////////////////////////////
297 // BattleCharacter class
298 ////////////////////////////////////////////////////////////////////////////////
299
BattleCharacter(GlobalCharacter * character)300 BattleCharacter::BattleCharacter(GlobalCharacter* character) :
301 BattleActor(character),
302 _global_character(character),
303 _sprite_animation_alias("idle"),
304 _animation_timer(0)
305 {
306 if (_stamina_icon.Load("img/icons/actors/characters/" + character->GetFilename() + ".png", 45, 45) == false)
307 PRINT_ERROR << "unable to load stamina icon for character: " << character->GetFilename() << endl;
308
309 _name_text.SetStyle(TextStyle("title22"));
310 _name_text.SetText(GetName());
311 _hit_points_text.SetStyle(TextStyle("text20"));
312 _hit_points_text.SetText(NumberToString(GetHitPoints()));
313 _skill_points_text.SetStyle(TextStyle("text20"));
314 _skill_points_text.SetText(NumberToString(GetSkillPoints()));
315 }
316
317
318
~BattleCharacter()319 BattleCharacter::~BattleCharacter() {
320 // If character was about to use an item before being destructed, restore it to inventory
321 if ((_action != NULL) && (_action->IsItemAction() == true)) {
322 // TODO: not sure if this is necessary/safe to do.
323 // ItemAction* item_action = dynamic_cast<ItemAction*>(_action);
324 // item_action->GetItem()->IncrementCount(1);
325 }
326 }
327
328
329
ChangeState(ACTOR_STATE new_state)330 void BattleCharacter::ChangeState(ACTOR_STATE new_state) {
331 BattleActor::ChangeState(new_state);
332
333 switch (_state) {
334 case ACTOR_STATE_COMMAND:
335 BattleMode::CurrentInstance()->NotifyCharacterCommand(this);
336 break;
337 case ACTOR_STATE_ACTING:
338 // TODO: reset state timer?
339 break;
340 case ACTOR_STATE_DEAD:
341 ChangeSpriteAnimation("idle");
342 _global_character->RetrieveBattleAnimation("idle")->GetCurrentFrame()->EnableGrayScale();
343 break;
344 default:
345 break;
346 }
347 }
348
349
350
Update()351 void BattleCharacter::Update() {
352 BattleActor::Update();
353 _animation_timer.Update();
354
355 // Update the active sprite animation
356 if (IsAlive() == true) {
357 _global_character->RetrieveBattleAnimation(_sprite_animation_alias)->Update();
358 }
359
360 // If the character is executing their action,
361 if (_state == ACTOR_STATE_ACTING) {
362 if (_action->Execute() == true) {
363 ChangeState(ACTOR_STATE_COOL_DOWN);
364 }
365 }
366 }
367
368
369
DrawSprite()370 void BattleCharacter::DrawSprite() {
371 // Draw the character sprite
372 VideoManager->Move(_x_location, _y_location);
373
374 if (_sprite_animation_alias == "idle") {
375 // no need to do anything
376 }
377 else if (_animation_timer.IsFinished()) {
378 _sprite_animation_alias = "idle";
379 }
380 else {
381 uint32 dist = 120 * _animation_timer.GetTimeExpired() / _animation_timer.GetDuration();
382 VideoManager->MoveRelative(dist, 0.0f);
383 }
384
385 _global_character->RetrieveBattleAnimation(_sprite_animation_alias)->Draw();
386 } // void BattleCharacter::DrawSprite()
387
388
389
390
ChangeSpriteAnimation(const std::string & alias)391 void BattleCharacter::ChangeSpriteAnimation(const std::string& alias) {
392 _sprite_animation_alias = alias;
393 _global_character->RetrieveBattleAnimation(_sprite_animation_alias)->ResetAnimation();
394 _animation_timer.Reset();
395 _animation_timer.SetDuration(300);
396 _animation_timer.Run();
397 }
398
399
400
DrawPortrait()401 void BattleCharacter::DrawPortrait() {
402 VideoManager->SetDrawFlags(VIDEO_X_LEFT, VIDEO_Y_BOTTOM, VIDEO_BLEND, 0);
403 VideoManager->Move(48.0f, 9.0f);
404
405 vector<StillImage>& portrait_frames = *(_global_character->GetBattlePortraits());
406 float hp_percent = static_cast<float>(GetHitPoints()) / static_cast<float>(GetMaxHitPoints());
407
408 if (GetHitPoints() == GetMaxHitPoints()) {
409 portrait_frames[0].Draw();
410 }
411 else if (GetHitPoints() == 0) {
412 portrait_frames[4].Draw();
413 }
414 else if (hp_percent > 0.75f) {
415 portrait_frames[0].Draw();
416 float alpha = 1.0f - ((hp_percent - 0.75f) * 4.0f);
417 portrait_frames[1].Draw(Color(1.0f, 1.0f, 1.0f, alpha));
418 }
419 else if (hp_percent > 0.50f) {
420 portrait_frames[1].Draw();
421 float alpha = 1.0f - ((hp_percent - 0.50f) * 4.0f);
422 portrait_frames[2].Draw(Color(1.0f, 1.0f, 1.0f, alpha));
423 }
424 else if (hp_percent > 0.25f) {
425 portrait_frames[2].Draw();
426 float alpha = 1.0f - ((hp_percent - 0.25f) * 4.0f);
427 portrait_frames[3].Draw(Color(1.0f, 1.0f, 1.0f, alpha));
428 }
429 else { // (hp_precent > 0.0f)
430 portrait_frames[3].Draw();
431 float alpha = 1.0f - (hp_percent * 4.0f);
432 portrait_frames[4].Draw(Color(1.0f, 1.0f, 1.0f, alpha));
433 }
434 }
435
436
437
DrawStatus(uint32 order)438 void BattleCharacter::DrawStatus(uint32 order) {
439 // Used to determine where to draw the character's status
440 float y_offset = 0.0f;
441
442 // Determine what vertical order the character is in and set the y_offset accordingly
443 switch (order) {
444 case 0:
445 y_offset = 0.0f;
446 break;
447 case 1:
448 y_offset = -25.0f;
449 break;
450 case 2:
451 y_offset = -50.0f;
452 break;
453 case 3:
454 y_offset = -75.0f;
455 break;
456 default:
457 IF_PRINT_WARNING(BATTLE_DEBUG) << "invalid order argument: " << order << endl;
458 y_offset = 0.0f;
459 }
460
461 // Draw the character's name
462 VideoManager->SetDrawFlags(VIDEO_X_RIGHT, VIDEO_Y_BOTTOM, VIDEO_BLEND, 0);
463 VideoManager->Move(280.0f, 82.0f + y_offset);
464 _name_text.Draw();
465
466 // If the swap key is being held down, draw status icons
467 if (InputManager->SwapState()) {
468 VideoManager->SetDrawFlags(VIDEO_X_LEFT, VIDEO_Y_BOTTOM, VIDEO_BLEND, 0);
469 VideoManager->MoveRelative(10.0f, 0.0f);
470 _effects_supervisor->Draw();
471 }
472
473 // Otherwise, draw the HP and SP bars (bars are 90 pixels wide and 6 pixels high)
474 else {
475 float bar_size;
476 VideoManager->SetDrawFlags(VIDEO_X_LEFT, VIDEO_NO_BLEND, 0);
477
478 // Draw HP bar in green
479 bar_size = static_cast<float>(90 * GetHitPoints()) / static_cast<float>(GetMaxHitPoints());
480 VideoManager->Move(312.0f, 90.0f + y_offset);
481
482 if (GetHitPoints() > 0) {
483 VideoManager->DrawRectangle(bar_size, 6, Color(0.133f, 0.455f, 0.133f, 1.0f));
484 }
485
486 // Draw SP bar in blue
487 bar_size = static_cast<float>(90 * GetSkillPoints()) / static_cast<float>(GetMaxSkillPoints());
488 VideoManager->Move(420.0f, 90.0f + y_offset);
489
490 if (GetSkillPoints() > 0) {
491 VideoManager->DrawRectangle(bar_size, 6, Color(0.129f, 0.263f, 0.451f, 1.0f));
492 }
493
494 // Draw the cover image over the top of the bar
495 VideoManager->SetDrawFlags(VIDEO_BLEND, 0);
496 VideoManager->Move(293.0f, 84.0f + y_offset);
497 BattleMode::CurrentInstance()->GetCharacterBarCovers().Draw();
498
499 // TODO: The SetText calls below should not be done here. They should be made whenever the character's HP/SP
500 // is modified. This re-renders the text every frame regardless of whether or not the HP/SP changed so its
501 // not efficient
502
503 VideoManager->SetDrawFlags(VIDEO_X_CENTER, 0);
504 // Draw the character's current health on top of the middle of the HP bar
505 VideoManager->Move(355.0f, 90.0f + y_offset);
506 _hit_points_text.SetText(NumberToString(GetHitPoints()));
507 _hit_points_text.Draw();
508
509 // Draw the character's current skill points on top of the middle of the SP bar
510 VideoManager->MoveRelative(110.0f, 0.0f);
511 _skill_points_text.SetText(NumberToString(GetSkillPoints()));
512 _skill_points_text.Draw();
513 }
514 } // void BattleCharacter::DrawStatus()
515
516 // /////////////////////////////////////////////////////////////////////////////
517 // BattleEnemy class
518 // /////////////////////////////////////////////////////////////////////////////
519
BattleEnemy(GlobalEnemy * enemy)520 BattleEnemy::BattleEnemy(GlobalEnemy* enemy) :
521 BattleActor(enemy),
522 _global_enemy(enemy)
523 {
524 if (_stamina_icon.Load("img/icons/actors/enemies/" + _global_actor->GetFilename() + ".png", 45, 45) == false)
525 PRINT_ERROR << "failed to load enemy stamina icon: " << _global_actor->GetFilename() << endl;
526 }
527
528
529
~BattleEnemy()530 BattleEnemy::~BattleEnemy() {
531 delete _global_actor;
532 }
533
534
535
536 // Compares the Y-coordinates of the actors, used for sorting the actors up-down when drawing
operator <(const BattleEnemy & other) const537 bool BattleEnemy::operator<(const BattleEnemy & other) const {
538 // NOTE: this code is currently not working correctly
539 //if ((_y_location - ((*GetActor()).GetHeight())) > (other.GetYLocation() - (*(other.GetActor()).GetHeight())))
540 // return true;
541 return false;
542 }
543
544
545
ChangeState(ACTOR_STATE new_state)546 void BattleEnemy::ChangeState(ACTOR_STATE new_state) {
547 BattleActor::ChangeState(new_state);
548
549 vector<StillImage>& sprite_frames = *(_global_enemy->GetBattleSpriteFrames());
550 switch (_state) {
551 case ACTOR_STATE_COMMAND:
552 _DecideAction();
553 ChangeState(ACTOR_STATE_WARM_UP);
554 break;
555 case ACTOR_STATE_ACTING:
556 _state_timer.Initialize(400); // TEMP: 400ms is a random time for the enemy sprite to move
557 _state_timer.Run();
558 break;
559 case ACTOR_STATE_DEAD:
560 sprite_frames[3].EnableGrayScale();
561 break;
562 default:
563 break;
564 }
565 }
566
567
568
Update()569 void BattleEnemy::Update() {
570 BattleActor::Update();
571
572 if (_state == ACTOR_STATE_ACTING) {
573 if (_execution_finished == false)
574 _execution_finished = _action->Execute();
575
576 if ((_execution_finished == true) && (_state_timer.IsFinished() == true))
577 ChangeState(ACTOR_STATE_COOL_DOWN);
578 }
579 }
580
581
582
DrawSprite()583 void BattleEnemy::DrawSprite() {
584 vector<StillImage>& sprite_frames = *(_global_enemy->GetBattleSpriteFrames());
585
586 // Draw the sprite's final damage frame, which should have grayscale enabled
587 if (_state == ACTOR_STATE_DEAD) {
588 VideoManager->Move(_x_location, _y_location);
589 sprite_frames[3].Draw();
590 return;
591 }
592
593 // TEMP: when the actor is acting, change its x draw position to show it move forward and then
594 // backward one tile as it completes its execution. In the future this functionality should be
595 // replaced by modifying the enemy's draw location members directly
596 uint32 enemy_draw_offset = 0;
597 if (_state == ACTOR_STATE_ACTING) {
598 if (_state_timer.PercentComplete() <= 0.50f)
599 enemy_draw_offset = TILE_SIZE * (2.0f * _state_timer.PercentComplete());
600 else
601 enemy_draw_offset = TILE_SIZE * (2.0f - 2.0f * _state_timer.PercentComplete());
602 }
603
604 // Draw the enemy's damage-blended sprite frames
605 VideoManager->Move(_x_location - enemy_draw_offset, _y_location);
606
607 float hp_percent = static_cast<float>(GetHitPoints()) / static_cast<float>(GetMaxHitPoints());
608
609 // Alpha will range from 1.0 to 0.0 in the following calculations
610 if (GetHitPoints() == GetMaxHitPoints()) {
611 sprite_frames[0].Draw();
612 }
613 else if (GetHitPoints() == 0) {
614 sprite_frames[3].Draw();
615 }
616 else if (hp_percent > 0.666f) {
617 sprite_frames[0].Draw();
618 float alpha = 1.0f - ((hp_percent - 0.666f) * 3.0f);
619 sprite_frames[1].Draw(Color (1.0f, 1.0f, 1.0f, alpha));
620 }
621 else if (hp_percent > 0.333f) {
622 sprite_frames[1].Draw();
623 float alpha = 1.0f - ((hp_percent - 0.333f) * 3.0f);
624 sprite_frames[2].Draw(Color(1.0f, 1.0f, 1.0f, alpha));
625 }
626 else { // (hp_precent > 0.0f)
627 sprite_frames[2].Draw();
628 float alpha = 1.0f - (hp_percent * 3.0f);
629 sprite_frames[3].Draw(Color(1.0f, 1.0f, 1.0f, alpha));
630 }
631 } // void BattleEnemy::DrawSprite()
632
633
634
_DecideAction()635 void BattleEnemy::_DecideAction() {
636 if (_global_enemy->GetSkills().empty() == true) {
637 IF_PRINT_WARNING(BATTLE_DEBUG) << "enemy had no usable skills" << endl;
638 ChangeState(ACTOR_STATE_IDLE);
639 }
640
641 // TODO: this method is mostly temporary and makes no intelligent decisions about what action to
642 // take or on what target to select. Currently this method does the following.
643 //
644 // (1): select the first skill that the enemy has available
645 // (2): select a random character that is not in the dead state to target
646 // (3): select a random attack point on the selected character target
647 //
648 // Therefore, only skills that target attack points on enemies are valid. No party or actor targets
649 // will work. Obviously these needs will be addressed eventually.
650
651 // TEMP: select a random skill to use
652 GlobalSkill* skill = NULL;
653 skill = _global_enemy->GetSkills().begin()->second;
654
655 // TEMP: select a random living character in the party for the target
656 BattleTarget target;
657
658 deque<BattleCharacter*> alive_characters = BattleMode::CurrentInstance()->GetCharacterActors();
659 deque<BattleCharacter*>::iterator character_iterator = alive_characters.begin();
660 while (character_iterator != alive_characters.end()) {
661 if ((*character_iterator)->IsAlive() == false)
662 character_iterator = alive_characters.erase(character_iterator);
663 else
664 character_iterator++;
665 }
666
667 if (alive_characters.empty() == true) {
668 IF_PRINT_WARNING(BATTLE_DEBUG) << "no characters were alive when enemy was selecting a target" << endl;
669 ChangeState(ACTOR_STATE_IDLE);
670 return;
671 }
672
673 uint32 point_target = 0;
674 BattleActor* actor_target = NULL;
675
676 // TEMP: select a random alive character
677 if (alive_characters.size() == 1)
678 actor_target = alive_characters[0];
679 else
680 actor_target = alive_characters[RandomBoundedInteger(0, alive_characters.size() - 1)];
681
682 // TEMP: select a random attack point on the target character
683 uint32 num_points = actor_target->GetAttackPoints().size();
684 if (num_points == 1)
685 point_target = 0;
686 else
687 point_target = RandomBoundedInteger(0, num_points - 1);
688
689 // TEMP: Should not statically assign to target a foe point. Examine the selected skill's target type
690 target.SetPointTarget(GLOBAL_TARGET_FOE_POINT, point_target, actor_target);
691
692 SetAction(new SkillAction(this, target, skill));
693 }
694
695 } // namespace private_battle
696
697 } // namespace hoa_battle
698