00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "supertux/sector.hpp"
00018
00019 #include <algorithm>
00020 #include <math.h>
00021
00022 #include "audio/sound_manager.hpp"
00023 #include "badguy/jumpy.hpp"
00024 #include "lisp/list_iterator.hpp"
00025 #include "math/aatriangle.hpp"
00026 #include "object/background.hpp"
00027 #include "object/bonus_block.hpp"
00028 #include "object/brick.hpp"
00029 #include "object/bullet.hpp"
00030 #include "object/camera.hpp"
00031 #include "object/cloud_particle_system.hpp"
00032 #include "object/coin.hpp"
00033 #include "object/comet_particle_system.hpp"
00034 #include "object/display_effect.hpp"
00035 #include "object/ghost_particle_system.hpp"
00036 #include "object/gradient.hpp"
00037 #include "object/invisible_block.hpp"
00038 #include "object/particlesystem.hpp"
00039 #include "object/particlesystem_interactive.hpp"
00040 #include "object/player.hpp"
00041 #include "object/portable.hpp"
00042 #include "object/pulsing_light.hpp"
00043 #include "object/rain_particle_system.hpp"
00044 #include "object/smoke_cloud.hpp"
00045 #include "object/snow_particle_system.hpp"
00046 #include "object/text_object.hpp"
00047 #include "object/tilemap.hpp"
00048 #include "physfs/ifile_stream.hpp"
00049 #include "scripting/squirrel_util.hpp"
00050 #include "supertux/collision.hpp"
00051 #include "supertux/constants.hpp"
00052 #include "supertux/game_session.hpp"
00053 #include "supertux/globals.hpp"
00054 #include "supertux/level.hpp"
00055 #include "supertux/object_factory.hpp"
00056 #include "supertux/player_status.hpp"
00057 #include "supertux/spawn_point.hpp"
00058 #include "supertux/tile.hpp"
00059 #include "trigger/sequence_trigger.hpp"
00060 #include "util/file_system.hpp"
00061
00062 Sector* Sector::_current = 0;
00063
00064 bool Sector::show_collrects = false;
00065 bool Sector::draw_solids_only = false;
00066
00067 Sector::Sector(Level* parent) :
00068 level(parent),
00069 name(),
00070 bullets(),
00071 init_script(),
00072 gameobjects_new(),
00073 currentmusic(LEVEL_MUSIC),
00074 sector_table(),
00075 scripts(),
00076 ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ),
00077 gameobjects(),
00078 moving_objects(),
00079 spawnpoints(),
00080 portables(),
00081 music(),
00082 gravity(10.0),
00083 player(0),
00084 solid_tilemaps(),
00085 camera(0),
00086 effect(0)
00087 {
00088 add_object(new Player(GameSession::current()->get_player_status(), "Tux"));
00089 add_object(new DisplayEffect("Effect"));
00090 add_object(new TextObject("Text"));
00091
00092 sound_manager->preload("sounds/shoot.wav");
00093
00094
00095 using namespace scripting;
00096
00097 sq_collectgarbage(global_vm);
00098
00099 sq_newtable(global_vm);
00100 sq_pushroottable(global_vm);
00101 if(SQ_FAILED(sq_setdelegate(global_vm, -2)))
00102 throw scripting::SquirrelError(global_vm, "Couldn't set sector_table delegate");
00103
00104 sq_resetobject(§or_table);
00105 if(SQ_FAILED(sq_getstackobj(global_vm, -1, §or_table)))
00106 throw scripting::SquirrelError(global_vm, "Couldn't get sector table");
00107 sq_addref(global_vm, §or_table);
00108 sq_pop(global_vm, 1);
00109 }
00110
00111 Sector::~Sector()
00112 {
00113 using namespace scripting;
00114
00115 deactivate();
00116
00117 for(ScriptList::iterator i = scripts.begin();
00118 i != scripts.end(); ++i) {
00119 HSQOBJECT& object = *i;
00120 sq_release(global_vm, &object);
00121 }
00122 sq_release(global_vm, §or_table);
00123 sq_collectgarbage(global_vm);
00124
00125 update_game_objects();
00126 assert(gameobjects_new.size() == 0);
00127
00128 for(GameObjects::iterator i = gameobjects.begin();
00129 i != gameobjects.end(); ++i) {
00130 GameObject* object = *i;
00131 before_object_remove(object);
00132 object->unref();
00133 }
00134
00135 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
00136 ++i)
00137 delete *i;
00138 }
00139
00140 Level*
00141 Sector::get_level()
00142 {
00143 return level;
00144 }
00145
00146 GameObject*
00147 Sector::parse_object(const std::string& name, const Reader& reader)
00148 {
00149 if(name == "camera") {
00150 Camera* camera = new Camera(this, "Camera");
00151 camera->parse(reader);
00152 return camera;
00153 } else if(name == "particles-snow") {
00154 SnowParticleSystem* partsys = new SnowParticleSystem();
00155 partsys->parse(reader);
00156 return partsys;
00157 } else if(name == "particles-rain") {
00158 RainParticleSystem* partsys = new RainParticleSystem();
00159 partsys->parse(reader);
00160 return partsys;
00161 } else if(name == "particles-comets") {
00162 CometParticleSystem* partsys = new CometParticleSystem();
00163 partsys->parse(reader);
00164 return partsys;
00165 } else if(name == "particles-ghosts") {
00166 GhostParticleSystem* partsys = new GhostParticleSystem();
00167 partsys->parse(reader);
00168 return partsys;
00169 } else if(name == "particles-clouds") {
00170 CloudParticleSystem* partsys = new CloudParticleSystem();
00171 partsys->parse(reader);
00172 return partsys;
00173 } else if(name == "money") {
00174 return new Jumpy(reader);
00175 } else {
00176 try {
00177 return ObjectFactory::instance().create(name, reader);
00178 } catch(std::exception& e) {
00179 log_warning << e.what() << "" << std::endl;
00180 return 0;
00181 }
00182 }
00183 }
00184
00185 void
00186 Sector::parse(const Reader& sector)
00187 {
00188 bool has_background = false;
00189 lisp::ListIterator iter(§or);
00190 while(iter.next()) {
00191 const std::string& token = iter.item();
00192 if(token == "name") {
00193 iter.value()->get(name);
00194 } else if(token == "gravity") {
00195 iter.value()->get(gravity);
00196 } else if(token == "music") {
00197 iter.value()->get(music);
00198 } else if(token == "spawnpoint") {
00199 SpawnPoint* sp = new SpawnPoint(*iter.lisp());
00200 spawnpoints.push_back(sp);
00201 } else if(token == "init-script") {
00202 iter.value()->get(init_script);
00203 } else if(token == "ambient-light") {
00204 std::vector<float> vColor;
00205 sector.get( "ambient-light", vColor );
00206 if(vColor.size() < 3) {
00207 log_warning << "(ambient-light) requires a color as argument" << std::endl;
00208 } else {
00209 ambient_light = Color( vColor );
00210 }
00211 } else {
00212 GameObject* object = parse_object(token, *(iter.lisp()));
00213 if(object) {
00214 if(dynamic_cast<Background *>(object)) {
00215 has_background = true;
00216 } else if(dynamic_cast<Gradient *>(object)) {
00217 has_background = true;
00218 }
00219 add_object(object);
00220 }
00221 }
00222 }
00223
00224 if(!has_background) {
00225 Gradient* gradient = new Gradient();
00226 gradient->set_gradient(Color(0.3, 0.4, 0.75), Color(1, 1, 1));
00227 add_object(gradient);
00228 }
00229
00230 update_game_objects();
00231
00232 if(solid_tilemaps.size() < 1) log_warning << "sector '" << name << "' does not contain a solid tile layer." << std::endl;
00233
00234 fix_old_tiles();
00235 if(!camera) {
00236 log_warning << "sector '" << name << "' does not contain a camera." << std::endl;
00237 update_game_objects();
00238 add_object(new Camera(this, "Camera"));
00239 }
00240
00241 update_game_objects();
00242 }
00243
00244 void
00245 Sector::parse_old_format(const Reader& reader)
00246 {
00247 name = "main";
00248 reader.get("gravity", gravity);
00249
00250 std::string backgroundimage;
00251 if (reader.get("background", backgroundimage) && (backgroundimage != "")) {
00252 if (backgroundimage == "arctis.png") backgroundimage = "arctis.jpg";
00253 if (backgroundimage == "arctis2.jpg") backgroundimage = "arctis.jpg";
00254 if (backgroundimage == "ocean.png") backgroundimage = "ocean.jpg";
00255 backgroundimage = "images/background/" + backgroundimage;
00256 if (!PHYSFS_exists(backgroundimage.c_str())) {
00257 log_warning << "Background image \"" << backgroundimage << "\" not found. Ignoring." << std::endl;
00258 backgroundimage = "";
00259 }
00260 }
00261
00262 float bgspeed = .5;
00263 reader.get("bkgd_speed", bgspeed);
00264 bgspeed /= 100;
00265
00266 Color bkgd_top, bkgd_bottom;
00267 int r = 0, g = 0, b = 128;
00268 reader.get("bkgd_red_top", r);
00269 reader.get("bkgd_green_top", g);
00270 reader.get("bkgd_blue_top", b);
00271 bkgd_top.red = static_cast<float> (r) / 255.0f;
00272 bkgd_top.green = static_cast<float> (g) / 255.0f;
00273 bkgd_top.blue = static_cast<float> (b) / 255.0f;
00274
00275 reader.get("bkgd_red_bottom", r);
00276 reader.get("bkgd_green_bottom", g);
00277 reader.get("bkgd_blue_bottom", b);
00278 bkgd_bottom.red = static_cast<float> (r) / 255.0f;
00279 bkgd_bottom.green = static_cast<float> (g) / 255.0f;
00280 bkgd_bottom.blue = static_cast<float> (b) / 255.0f;
00281
00282 if(backgroundimage != "") {
00283 Background* background = new Background();
00284 background->set_image(backgroundimage, bgspeed);
00285 add_object(background);
00286 } else {
00287 Gradient* gradient = new Gradient();
00288 gradient->set_gradient(bkgd_top, bkgd_bottom);
00289 add_object(gradient);
00290 }
00291
00292 std::string particlesystem;
00293 reader.get("particle_system", particlesystem);
00294 if(particlesystem == "clouds")
00295 add_object(new CloudParticleSystem());
00296 else if(particlesystem == "snow")
00297 add_object(new SnowParticleSystem());
00298 else if(particlesystem == "rain")
00299 add_object(new RainParticleSystem());
00300
00301 Vector startpos(100, 170);
00302 reader.get("start_pos_x", startpos.x);
00303 reader.get("start_pos_y", startpos.y);
00304
00305 SpawnPoint* spawn = new SpawnPoint;
00306 spawn->pos = startpos;
00307 spawn->name = "main";
00308 spawnpoints.push_back(spawn);
00309
00310 music = "chipdisko.ogg";
00311
00312
00313
00314
00315 music = "music/" + music;
00316
00317 int width = 30, height = 15;
00318 reader.get("width", width);
00319 reader.get("height", height);
00320
00321 std::vector<unsigned int> tiles;
00322 if(reader.get("interactive-tm", tiles)
00323 || reader.get("tilemap", tiles)) {
00324 TileMap* tilemap = new TileMap(level->get_tileset());
00325 tilemap->set(width, height, tiles, LAYER_TILES, true);
00326
00327
00328 for(size_t x=0; x < tilemap->get_width(); ++x) {
00329 for(size_t y=0; y < tilemap->get_height(); ++y) {
00330 uint32_t id = tilemap->get_tile_id(x, y);
00331 if(id == 112)
00332 tilemap->change(x, y, 1311);
00333 }
00334 }
00335
00336 if (height < 19) tilemap->resize(width, 19);
00337 add_object(tilemap);
00338 }
00339
00340 if(reader.get("background-tm", tiles)) {
00341 TileMap* tilemap = new TileMap(level->get_tileset());
00342 tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
00343 if (height < 19) tilemap->resize(width, 19);
00344 add_object(tilemap);
00345 }
00346
00347 if(reader.get("foreground-tm", tiles)) {
00348 TileMap* tilemap = new TileMap(level->get_tileset());
00349 tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
00350
00351
00352 if (height < 19) tilemap->resize(width, 19, 2035);
00353
00354 add_object(tilemap);
00355 }
00356
00357
00358 const lisp::Lisp* resetpoints = reader.get_lisp("reset-points");
00359 if(resetpoints) {
00360 lisp::ListIterator iter(resetpoints);
00361 while(iter.next()) {
00362 if(iter.item() == "point") {
00363 Vector sp_pos;
00364 if(reader.get("x", sp_pos.x) && reader.get("y", sp_pos.y))
00365 {
00366 SpawnPoint* sp = new SpawnPoint;
00367 sp->name = "main";
00368 sp->pos = sp_pos;
00369 spawnpoints.push_back(sp);
00370 }
00371 } else {
00372 log_warning << "Unknown token '" << iter.item() << "' in reset-points." << std::endl;
00373 }
00374 }
00375 }
00376
00377
00378 const lisp::Lisp* objects = reader.get_lisp("objects");
00379 if(objects) {
00380 lisp::ListIterator iter(objects);
00381 while(iter.next()) {
00382 GameObject* object = parse_object(iter.item(), *(iter.lisp()));
00383 if(object) {
00384 add_object(object);
00385 } else {
00386 log_warning << "Unknown object '" << iter.item() << "' in level." << std::endl;
00387 }
00388 }
00389 }
00390
00391
00392 Camera* camera = new Camera(this, "Camera");
00393 add_object(camera);
00394
00395 update_game_objects();
00396
00397 if(solid_tilemaps.size() < 1) log_warning << "sector '" << name << "' does not contain a solid tile layer." << std::endl;
00398
00399 fix_old_tiles();
00400 update_game_objects();
00401 }
00402
00403 void
00404 Sector::fix_old_tiles()
00405 {
00406 for(std::list<TileMap*>::iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
00407 TileMap* solids = *i;
00408 for(size_t x=0; x < solids->get_width(); ++x) {
00409 for(size_t y=0; y < solids->get_height(); ++y) {
00410 uint32_t id = solids->get_tile_id(x, y);
00411 const Tile *tile = solids->get_tile(x, y);
00412 Vector pos = solids->get_tile_position(x, y);
00413
00414 if(id == 112) {
00415 add_object(new InvisibleBlock(pos));
00416 solids->change(x, y, 0);
00417 } else if(tile->getAttributes() & Tile::COIN) {
00418 add_object(new Coin(pos, solids));
00419 solids->change(x, y, 0);
00420 } else if(tile->getAttributes() & Tile::FULLBOX) {
00421 add_object(new BonusBlock(pos, tile->getData()));
00422 solids->change(x, y, 0);
00423 } else if(tile->getAttributes() & Tile::BRICK) {
00424 add_object(new Brick(pos, tile->getData()));
00425 solids->change(x, y, 0);
00426 } else if(tile->getAttributes() & Tile::GOAL) {
00427 std::string sequence = tile->getData() == 0 ? "endsequence" : "stoptux";
00428 add_object(new SequenceTrigger(pos, sequence));
00429 solids->change(x, y, 0);
00430 }
00431 }
00432 }
00433 }
00434
00435
00436 for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end(); i++) {
00437 TileMap* tm = dynamic_cast<TileMap*>(*i);
00438 if (!tm) continue;
00439 for(size_t x=0; x < tm->get_width(); ++x) {
00440 for(size_t y=0; y < tm->get_height(); ++y) {
00441 uint32_t id = tm->get_tile_id(x, y);
00442 Vector pos = tm->get_tile_position(x, y);
00443 Vector center = pos + Vector(16, 16);
00444
00445
00446 if (id == 1517) {
00447 float pseudo_rnd = (float)((int)pos.x % 10) / 10;
00448 add_object(new PulsingLight(center, 1.0f + pseudo_rnd, 0.9f, 1.0f, Color(1.0f, 1.0f, 0.6f, 1.0f)));
00449 }
00450
00451 if ((id == 173) || (id == 1700) || (id == 1705) || (id == 1706)) {
00452
00453 if ((((tm->get_tile_id(x-1, y)) != tm->get_tile_id(x,y))
00454 && (tm->get_tile_id(x, y-1) != tm->get_tile_id(x,y)))
00455 || ((x % 3 == 0) && (y % 3 == 0))) {
00456 float pseudo_rnd = (float)((int)pos.x % 10) / 10;
00457 add_object(new PulsingLight(center, 1.0f + pseudo_rnd, 0.8f, 1.0f, Color(1.0f, 0.3f, 0.0f, 1.0f)));
00458 }
00459 }
00460
00461 }
00462 }
00463 }
00464
00465 }
00466
00467 HSQUIRRELVM
00468 Sector::run_script(std::istream& in, const std::string& sourcename)
00469 {
00470 using namespace scripting;
00471
00472
00473 for(ScriptList::iterator i = scripts.begin();
00474 i != scripts.end(); ) {
00475 HSQOBJECT& object = *i;
00476 HSQUIRRELVM vm = object_to_vm(object);
00477
00478 if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
00479 sq_release(global_vm, &object);
00480 i = scripts.erase(i);
00481 continue;
00482 }
00483
00484 ++i;
00485 }
00486
00487 HSQOBJECT object = create_thread(global_vm);
00488 scripts.push_back(object);
00489
00490 HSQUIRRELVM vm = object_to_vm(object);
00491
00492
00493 sq_pushobject(vm, sector_table);
00494 sq_setroottable(vm);
00495
00496 try {
00497 compile_and_run(vm, in, "Sector " + name + " - " + sourcename);
00498 } catch(std::exception& e) {
00499 log_warning << "Error running script: " << e.what() << std::endl;
00500 }
00501
00502 return vm;
00503 }
00504
00505 void
00506 Sector::add_object(GameObject* object)
00507 {
00508
00509 #ifndef NDEBUG
00510 for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
00511 ++i) {
00512 assert(*i != object);
00513 }
00514 for(GameObjects::iterator i = gameobjects_new.begin();
00515 i != gameobjects_new.end(); ++i) {
00516 assert(*i != object);
00517 }
00518 #endif
00519
00520 object->ref();
00521 gameobjects_new.push_back(object);
00522 }
00523
00524 void
00525 Sector::activate(const std::string& spawnpoint)
00526 {
00527 SpawnPoint* sp = 0;
00528 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
00529 ++i) {
00530 if((*i)->name == spawnpoint) {
00531 sp = *i;
00532 break;
00533 }
00534 }
00535 if(!sp) {
00536 log_warning << "Spawnpoint '" << spawnpoint << "' not found." << std::endl;
00537 if(spawnpoint != "main") {
00538 activate("main");
00539 } else {
00540 activate(Vector(0, 0));
00541 }
00542 } else {
00543 activate(sp->pos);
00544 }
00545 }
00546
00547 void
00548 Sector::activate(const Vector& player_pos)
00549 {
00550 if(_current != this) {
00551 if(_current != NULL)
00552 _current->deactivate();
00553 _current = this;
00554
00555
00556 HSQUIRRELVM vm = scripting::global_vm;
00557 sq_pushroottable(vm);
00558 sq_pushstring(vm, "sector", -1);
00559 sq_pushobject(vm, sector_table);
00560 if(SQ_FAILED(sq_createslot(vm, -3)))
00561 throw scripting::SquirrelError(vm, "Couldn't set sector in roottable");
00562 sq_pop(vm, 1);
00563
00564 for(GameObjects::iterator i = gameobjects.begin();
00565 i != gameobjects.end(); ++i) {
00566 GameObject* object = *i;
00567
00568 try_expose(object);
00569 }
00570 }
00571 try_expose_me();
00572
00573
00574
00575
00576 for(GameObjects::iterator i = gameobjects.begin();
00577 i != gameobjects.end(); ++i) {
00578 Player* p = dynamic_cast<Player*>(*i);
00579 if (!p) continue;
00580
00581
00582 if (!p->is_big()) {
00583 p->move(player_pos + Vector(0,32));
00584 } else {
00585 p->move(player_pos);
00586 }
00587
00588
00589 if(!is_free_of_tiles(p->get_bbox())) {
00590 log_warning << "Tried spawning Tux in solid matter. Compensating." << std::endl;
00591 Vector npos = p->get_bbox().p1;
00592 npos.y-=32;
00593 p->move(npos);
00594 }
00595 }
00596
00597 camera->reset(player->get_pos());
00598 update_game_objects();
00599
00600
00601
00602 std::string basedir = FileSystem::dirname(get_level()->filename);
00603 if(PHYSFS_exists((basedir + "/info").c_str())) {
00604 try {
00605 IFileStream in(basedir + "/default.nut");
00606 run_script(in, "default.nut");
00607 } catch(std::exception& ) {
00608
00609 }
00610 }
00611
00612
00613 if(init_script != "") {
00614 std::istringstream in(init_script);
00615 run_script(in, "init-script");
00616 }
00617 }
00618
00619 void
00620 Sector::deactivate()
00621 {
00622 if(_current != this)
00623 return;
00624
00625
00626 HSQUIRRELVM vm = scripting::global_vm;
00627 sq_pushroottable(vm);
00628 sq_pushstring(vm, "sector", -1);
00629 if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
00630 throw scripting::SquirrelError(vm, "Couldn't unset sector in roottable");
00631 sq_pop(vm, 1);
00632
00633 for(GameObjects::iterator i = gameobjects.begin();
00634 i != gameobjects.end(); ++i) {
00635 GameObject* object = *i;
00636
00637 try_unexpose(object);
00638 }
00639
00640 try_unexpose_me();
00641 _current = NULL;
00642 }
00643
00644 Rectf
00645 Sector::get_active_region()
00646 {
00647 return Rectf(
00648 camera->get_translation() - Vector(1600, 1200),
00649 camera->get_translation() + Vector(1600, 1200) + Vector(SCREEN_WIDTH,SCREEN_HEIGHT));
00650 }
00651
00652 void
00653 Sector::update(float elapsed_time)
00654 {
00655 player->check_bounds();
00656
00657
00658 for(GameObjects::iterator i = gameobjects.begin();
00659 i != gameobjects.end(); ++i) {
00660 GameObject* object = *i;
00661 if(!object->is_valid())
00662 continue;
00663
00664 object->update(elapsed_time);
00665 }
00666
00667
00668 handle_collisions();
00669 update_game_objects();
00670 }
00671
00672 void
00673 Sector::update_game_objects()
00674 {
00676 for(std::vector<GameObject*>::iterator i = gameobjects.begin();
00677 i != gameobjects.end(); ) {
00678 GameObject* object = *i;
00679
00680 if(object->is_valid()) {
00681 ++i;
00682 continue;
00683 }
00684
00685 before_object_remove(object);
00686
00687 object->unref();
00688 i = gameobjects.erase(i);
00689 }
00690
00691
00692 for(std::vector<GameObject*>::iterator i = gameobjects_new.begin();
00693 i != gameobjects_new.end(); ++i)
00694 {
00695 GameObject* object = *i;
00696
00697 before_object_add(object);
00698
00699 gameobjects.push_back(object);
00700 }
00701 gameobjects_new.clear();
00702
00703
00704
00705 solid_tilemaps.clear();
00706 for(std::vector<GameObject*>::iterator i = gameobjects.begin();
00707 i != gameobjects.end(); ++i)
00708 {
00709 TileMap* tm = dynamic_cast<TileMap*>(*i);
00710 if (!tm) continue;
00711 if (tm->is_solid()) solid_tilemaps.push_back(tm);
00712 }
00713
00714 }
00715
00716 bool
00717 Sector::before_object_add(GameObject* object)
00718 {
00719 Bullet* bullet = dynamic_cast<Bullet*> (object);
00720 if(bullet != NULL) {
00721 bullets.push_back(bullet);
00722 }
00723
00724 MovingObject* movingobject = dynamic_cast<MovingObject*> (object);
00725 if(movingobject != NULL) {
00726 moving_objects.push_back(movingobject);
00727 }
00728
00729 Portable* portable = dynamic_cast<Portable*> (object);
00730 if(portable != NULL) {
00731 portables.push_back(portable);
00732 }
00733
00734 TileMap* tilemap = dynamic_cast<TileMap*> (object);
00735 if(tilemap != NULL && tilemap->is_solid()) {
00736 solid_tilemaps.push_back(tilemap);
00737 }
00738
00739 Camera* camera = dynamic_cast<Camera*> (object);
00740 if(camera != NULL) {
00741 if(this->camera != 0) {
00742 log_warning << "Multiple cameras added. Ignoring" << std::endl;
00743 return false;
00744 }
00745 this->camera = camera;
00746 }
00747
00748 Player* player = dynamic_cast<Player*> (object);
00749 if(player != NULL) {
00750 if(this->player != 0) {
00751 log_warning << "Multiple players added. Ignoring" << std::endl;
00752 return false;
00753 }
00754 this->player = player;
00755 }
00756
00757 DisplayEffect* effect = dynamic_cast<DisplayEffect*> (object);
00758 if(effect != NULL) {
00759 if(this->effect != 0) {
00760 log_warning << "Multiple DisplayEffects added. Ignoring" << std::endl;
00761 return false;
00762 }
00763 this->effect = effect;
00764 }
00765
00766 if(_current == this) {
00767 try_expose(object);
00768 }
00769
00770 return true;
00771 }
00772
00773 void
00774 Sector::try_expose(GameObject* object)
00775 {
00776 ScriptInterface* object_ = dynamic_cast<ScriptInterface*> (object);
00777 if(object_ != NULL) {
00778 HSQUIRRELVM vm = scripting::global_vm;
00779 sq_pushobject(vm, sector_table);
00780 object_->expose(vm, -1);
00781 sq_pop(vm, 1);
00782 }
00783 }
00784
00785 void
00786 Sector::try_expose_me()
00787 {
00788 HSQUIRRELVM vm = scripting::global_vm;
00789 sq_pushobject(vm, sector_table);
00790 scripting::SSector* this_ = static_cast<scripting::SSector*> (this);
00791 expose_object(vm, -1, this_, "settings", false);
00792 sq_pop(vm, 1);
00793 }
00794
00795 void
00796 Sector::before_object_remove(GameObject* object)
00797 {
00798 Portable* portable = dynamic_cast<Portable*> (object);
00799 if(portable != NULL) {
00800 portables.erase(std::find(portables.begin(), portables.end(), portable));
00801 }
00802 Bullet* bullet = dynamic_cast<Bullet*> (object);
00803 if(bullet != NULL) {
00804 bullets.erase(std::find(bullets.begin(), bullets.end(), bullet));
00805 }
00806 MovingObject* moving_object = dynamic_cast<MovingObject*> (object);
00807 if(moving_object != NULL) {
00808 moving_objects.erase(
00809 std::find(moving_objects.begin(), moving_objects.end(), moving_object));
00810 }
00811
00812 if(_current == this)
00813 try_unexpose(object);
00814 }
00815
00816 void
00817 Sector::try_unexpose(GameObject* object)
00818 {
00819 ScriptInterface* object_ = dynamic_cast<ScriptInterface*> (object);
00820 if(object_ != NULL) {
00821 HSQUIRRELVM vm = scripting::global_vm;
00822 SQInteger oldtop = sq_gettop(vm);
00823 sq_pushobject(vm, sector_table);
00824 try {
00825 object_->unexpose(vm, -1);
00826 } catch(std::exception& e) {
00827 log_warning << "Couldn't unregister object: " << e.what() << std::endl;
00828 }
00829 sq_settop(vm, oldtop);
00830 }
00831 }
00832
00833 void
00834 Sector::try_unexpose_me()
00835 {
00836 HSQUIRRELVM vm = scripting::global_vm;
00837 SQInteger oldtop = sq_gettop(vm);
00838 sq_pushobject(vm, sector_table);
00839 try {
00840 scripting::unexpose_object(vm, -1, "settings");
00841 } catch(std::exception& e) {
00842 log_warning << "Couldn't unregister object: " << e.what() << std::endl;
00843 }
00844 sq_settop(vm, oldtop);
00845 }
00846 void
00847 Sector::draw(DrawingContext& context)
00848 {
00849 context.set_ambient_color( ambient_light );
00850 context.push_transform();
00851 context.set_translation(camera->get_translation());
00852
00853 for(GameObjects::iterator i = gameobjects.begin();
00854 i != gameobjects.end(); ++i) {
00855 GameObject* object = *i;
00856 if(!object->is_valid())
00857 continue;
00858
00859 if (draw_solids_only)
00860 {
00861 TileMap* tm = dynamic_cast<TileMap*>(object);
00862 if (tm && !tm->is_solid())
00863 continue;
00864 }
00865
00866 object->draw(context);
00867 }
00868
00869 if(show_collrects) {
00870 Color color(1.0f, 0.0f, 0.0f, 0.75f);
00871 for(MovingObjects::iterator i = moving_objects.begin();
00872 i != moving_objects.end(); ++i) {
00873 MovingObject* object = *i;
00874 const Rectf& rect = object->get_bbox();
00875
00876 context.draw_filled_rect(rect, color, LAYER_FOREGROUND1 + 10);
00877 }
00878 }
00879
00880 context.pop_transform();
00881 }
00882
00883
00884
00885
00886
00888 void check_collisions(collision::Constraints* constraints,
00889 const Vector& obj_movement, const Rectf& obj_rect, const Rectf& other_rect,
00890 GameObject* object = NULL, MovingObject* other = NULL, const Vector& other_movement = Vector(0,0))
00891 {
00892 if(!collision::intersects(obj_rect, other_rect))
00893 return;
00894
00895 MovingObject *moving_object = dynamic_cast<MovingObject*> (object);
00896 CollisionHit dummy;
00897 if(other != NULL && !other->collides(*object, dummy))
00898 return;
00899 if(moving_object != NULL && !moving_object->collides(*other, dummy))
00900 return;
00901
00902
00903 float itop = obj_rect.get_bottom() - other_rect.get_top();
00904 float ibottom = other_rect.get_bottom() - obj_rect.get_top();
00905 float ileft = obj_rect.get_right() - other_rect.get_left();
00906 float iright = other_rect.get_right() - obj_rect.get_left();
00907
00908 if(fabsf(obj_movement.y) > fabsf(obj_movement.x)) {
00909 if(ileft < SHIFT_DELTA) {
00910 constraints->constrain_right(other_rect.get_left(), other_movement.x);
00911 return;
00912 } else if(iright < SHIFT_DELTA) {
00913 constraints->constrain_left(other_rect.get_right(), other_movement.x);
00914 return;
00915 }
00916 } else {
00917
00918 if(itop < SHIFT_DELTA) {
00919 constraints->constrain_bottom(other_rect.get_top(), other_movement.y);
00920 return;
00921 } else if(ibottom < SHIFT_DELTA) {
00922 constraints->constrain_top(other_rect.get_bottom(), other_movement.y);
00923 return;
00924 }
00925 }
00926
00927 constraints->ground_movement += other_movement;
00928 if(other != NULL) {
00929 HitResponse response = other->collision(*object, dummy);
00930 if(response == ABORT_MOVE)
00931 return;
00932
00933 if(other->get_movement() != Vector(0, 0)) {
00934
00935 constraints->ground_movement = other->get_movement();
00936 }
00937 }
00938
00939 float vert_penetration = std::min(itop, ibottom);
00940 float horiz_penetration = std::min(ileft, iright);
00941 if(vert_penetration < horiz_penetration) {
00942 if(itop < ibottom) {
00943 constraints->constrain_bottom(other_rect.get_top(), other_movement.y);
00944 constraints->hit.bottom = true;
00945 } else {
00946 constraints->constrain_top(other_rect.get_bottom(), other_movement.y);
00947 constraints->hit.top = true;
00948 }
00949 } else {
00950 if(ileft < iright) {
00951 constraints->constrain_right(other_rect.get_left(), other_movement.x);
00952 constraints->hit.right = true;
00953 } else {
00954 constraints->constrain_left(other_rect.get_right(), other_movement.x);
00955 constraints->hit.left = true;
00956 }
00957 }
00958 }
00959
00960 void
00961 Sector::collision_tilemap(collision::Constraints* constraints,
00962 const Vector& movement, const Rectf& dest,
00963 MovingObject& object) const
00964 {
00965
00966 float x1 = dest.get_left();
00967 float x2 = dest.get_right();
00968 float y1 = dest.get_top();
00969 float y2 = dest.get_bottom();
00970
00971 for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
00972 TileMap* solids = *i;
00973
00974
00975 Rect test_tiles = solids->get_tiles_overlapping(Rectf(x1, y1, x2, y2));
00976
00977 for(int x = test_tiles.left; x < test_tiles.right; ++x) {
00978 for(int y = test_tiles.top; y < test_tiles.bottom; ++y) {
00979 const Tile* tile = solids->get_tile(x, y);
00980 if(!tile)
00981 continue;
00982
00983 if(!tile->is_solid ())
00984 continue;
00985 Rectf tile_bbox = solids->get_tile_bbox(x, y);
00986
00987
00988
00989
00990
00991 if(tile->is_unisolid ()) {
00992 Vector relative_movement = movement
00993 - solids->get_movement( true);
00994
00995 if (!tile->is_solid (tile_bbox, object.get_bbox(), relative_movement))
00996 continue;
00997 }
00998
00999 if(tile->is_slope ()) {
01000 AATriangle triangle;
01001 int slope_data = tile->getData();
01002 if (solids->get_drawing_effect() == VERTICAL_FLIP)
01003 slope_data = AATriangle::vertical_flip(slope_data);
01004 triangle = AATriangle(tile_bbox, slope_data);
01005
01006 collision::rectangle_aatriangle(constraints, dest, triangle,
01007 solids->get_movement( false));
01008 } else {
01009 check_collisions(constraints, movement, dest, tile_bbox, NULL, NULL,
01010 solids->get_movement( false));
01011 }
01012 }
01013 }
01014 }
01015 }
01016
01017 uint32_t
01018 Sector::collision_tile_attributes(const Rectf& dest) const
01019 {
01020 float x1 = dest.p1.x;
01021 float y1 = dest.p1.y;
01022 float x2 = dest.p2.x;
01023 float y2 = dest.p2.y;
01024
01025 uint32_t result = 0;
01026 for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
01027 TileMap* solids = *i;
01028
01029
01030 Rect test_tiles = solids->get_tiles_overlapping(Rectf(x1, y1, x2, y2));
01031
01032 Rect test_tiles_ice = solids->get_tiles_overlapping(Rectf(x1, y1, x2, y2 + SHIFT_DELTA));
01033
01034 for(int x = test_tiles.left; x < test_tiles.right; ++x) {
01035 int y;
01036 for(y = test_tiles.top; y < test_tiles.bottom; ++y) {
01037 const Tile* tile = solids->get_tile(x, y);
01038 if(!tile)
01039 continue;
01040 result |= tile->getAttributes();
01041 }
01042 for(; y < test_tiles_ice.bottom; ++y) {
01043 const Tile* tile = solids->get_tile(x, y);
01044 if(!tile)
01045 continue;
01046 result |= (tile->getAttributes() & Tile::ICE);
01047 }
01048 }
01049 }
01050
01051 return result;
01052 }
01053
01055 static void get_hit_normal(const Rectf& r1, const Rectf& r2, CollisionHit& hit,
01056 Vector& normal)
01057 {
01058 float itop = r1.get_bottom() - r2.get_top();
01059 float ibottom = r2.get_bottom() - r1.get_top();
01060 float ileft = r1.get_right() - r2.get_left();
01061 float iright = r2.get_right() - r1.get_left();
01062
01063 float vert_penetration = std::min(itop, ibottom);
01064 float horiz_penetration = std::min(ileft, iright);
01065 if(vert_penetration < horiz_penetration) {
01066 if(itop < ibottom) {
01067 hit.bottom = true;
01068 normal.y = vert_penetration;
01069 } else {
01070 hit.top = true;
01071 normal.y = -vert_penetration;
01072 }
01073 } else {
01074 if(ileft < iright) {
01075 hit.right = true;
01076 normal.x = horiz_penetration;
01077 } else {
01078 hit.left = true;
01079 normal.x = -horiz_penetration;
01080 }
01081 }
01082 }
01083
01084 void
01085 Sector::collision_object(MovingObject* object1, MovingObject* object2) const
01086 {
01087 using namespace collision;
01088
01089 const Rectf& r1 = object1->dest;
01090 const Rectf& r2 = object2->dest;
01091
01092 CollisionHit hit;
01093 if(intersects(object1->dest, object2->dest)) {
01094 Vector normal;
01095 get_hit_normal(r1, r2, hit, normal);
01096
01097 if(!object1->collides(*object2, hit))
01098 return;
01099 std::swap(hit.left, hit.right);
01100 std::swap(hit.top, hit.bottom);
01101 if(!object2->collides(*object1, hit))
01102 return;
01103 std::swap(hit.left, hit.right);
01104 std::swap(hit.top, hit.bottom);
01105
01106 HitResponse response1 = object1->collision(*object2, hit);
01107 std::swap(hit.left, hit.right);
01108 std::swap(hit.top, hit.bottom);
01109 HitResponse response2 = object2->collision(*object1, hit);
01110 if(response1 == CONTINUE && response2 == CONTINUE) {
01111 normal *= (0.5 + DELTA);
01112 object1->dest.move(-normal);
01113 object2->dest.move(normal);
01114 } else if (response1 == CONTINUE && response2 == FORCE_MOVE) {
01115 normal *= (1 + DELTA);
01116 object1->dest.move(-normal);
01117 } else if (response1 == FORCE_MOVE && response2 == CONTINUE) {
01118 normal *= (1 + DELTA);
01119 object2->dest.move(normal);
01120 }
01121 }
01122 }
01123
01124 void
01125 Sector::collision_static(collision::Constraints* constraints,
01126 const Vector& movement, const Rectf& dest,
01127 MovingObject& object)
01128 {
01129 collision_tilemap(constraints, movement, dest, object);
01130
01131
01132 for(MovingObjects::iterator i = moving_objects.begin();
01133 i != moving_objects.end(); ++i) {
01134 MovingObject* moving_object = *i;
01135 if(moving_object->get_group() != COLGROUP_STATIC
01136 && moving_object->get_group() != COLGROUP_MOVING_STATIC)
01137 continue;
01138 if(!moving_object->is_valid())
01139 continue;
01140
01141 if(moving_object != &object)
01142 check_collisions(constraints, movement, dest, moving_object->bbox,
01143 &object, moving_object);
01144 }
01145 }
01146
01147 void
01148 Sector::collision_static_constrains(MovingObject& object)
01149 {
01150 using namespace collision;
01151 float infinity = (std::numeric_limits<float>::has_infinity ? std::numeric_limits<float>::infinity() : std::numeric_limits<float>::max());
01152
01153 Constraints constraints;
01154 Vector movement = object.get_movement();
01155 Rectf& dest = object.dest;
01156
01157 for(int i = 0; i < 2; ++i) {
01158 collision_static(&constraints, Vector(0, movement.y), dest, object);
01159 if(!constraints.has_constraints())
01160 break;
01161
01162
01163 if(constraints.get_position_bottom() < infinity) {
01164 float height = constraints.get_height ();
01165 if(height < object.get_bbox().get_height()) {
01166
01167
01168
01169 }
01170 dest.p2.y = constraints.get_position_bottom() - DELTA;
01171 dest.p1.y = dest.p2.y - object.get_bbox().get_height();
01172 } else if(constraints.get_position_top() > -infinity) {
01173 dest.p1.y = constraints.get_position_top() + DELTA;
01174 dest.p2.y = dest.p1.y + object.get_bbox().get_height();
01175 }
01176 }
01177 if(constraints.has_constraints()) {
01178 if(constraints.hit.bottom) {
01179 dest.move(constraints.ground_movement);
01180 }
01181 if(constraints.hit.top || constraints.hit.bottom) {
01182 constraints.hit.left = false;
01183 constraints.hit.right = false;
01184 object.collision_solid(constraints.hit);
01185 }
01186 }
01187
01188 constraints = Constraints();
01189 for(int i = 0; i < 2; ++i) {
01190 collision_static(&constraints, movement, dest, object);
01191 if(!constraints.has_constraints())
01192 break;
01193
01194
01195 float width = constraints.get_width ();
01196 if(width < infinity) {
01197 if(width + SHIFT_DELTA < object.get_bbox().get_width()) {
01198 #if 0
01199 printf("Object %p crushed horizontally... L:%f R:%f\n", &object,
01200 constraints.get_position_left(), constraints.get_position_right());
01201 #endif
01202 CollisionHit h;
01203 h.left = true;
01204 h.right = true;
01205 h.crush = true;
01206 object.collision_solid(h);
01207 } else {
01208 float xmid = constraints.get_x_midpoint ();
01209 dest.p1.x = xmid - object.get_bbox().get_width()/2;
01210 dest.p2.x = xmid + object.get_bbox().get_width()/2;
01211 }
01212 } else if(constraints.get_position_right() < infinity) {
01213 dest.p2.x = constraints.get_position_right() - DELTA;
01214 dest.p1.x = dest.p2.x - object.get_bbox().get_width();
01215 } else if(constraints.get_position_left() > -infinity) {
01216 dest.p1.x = constraints.get_position_left() + DELTA;
01217 dest.p2.x = dest.p1.x + object.get_bbox().get_width();
01218 }
01219 }
01220
01221 if(constraints.has_constraints()) {
01222 if( constraints.hit.left || constraints.hit.right
01223 || constraints.hit.top || constraints.hit.bottom
01224 || constraints.hit.crush )
01225 object.collision_solid(constraints.hit);
01226 }
01227
01228
01229 constraints = Constraints();
01230 collision_static(&constraints, movement, dest, object);
01231 if(constraints.get_position_bottom() < infinity) {
01232 float height = constraints.get_height ();
01233 if(height + SHIFT_DELTA < object.get_bbox().get_height()) {
01234 #if 0
01235 printf("Object %p crushed vertically...\n", &object);
01236 #endif
01237 CollisionHit h;
01238 h.top = true;
01239 h.bottom = true;
01240 h.crush = true;
01241 object.collision_solid(h);
01242 }
01243 }
01244 }
01245
01246 namespace {
01247 const float MAX_SPEED = 16.0f;
01248 }
01249
01250 void
01251 Sector::handle_collisions()
01252 {
01253 using namespace collision;
01254
01255
01256 for(MovingObjects::iterator i = moving_objects.begin();
01257 i != moving_objects.end(); ++i) {
01258 MovingObject* moving_object = *i;
01259 Vector mov = moving_object->get_movement();
01260
01261
01262 if (((mov.x > MAX_SPEED * M_SQRT1_2) || (mov.y > MAX_SPEED * M_SQRT1_2)) && (mov.norm() > MAX_SPEED)) {
01263 moving_object->movement = mov.unit() * MAX_SPEED;
01264
01265 }
01266
01267 moving_object->dest = moving_object->get_bbox();
01268 moving_object->dest.move(moving_object->get_movement());
01269 }
01270
01271
01272 for(MovingObjects::iterator i = moving_objects.begin();
01273 i != moving_objects.end(); ++i) {
01274 MovingObject* moving_object = *i;
01275 if((moving_object->get_group() != COLGROUP_MOVING
01276 && moving_object->get_group() != COLGROUP_MOVING_STATIC
01277 && moving_object->get_group() != COLGROUP_MOVING_ONLY_STATIC)
01278 || !moving_object->is_valid())
01279 continue;
01280
01281 collision_static_constrains(*moving_object);
01282 }
01283
01284
01285 for(MovingObjects::iterator i = moving_objects.begin();
01286 i != moving_objects.end(); ++i) {
01287 MovingObject* moving_object = *i;
01288 if((moving_object->get_group() != COLGROUP_MOVING
01289 && moving_object->get_group() != COLGROUP_MOVING_STATIC
01290 && moving_object->get_group() != COLGROUP_MOVING_ONLY_STATIC)
01291 || !moving_object->is_valid())
01292 continue;
01293
01294 uint32_t tile_attributes = collision_tile_attributes(moving_object->dest);
01295 if(tile_attributes >= Tile::FIRST_INTERESTING_FLAG) {
01296 moving_object->collision_tile(tile_attributes);
01297 }
01298 }
01299
01300
01301 for(MovingObjects::iterator i = moving_objects.begin();
01302 i != moving_objects.end(); ++i) {
01303 MovingObject* moving_object = *i;
01304 if((moving_object->get_group() != COLGROUP_MOVING
01305 && moving_object->get_group() != COLGROUP_MOVING_STATIC)
01306 || !moving_object->is_valid())
01307 continue;
01308
01309 for(MovingObjects::iterator i2 = moving_objects.begin();
01310 i2 != moving_objects.end(); ++i2) {
01311 MovingObject* moving_object_2 = *i2;
01312 if(moving_object_2->get_group() != COLGROUP_TOUCHABLE
01313 || !moving_object_2->is_valid())
01314 continue;
01315
01316 if(intersects(moving_object->dest, moving_object_2->dest)) {
01317 Vector normal;
01318 CollisionHit hit;
01319 get_hit_normal(moving_object->dest, moving_object_2->dest,
01320 hit, normal);
01321 if(!moving_object->collides(*moving_object_2, hit))
01322 continue;
01323 if(!moving_object_2->collides(*moving_object, hit))
01324 continue;
01325
01326 moving_object->collision(*moving_object_2, hit);
01327 moving_object_2->collision(*moving_object, hit);
01328 }
01329 }
01330 }
01331
01332
01333 for(MovingObjects::iterator i = moving_objects.begin();
01334 i != moving_objects.end(); ++i) {
01335 MovingObject* moving_object = *i;
01336
01337 if((moving_object->get_group() != COLGROUP_MOVING
01338 && moving_object->get_group() != COLGROUP_MOVING_STATIC)
01339 || !moving_object->is_valid())
01340 continue;
01341
01342 for(MovingObjects::iterator i2 = i+1;
01343 i2 != moving_objects.end(); ++i2) {
01344 MovingObject* moving_object_2 = *i2;
01345 if((moving_object_2->get_group() != COLGROUP_MOVING
01346 && moving_object_2->get_group() != COLGROUP_MOVING_STATIC)
01347 || !moving_object_2->is_valid())
01348 continue;
01349
01350 collision_object(moving_object, moving_object_2);
01351 }
01352 }
01353
01354
01355 for(MovingObjects::iterator i = moving_objects.begin();
01356 i != moving_objects.end(); ++i) {
01357 MovingObject* moving_object = *i;
01358
01359 moving_object->bbox = moving_object->dest;
01360 moving_object->movement = Vector(0, 0);
01361 }
01362 }
01363
01364 bool
01365 Sector::is_free_of_tiles(const Rectf& rect, const bool ignoreUnisolid) const
01366 {
01367 using namespace collision;
01368
01369 for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
01370 TileMap* solids = *i;
01371
01372
01373 Rect test_tiles = solids->get_tiles_overlapping(rect);
01374
01375 for(int x = test_tiles.left; x < test_tiles.right; ++x) {
01376 for(int y = test_tiles.top; y < test_tiles.bottom; ++y) {
01377 const Tile* tile = solids->get_tile(x, y);
01378 if(!tile) continue;
01379 if(!(tile->getAttributes() & Tile::SOLID))
01380 continue;
01381 if(tile->is_unisolid () && ignoreUnisolid)
01382 continue;
01383 if(tile->is_slope ()) {
01384 AATriangle triangle;
01385 Rectf tbbox = solids->get_tile_bbox(x, y);
01386 triangle = AATriangle(tbbox, tile->getData());
01387 Constraints constraints;
01388 if(!collision::rectangle_aatriangle(&constraints, rect, triangle))
01389 continue;
01390 }
01391
01392 return false;
01393 }
01394 }
01395 }
01396
01397 return true;
01398 }
01399
01400 bool
01401 Sector::is_free_of_statics(const Rectf& rect, const MovingObject* ignore_object, const bool ignoreUnisolid) const
01402 {
01403 using namespace collision;
01404
01405 if (!is_free_of_tiles(rect, ignoreUnisolid)) return false;
01406
01407 for(MovingObjects::const_iterator i = moving_objects.begin();
01408 i != moving_objects.end(); ++i) {
01409 const MovingObject* moving_object = *i;
01410 if (moving_object == ignore_object) continue;
01411 if (!moving_object->is_valid()) continue;
01412 if (moving_object->get_group() == COLGROUP_STATIC) {
01413 if(intersects(rect, moving_object->get_bbox())) return false;
01414 }
01415 }
01416
01417 return true;
01418 }
01419
01420 bool
01421 Sector::is_free_of_movingstatics(const Rectf& rect, const MovingObject* ignore_object) const
01422 {
01423 using namespace collision;
01424
01425 if (!is_free_of_tiles(rect)) return false;
01426
01427 for(MovingObjects::const_iterator i = moving_objects.begin();
01428 i != moving_objects.end(); ++i) {
01429 const MovingObject* moving_object = *i;
01430 if (moving_object == ignore_object) continue;
01431 if (!moving_object->is_valid()) continue;
01432 if ((moving_object->get_group() == COLGROUP_MOVING)
01433 || (moving_object->get_group() == COLGROUP_MOVING_STATIC)
01434 || (moving_object->get_group() == COLGROUP_STATIC)) {
01435 if(intersects(rect, moving_object->get_bbox())) return false;
01436 }
01437 }
01438
01439 return true;
01440 }
01441
01442 bool
01443 Sector::add_bullet(const Vector& pos, const PlayerStatus* player_status, float xm, Direction dir)
01444 {
01445
01446
01447 Bullet* new_bullet = 0;
01448 if((player_status->bonus == FIRE_BONUS &&
01449 (int)bullets.size() >= player_status->max_fire_bullets) ||
01450 (player_status->bonus == ICE_BONUS &&
01451 (int)bullets.size() >= player_status->max_ice_bullets))
01452 return false;
01453 new_bullet = new Bullet(pos, xm, dir, player_status->bonus);
01454 add_object(new_bullet);
01455
01456 sound_manager->play("sounds/shoot.wav");
01457
01458 return true;
01459 }
01460
01461 bool
01462 Sector::add_smoke_cloud(const Vector& pos)
01463 {
01464 add_object(new SmokeCloud(pos));
01465 return true;
01466 }
01467
01468 void
01469 Sector::play_music(MusicType type)
01470 {
01471 currentmusic = type;
01472 switch(currentmusic) {
01473 case LEVEL_MUSIC:
01474 sound_manager->play_music(music);
01475 break;
01476 case HERRING_MUSIC:
01477 sound_manager->play_music("music/invincible.ogg");
01478 break;
01479 case HERRING_WARNING_MUSIC:
01480 sound_manager->stop_music(TUX_INVINCIBLE_TIME_WARNING);
01481 break;
01482 default:
01483 sound_manager->play_music("");
01484 break;
01485 }
01486 }
01487
01488 MusicType
01489 Sector::get_music_type()
01490 {
01491 return currentmusic;
01492 }
01493
01494 int
01495 Sector::get_total_badguys()
01496 {
01497 int total_badguys = 0;
01498 for(GameObjects::iterator i = gameobjects.begin();
01499 i != gameobjects.end(); ++i) {
01500 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
01501 if (badguy && badguy->countMe)
01502 total_badguys++;
01503 }
01504
01505 return total_badguys;
01506 }
01507
01508 bool
01509 Sector::inside(const Rectf& rect) const
01510 {
01511 for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
01512 TileMap* solids = *i;
01513
01514 Rectf bbox = solids->get_bbox();
01515 bbox.p1.y = -INFINITY;
01516
01517 if (bbox.contains(rect))
01518 return true;
01519 }
01520 return false;
01521 }
01522
01523 float
01524 Sector::get_width() const
01525 {
01526 float width = 0;
01527 for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin();
01528 i != solid_tilemaps.end(); i++) {
01529 TileMap* solids = *i;
01530 width = std::max(width, solids->get_bbox().get_right());
01531 }
01532
01533 return width;
01534 }
01535
01536 float
01537 Sector::get_height() const
01538 {
01539 float height = 0;
01540 for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin();
01541 i != solid_tilemaps.end(); i++) {
01542 TileMap* solids = *i;
01543 height = std::max(height, solids->get_bbox().get_bottom());
01544 }
01545
01546 return height;
01547 }
01548
01549 void
01550 Sector::change_solid_tiles(uint32_t old_tile_id, uint32_t new_tile_id)
01551 {
01552 for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
01553 TileMap* solids = *i;
01554 solids->change_all(old_tile_id, new_tile_id);
01555 }
01556 }
01557
01558 void
01559 Sector::set_ambient_light(float red, float green, float blue)
01560 {
01561 ambient_light.red = red;
01562 ambient_light.green = green;
01563 ambient_light.blue = blue;
01564 }
01565
01566 float
01567 Sector::get_ambient_red()
01568 {
01569 return ambient_light.red;
01570 }
01571
01572 float
01573 Sector::get_ambient_green()
01574 {
01575 return ambient_light.green;
01576 }
01577
01578 float
01579 Sector::get_ambient_blue()
01580 {
01581 return ambient_light.blue;
01582 }
01583
01584 void
01585 Sector::set_gravity(float gravity)
01586 {
01587 log_warning << "Changing a Sector's gravitational constant might have unforeseen side-effects" << std::endl;
01588 this->gravity = gravity;
01589 }
01590
01591 float
01592 Sector::get_gravity() const
01593 {
01594 return gravity;
01595 }
01596
01597 Player*
01598 Sector::get_nearest_player (const Vector& pos)
01599 {
01600 Player *nearest_player = NULL;
01601 float nearest_dist = std::numeric_limits<float>::max();
01602
01603 std::vector<Player*> players = Sector::current()->get_players();
01604 for (std::vector<Player*>::iterator playerIter = players.begin();
01605 playerIter != players.end();
01606 ++playerIter)
01607 {
01608 Player *this_player = *playerIter;
01609 if (this_player->is_dying() || this_player->is_dead())
01610 continue;
01611
01612 float this_dist = this_player->get_bbox ().distance(pos);
01613
01614 if (this_dist < nearest_dist) {
01615 nearest_player = this_player;
01616 nearest_dist = this_dist;
01617 }
01618 }
01619
01620 return nearest_player;
01621 }
01622
01623 std::vector<MovingObject*>
01624 Sector::get_nearby_objects (const Vector& center, float max_distance)
01625 {
01626 std::vector<MovingObject*> ret;
01627 std::vector<Player*> players = Sector::current()->get_players();
01628
01629 for (size_t i = 0; i < players.size (); i++) {
01630 float distance = players[i]->get_bbox ().distance (center);
01631 if (distance <= max_distance)
01632 ret.push_back (players[i]);
01633 }
01634
01635 for (size_t i = 0; i < moving_objects.size (); i++) {
01636 float distance = moving_objects[i]->get_bbox ().distance (center);
01637 if (distance <= max_distance)
01638 ret.push_back (moving_objects[i]);
01639 }
01640
01641 return (ret);
01642 }
01643
01644
01645