00001
00002
00003
00004
00005
00006
00007
00009
00016 #include "utils.h"
00017 #include "map.h"
00018 #include "map_sprites.h"
00019 #include "map_objects.h"
00020 #include "map_dialogue.h"
00021 #include "map_actions.h"
00022
00023 #include "audio.h"
00024 #include "video.h"
00025 #include "script.h"
00026 #include "system.h"
00027 #include "global.h"
00028
00029 using namespace std;
00030 using namespace hoa_utils;
00031 using namespace hoa_audio;
00032 using namespace hoa_video;
00033 using namespace hoa_script;
00034 using namespace hoa_system;
00035 using namespace hoa_global;
00036
00037 namespace hoa_map {
00038
00039 namespace private_map {
00040
00041
00042 hoa_video::AnimatedImage new_dialogue_icon;
00043
00044
00045
00046
00047
00048 VirtualSprite::VirtualSprite() :
00049 direction(SOUTH),
00050 movement_speed(NORMAL_SPEED),
00051 moving(false),
00052 sky_object(false),
00053 face_portrait( NULL ),
00054 current_action(-1),
00055 forced_action(-1),
00056 _saved(false),
00057 _current_dialogue(0),
00058 _show_dialogue_icon(true),
00059 _dialogue_icon_color( 1.0f, 1.0f, 1.0f, 0.0f )
00060 {
00061 MapObject::_object_type = VIRTUAL_TYPE;
00062 }
00063
00064
00065
00066 VirtualSprite::~VirtualSprite() {
00067 if (face_portrait != NULL) {
00068 VideoManager->DeleteImage(*face_portrait);
00069 face_portrait = NULL;
00070 }
00071
00072 for (uint32 i = 0; i < actions.size(); i++) {
00073 delete actions[i];
00074 }
00075 actions.clear();
00076
00077 for(uint32 i = 0; i < dialogues.size(); ++i) {
00078 delete dialogues[i];
00079 }
00080 dialogues.clear();
00081 }
00082
00083
00084 void VirtualSprite::UpdateSeenDialogue() {
00085
00086 for (uint32 i = 0; i < dialogues.size(); i++) {
00087 if (dialogues[i]->HasAlreadySeen() == false) {
00088 seen_all_dialogue = false;
00089 return;
00090 }
00091 }
00092
00093 seen_all_dialogue = true;
00094 }
00095
00096
00097
00098 uint16 VirtualSprite::CalculateOppositeDirection(const uint16 direction) {
00099 switch (direction) {
00100 case NORTH: return SOUTH;
00101 case SOUTH: return NORTH;
00102 case WEST: return EAST;
00103 case EAST: return WEST;
00104 case NW_NORTH: return SE_SOUTH;
00105 case NW_WEST: return SE_EAST;
00106 case NE_NORTH: return SW_SOUTH;
00107 case NE_EAST: return SW_WEST;
00108 case SW_SOUTH: return NE_NORTH;
00109 case SW_WEST: return NE_EAST;
00110 case SE_SOUTH: return NW_NORTH;
00111 case SE_EAST: return NW_WEST;
00112 default:
00113 if (MAP_DEBUG)
00114 cerr << "MAP WARNING: VirtualSprite::CalculateOppositeDirection received invalid direction" << endl;
00115 return SOUTH;
00116 }
00117 }
00118
00119
00120
00121 void VirtualSprite::Update() {
00122
00123 const float DIALOGUE_ICON_VISIBLE_RANGE = 30.0f;
00124 float icon_alpha = 1.0f - ( abs( ComputeXLocation() - MapMode::_current_map->_camera->ComputeXLocation() ) + abs( ComputeYLocation() - MapMode::_current_map->_camera->ComputeYLocation() ) ) / DIALOGUE_ICON_VISIBLE_RANGE;
00125 if( icon_alpha < 0 )
00126 icon_alpha = 0;
00127 _dialogue_icon_color.SetAlpha( icon_alpha );
00128
00129 new_dialogue_icon.Update();
00130 if (!updatable) {
00131 return;
00132 }
00133
00134
00135 if (forced_action < 0) {
00136
00137 if (current_action >= 0) {
00138 actions[current_action]->Execute();
00139 if (actions[current_action]->IsFinishedReset()) {
00140 current_action++;
00141 if (static_cast<uint8>(current_action) >= actions.size())
00142 current_action = 0;
00143 }
00144 }
00145 }
00146
00147 if (moving) {
00148
00149 float tmp_x = x_offset;
00150 float tmp_y = y_offset;
00151
00152 float distance_moved = static_cast<float>(MapMode::_current_map->_time_elapsed) / movement_speed;
00153
00154
00155 switch (direction) {
00156 case NORTH:
00157 y_offset -= distance_moved; break;
00158 case SOUTH:
00159 y_offset += distance_moved; break;
00160 case WEST: break;
00161 case EAST: break;
00162 case NW_NORTH:
00163 case NW_WEST:
00164 y_offset -= distance_moved; break;
00165 case SW_SOUTH:
00166 case SW_WEST:
00167 y_offset += distance_moved; break;
00168 case NE_NORTH:
00169 case NE_EAST:
00170 y_offset -= distance_moved; break;
00171 case SE_SOUTH:
00172 case SE_EAST:
00173 y_offset += distance_moved; break;
00174 default:
00175 cerr << "MAP ERROR: sprite trying to move in an invalid direction" << endl;
00176 return;
00177 }
00178
00179
00180 if (MapMode::_current_map->_DetectCollision(this))
00181 y_offset = tmp_y;
00182
00183
00184 while (y_offset < 0.0f) {
00185 y_position -= 1;
00186 y_offset += 1.0f;
00187 }
00188 while (y_offset > 1.0f) {
00189 y_position += 1;
00190 y_offset -= 1.0f;
00191 }
00192
00193
00194 switch (direction) {
00195 case NORTH: break;
00196 case SOUTH: break;
00197 case WEST:
00198 x_offset -= distance_moved; break;
00199 case EAST:
00200 x_offset += distance_moved; break;
00201 case NW_NORTH:
00202 case NW_WEST:
00203 x_offset -= distance_moved; break;
00204 case SW_SOUTH:
00205 case SW_WEST:
00206 x_offset -= distance_moved; break;
00207 case NE_NORTH:
00208 case NE_EAST:
00209 x_offset += distance_moved; break;
00210 case SE_SOUTH:
00211 case SE_EAST:
00212 x_offset += distance_moved; break;
00213 default:
00214 cerr << "MAP ERROR: sprite trying to move in an invalid direction" << endl;
00215 return;
00216 }
00217
00218
00219 if (MapMode::_current_map->_DetectCollision(this))
00220 x_offset = tmp_x;
00221
00222
00223 while (x_offset < 0.0f) {
00224 x_position -= 1;
00225 x_offset += 1.0f;
00226 }
00227 while (x_offset > 1.0f) {
00228 x_position += 1;
00229 x_offset -= 1.0f;
00230 }
00231 }
00232 }
00233
00234
00235
00236 void VirtualSprite::Draw() {
00237 if (HasDialogue()) {
00238 if (IsShowingDialogueIcon() && MapMode::_IsShowingDialogueIcons() && seen_all_dialogue == false) {
00239 VideoManager->MoveRelative(0, -GetImgHeight());
00240 VideoManager->DrawImage(new_dialogue_icon, _dialogue_icon_color);
00241 }
00242 }
00243 }
00244
00245
00246
00247 void VirtualSprite::SetDirection(uint16 dir) {
00248
00249 if (dir & (NORTH | SOUTH | EAST | WEST)) {
00250 direction = dir;
00251 return;
00252 }
00253
00254
00255 if (dir & NORTHWEST) {
00256 if (direction & (FACING_NORTH | FACING_EAST))
00257 direction = NW_NORTH;
00258 else
00259 direction = NW_WEST;
00260 }
00261 else if (dir & SOUTHWEST) {
00262 if (direction & (FACING_SOUTH | FACING_EAST))
00263 direction = SW_SOUTH;
00264 else
00265 direction = SW_WEST;
00266 }
00267 else if (dir & NORTHEAST) {
00268 if (direction & (FACING_NORTH | FACING_WEST))
00269 direction = NE_NORTH;
00270 else
00271 direction = NE_EAST;
00272 }
00273 else if (dir & SOUTHEAST) {
00274 if (direction & (FACING_SOUTH | FACING_WEST))
00275 direction = SE_SOUTH;
00276 else
00277 direction = SE_EAST;
00278 }
00279 else {
00280 if (MAP_DEBUG)
00281 fprintf(stderr, "ERROR: in VirtualSprite::SetDirection tried to set an invalid direction (%d)\n", dir);
00282 }
00283 }
00284
00285
00286
00287 void VirtualSprite::SetFacePortrait(std::string pn) {
00288 if (face_portrait != NULL) {
00289 delete face_portrait;
00290 }
00291
00292 face_portrait = new StillImage();
00293 face_portrait->SetFilename(pn);
00294 VideoManager->LoadImage(*face_portrait);
00295 }
00296
00297
00298
00299 void VirtualSprite::SaveState() {
00300 _saved = true;
00301
00302 _saved_direction = direction;
00303 _saved_movement_speed = movement_speed;
00304 _saved_moving = moving;
00305 _saved_name = name;
00306 _saved_current_action = current_action;
00307
00308
00309 }
00310
00311
00312
00313 bool VirtualSprite::LoadState() {
00314 if (_saved == false)
00315 return false;
00316
00317 direction = _saved_direction;
00318 movement_speed = _saved_movement_speed;
00319 moving = _saved_moving;
00320 name = _saved_name;
00321 current_action = _saved_current_action;
00322
00323
00324
00325
00326 return true;
00327 }
00328
00329
00330
00331 void VirtualSprite::SetRandomDirection() {
00332 switch (RandomBoundedInteger(1, 8)) {
00333 case 1:
00334 SetDirection(NORTH);
00335 break;
00336 case 2:
00337 SetDirection(SOUTH);
00338 break;
00339 case 3:
00340 SetDirection(EAST);
00341 break;
00342 case 4:
00343 SetDirection(WEST);
00344 break;
00345 case 5:
00346 SetDirection(NORTHEAST);
00347 break;
00348 case 6:
00349 SetDirection(NORTHWEST);
00350 break;
00351 case 7:
00352 SetDirection(SOUTHEAST);
00353 break;
00354 case 8:
00355 SetDirection(SOUTHWEST);
00356 break;
00357 default:
00358 if (MAP_DEBUG)
00359 cerr << "MAP WARNING: In VirtualSprite::SetRandomDirection(), invalid direction was picked" << endl;
00360 }
00361 }
00362
00363
00364
00365
00366
00367
00368 MapSprite::MapSprite() :
00369 was_moving(false),
00370 walk_sound(-1),
00371 current_animation(ANIM_STANDING_SOUTH)
00372 {
00373 MapObject::_object_type = SPRITE_TYPE;
00374 VirtualSprite::face_portrait = 0;
00375 }
00376
00377
00378
00379 MapSprite::~MapSprite() {
00380 for (uint32 i = 0; i < animations.size(); i++) {
00381 VideoManager->DeleteImage(animations[i]);
00382 }
00383 animations.clear();
00384
00385 if (face_portrait != NULL) {
00386 VideoManager->DeleteImage(*face_portrait);
00387 face_portrait = NULL;
00388 }
00389
00390
00391
00392
00393 }
00394
00395
00396
00397 bool MapSprite::LoadStandardAnimations(std::string filename) {
00398
00399
00400 uint32 frame_speed = static_cast<uint32>(movement_speed / 10.0f);
00401
00402
00403 for (uint8 i = 0; i < 8; i++)
00404 animations.push_back(AnimatedImage());
00405
00406
00407 vector<StillImage> frames(24);
00408 for (uint8 i = 0; i < 24; i++)
00409 frames[i].SetDimensions(img_half_width * 2, img_height);
00410
00411 if (VideoManager->LoadMultiImageFromNumberElements(frames, filename, 4, 6) == false) {
00412 return false;
00413 }
00414
00415
00416 animations[0].AddFrame(frames[0], frame_speed);
00417 animations[1].AddFrame(frames[6], frame_speed);
00418 animations[2].AddFrame(frames[12], frame_speed);
00419 animations[3].AddFrame(frames[18], frame_speed);
00420
00421
00422 animations[4].AddFrame(frames[1], frame_speed);
00423 animations[4].AddFrame(frames[2], frame_speed);
00424 animations[4].AddFrame(frames[3], frame_speed);
00425 animations[4].AddFrame(frames[1], frame_speed);
00426 animations[4].AddFrame(frames[4], frame_speed);
00427 animations[4].AddFrame(frames[5], frame_speed);
00428
00429 animations[5].AddFrame(frames[7], frame_speed);
00430 animations[5].AddFrame(frames[8], frame_speed);
00431 animations[5].AddFrame(frames[9], frame_speed);
00432 animations[5].AddFrame(frames[7], frame_speed);
00433 animations[5].AddFrame(frames[10], frame_speed);
00434 animations[5].AddFrame(frames[11], frame_speed);
00435
00436 animations[6].AddFrame(frames[13], frame_speed);
00437 animations[6].AddFrame(frames[14], frame_speed);
00438 animations[6].AddFrame(frames[15], frame_speed);
00439 animations[6].AddFrame(frames[13], frame_speed);
00440 animations[6].AddFrame(frames[16], frame_speed);
00441 animations[6].AddFrame(frames[17], frame_speed);
00442
00443 animations[7].AddFrame(frames[19], frame_speed);
00444 animations[7].AddFrame(frames[20], frame_speed);
00445 animations[7].AddFrame(frames[21], frame_speed);
00446 animations[7].AddFrame(frames[19], frame_speed);
00447 animations[7].AddFrame(frames[22], frame_speed);
00448 animations[7].AddFrame(frames[23], frame_speed);
00449
00450 for (uint32 i = 0; i < animations.size(); i++) {
00451 if (animations[i].Load() == false) {
00452 cerr << "MAP ERROR: failed to load sprite animation" << endl;
00453 return false;
00454 }
00455 }
00456
00457 return true;
00458 }
00459
00460
00461
00462 void MapSprite::Update() {
00463
00464
00465
00466
00467 if (!moving) {
00468 if (was_moving) {
00469
00470 animations[current_animation].SetTimeProgress(0);
00471 was_moving = false;
00472 }
00473
00474
00475 if (current_action == -1) {
00476 if (direction & FACING_NORTH) {
00477 current_animation = ANIM_STANDING_NORTH;
00478 }
00479 else if (direction & FACING_SOUTH) {
00480 current_animation = ANIM_STANDING_SOUTH;
00481 }
00482 else if (direction & FACING_WEST) {
00483 current_animation = ANIM_STANDING_WEST;
00484 }
00485 else if (direction & FACING_EAST) {
00486 current_animation = ANIM_STANDING_EAST;
00487 }
00488 else {
00489 cerr << "MAP ERROR: could not find proper standing animation to draw" << endl;
00490 }
00491 }
00492 }
00493
00494
00495 VirtualSprite::Update();
00496
00497 if (moving) {
00498
00499 uint8 last_animation = current_animation;
00500
00501
00502 if (direction & FACING_NORTH) {
00503 current_animation = ANIM_WALKING_NORTH;
00504 }
00505 else if (direction & FACING_SOUTH) {
00506 current_animation = ANIM_WALKING_SOUTH;
00507 }
00508 else if (direction & FACING_WEST) {
00509 current_animation = ANIM_WALKING_WEST;
00510 }
00511 else if (direction & FACING_EAST) {
00512 current_animation = ANIM_WALKING_EAST;
00513 }
00514 else {
00515 cerr << "MAP ERROR: could not find proper movement animation to draw" << endl;
00516 }
00517
00518
00519
00520
00521 if (current_animation != last_animation) {
00522 animations[current_animation].SetTimeProgress(animations[last_animation].GetTimeProgress());
00523 animations[last_animation].SetTimeProgress(0);
00524 }
00525 animations[current_animation].Update();
00526
00527 was_moving = true;
00528 }
00529 }
00530
00531
00532
00533 void MapSprite::Draw() {
00534 if (MapObject::DrawHelper() == true) {
00535 VideoManager->DrawImage(animations[current_animation]);
00536 VirtualSprite::Draw();
00537 }
00538 }
00539
00540
00541
00542 void MapSprite::SaveState() {
00543 VirtualSprite::SaveState();
00544
00545 _saved_was_moving = was_moving;
00546 _saved_walk_sound = walk_sound;
00547 _saved_current_animation = current_animation;
00548 }
00549
00550
00551
00552 bool MapSprite::LoadState() {
00553 if (!VirtualSprite::LoadState())
00554 return false;
00555
00556 was_moving = _saved_was_moving;
00557 walk_sound = _saved_walk_sound;
00558 current_animation = _saved_current_animation;
00559
00560 return true;
00561 }
00562
00563
00564
00565
00566
00567 EnemySprite::EnemySprite() :
00568 _zone(NULL),
00569 _color(1.0f, 1.0f, 1.0f, 0.0f),
00570 _aggro_range(8.0f),
00571 _time_dir_change(2500),
00572 _time_to_spawn(3500),
00573 _music_theme("")
00574 {
00575 filename = "";
00576 MapObject::_object_type = ENEMY_TYPE;
00577 moving = true;
00578 Reset();
00579 }
00580
00581 EnemySprite::EnemySprite(std::string file) :
00582 _zone(NULL),
00583 _color(1.0f, 1.0f, 1.0f, 0.0f),
00584 _aggro_range(8.0f),
00585 _time_dir_change(2500),
00586 _time_to_spawn(3500)
00587 {
00588 filename = file;
00589 MapObject::_object_type = ENEMY_TYPE;
00590 moving = true;
00591 Reset();
00592 }
00593
00594
00595
00596 bool EnemySprite::Load() {
00597 ReadScriptDescriptor sprite_script;
00598 if (sprite_script.OpenFile(filename) == false) {
00599 return false;
00600 }
00601
00602 ScriptCallFunction<void>(sprite_script.GetLuaState(), "Load", this);
00603 string sprite_sheet = sprite_script.ReadString("sprite_sheet");
00604 return MapSprite::LoadStandardAnimations(sprite_sheet);
00605 }
00606
00607
00608
00609 void EnemySprite::Reset() {
00610 updatable = false;
00611 no_collision = true;
00612 _state = DEAD;
00613 _time_elapsed = 0;
00614 _color.SetAlpha(0.0f);
00615 _out_of_zone = false;
00616 }
00617
00618
00619
00620 void EnemySprite::AddEnemy(uint32 enemy_id) {
00621 if (_enemy_parties.empty()) {
00622 if (MAP_DEBUG) {
00623 cerr << "MAP WARNING: In EnemySprite::AddEnemy, can not add new enemy when no parties have been declared" << endl;
00624 }
00625 return;
00626 }
00627
00628 _enemy_parties.back().push_back(enemy_id);
00629
00630
00631 if (MAP_DEBUG) {
00632 bool found = false;
00633 for (uint32 i = 0; i < MapMode::_loading_map->_enemies.size(); i++) {
00634 if (MapMode::_loading_map->_enemies[i].GetID() == enemy_id) {
00635 found = true;
00636 break;
00637 }
00638 }
00639
00640 if (found == false) {
00641 cerr << "MAP WARNING: In EnemySprite::AddEnemy, enemy to add has id " << enemy_id
00642 << ", which does not exist in MapMode::_enemies" << endl;
00643 }
00644 }
00645 }
00646
00647
00648
00649 const std::vector<uint32>& EnemySprite::RetrieveRandomParty() {
00650 if (_enemy_parties.empty()) {
00651 cerr << "MAP ERROR: Called EnemySprite::RetreiveRandomParty when no enemy parties existed!" << endl;
00652 exit(1);
00653 }
00654
00655 return _enemy_parties[rand() % _enemy_parties.size()];
00656 }
00657
00658
00659
00660 void EnemySprite::Update() {
00661 if( current_action != -1 ) {
00662 MapSprite::Update();
00663 return;
00664 }
00665
00666 switch (_state) {
00667
00668 case SPAWNING:
00669 _time_elapsed += SystemManager->GetUpdateTime();
00670 if (_color.GetAlpha() < 1.0f) {
00671 _color.SetAlpha((_time_elapsed / static_cast<float>(_time_to_spawn)) * 1.0f);
00672 }
00673 else {
00674 ChangeStateHostile();
00675 }
00676 break;
00677
00678
00679 case HOSTILE:
00680
00681 float xdelta, ydelta;
00682 _time_elapsed += SystemManager->GetUpdateTime();
00683
00684 xdelta = ComputeXLocation() - MapMode::_current_map->_camera->ComputeXLocation();
00685 ydelta = ComputeYLocation() - MapMode::_current_map->_camera->ComputeYLocation();
00686
00687
00688 if ( _zone != NULL && _zone->IsInsideZone(x_position, y_position) == false && _zone->IsRestraining() ) {
00689
00690 if( !_out_of_zone )
00691 {
00692 SetDirection(CalculateOppositeDirection(GetDirection()));
00693
00694 _out_of_zone = true;
00695 }
00696 }
00697
00698 else {
00699 _out_of_zone = false;
00700
00701
00702
00703 if ( _zone == NULL || ( abs(xdelta) <= _aggro_range && abs(ydelta) <= _aggro_range
00704 && (!_zone->IsRestraining() || _zone->IsInsideZone(MapMode::_current_map->_camera->x_position, MapMode::_current_map->_camera->y_position)) ) )
00705 {
00706 if (xdelta > -0.5 && xdelta < 0.5 && ydelta < 0)
00707 SetDirection(SOUTH);
00708 else if (xdelta > -0.5 && xdelta < 0.5 && ydelta > 0)
00709 SetDirection(NORTH);
00710 else if (ydelta > -0.5 && ydelta < 0.5 && xdelta > 0)
00711 SetDirection(WEST);
00712 else if (ydelta > -0.5 && ydelta < 0.5 && xdelta < 0)
00713 SetDirection(EAST);
00714 else if (xdelta < 0 && ydelta < 0)
00715 SetDirection(SOUTHEAST);
00716 else if (xdelta < 0 && ydelta > 0)
00717 SetDirection(NORTHEAST);
00718 else if (xdelta > 0 && ydelta < 0)
00719 SetDirection(SOUTHWEST);
00720 else
00721 SetDirection(NORTHWEST);
00722 }
00723
00724 else {
00725 if (_time_elapsed >= GetTimeToChange()) {
00726
00727 SetDirection(1 << hoa_utils::RandomBoundedInteger(0,11));
00728 _time_elapsed = 0;
00729 }
00730 }
00731 }
00732
00733 MapSprite::Update();
00734 break;
00735
00736
00737 case DEAD:
00738 default:
00739 break;
00740 }
00741 }
00742
00743
00744
00745 void EnemySprite::Draw() {
00746
00747 if (_state != DEAD && MapObject::DrawHelper() == true) {
00748 VideoManager->DrawImage(animations[current_animation], _color);
00749 return;
00750 }
00751 }
00752
00753 }
00754
00755 }