Sector::Sector(Level* parent)
: level(parent), currentmusic(LEVEL_MUSIC), gravity(10),
- player(0), solids(0), camera(0)
+ player(0), camera(0)
{
add_object(new Player(player_status));
add_object(new DisplayEffect());
Sector::~Sector()
{
using namespace Scripting;
-
+
deactivate();
for(ScriptList::iterator i = scripts.begin();
}
sq_release(global_vm, §or_table);
sq_collectgarbage(global_vm);
-
+
update_game_objects();
assert(gameobjects_new.size() == 0);
return partsys;
} else if(name == "money") { // for compatibility with old maps
return new Jumpy(reader);
- }
+ }
try {
return create_object(name, reader);
} catch(std::exception& e) {
log_warning << e.what() << "" << std::endl;
}
-
+
return 0;
}
void
Sector::parse(const lisp::Lisp& sector)
-{
+{
lisp::ListIterator iter(§or);
while(iter.next()) {
const std::string& token = iter.item();
update_game_objects();
- if(!solids)
- throw std::runtime_error("sector does not contain a solid tile layer.");
+ if(solid_tilemaps.size() < 1) log_warning << "sector '" << name << "' does not contain a solid tile layer." << std::endl;
fix_old_tiles();
if(!camera) {
bkgd_top.red = static_cast<float> (r) / 255.0f;
bkgd_top.green = static_cast<float> (g) / 255.0f;
bkgd_top.blue = static_cast<float> (b) / 255.0f;
-
+
reader.get("bkgd_red_bottom", r);
reader.get("bkgd_green_bottom", g);
reader.get("bkgd_blue_bottom", b);
bkgd_bottom.red = static_cast<float> (r) / 255.0f;
bkgd_bottom.green = static_cast<float> (g) / 255.0f;
bkgd_bottom.blue = static_cast<float> (b) / 255.0f;
-
+
if(backgroundimage != "") {
Background* background = new Background();
background->set_image(
int width = 30, height = 15;
reader.get("width", width);
reader.get("height", height);
-
+
std::vector<unsigned int> tiles;
if(reader.get_vector("interactive-tm", tiles)
|| reader.get_vector("tilemap", tiles)) {
update_game_objects();
- if(solids == 0)
- throw std::runtime_error("sector does not contain a solid tile layer.");
+ if(solid_tilemaps.size() < 1) log_warning << "sector '" << name << "' does not contain a solid tile layer." << std::endl;
fix_old_tiles();
update_game_objects();
Sector::fix_old_tiles()
{
// hack for now...
- for(size_t x=0; x < solids->get_width(); ++x) {
- for(size_t y=0; y < solids->get_height(); ++y) {
- const Tile* tile = solids->get_tile(x, y);
- Vector pos(x*32, y*32);
-
- if(tile->getID() == 112) {
- add_object(new InvisibleBlock(pos));
- solids->change(x, y, 0);
- } else if(tile->getAttributes() & Tile::COIN) {
- add_object(new Coin(pos));
- solids->change(x, y, 0);
- } else if(tile->getAttributes() & Tile::FULLBOX) {
- add_object(new BonusBlock(pos, tile->getData()));
- solids->change(x, y, 0);
- } else if(tile->getAttributes() & Tile::BRICK) {
- add_object(new Brick(pos, tile->getData()));
- solids->change(x, y, 0);
- } else if(tile->getAttributes() & Tile::GOAL) {
- std::string sequence = tile->getData() == 0 ? "endsequence" : "stoptux";
- add_object(new SequenceTrigger(pos, sequence));
- solids->change(x, y, 0);
+ for(std::list<TileMap*>::iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+ for(size_t x=0; x < solids->get_width(); ++x) {
+ for(size_t y=0; y < solids->get_height(); ++y) {
+ const Tile* tile = solids->get_tile(x, y);
+ Vector pos(solids->get_x_offset() + x*32, solids->get_y_offset() + y*32);
+
+ if(tile->getID() == 112) {
+ add_object(new InvisibleBlock(pos));
+ solids->change(x, y, 0);
+ } else if(tile->getAttributes() & Tile::COIN) {
+ add_object(new Coin(pos));
+ solids->change(x, y, 0);
+ } else if(tile->getAttributes() & Tile::FULLBOX) {
+ add_object(new BonusBlock(pos, tile->getData()));
+ solids->change(x, y, 0);
+ } else if(tile->getAttributes() & Tile::BRICK) {
+ add_object(new Brick(pos, tile->getData()));
+ solids->change(x, y, 0);
+ } else if(tile->getAttributes() & Tile::GOAL) {
+ std::string sequence = tile->getData() == 0 ? "endsequence" : "stoptux";
+ add_object(new SequenceTrigger(pos, sequence));
+ solids->change(x, y, 0);
+ }
}
}
}
i = scripts.erase(i);
continue;
}
-
+
++i;
}
-
+
HSQOBJECT object = create_thread(global_vm);
scripts.push_back(object);
sp = *i;
break;
}
- }
+ }
if(!sp) {
log_warning << "Spawnpoint '" << spawnpoint << "' not found." << std::endl;
if(spawnpoint != "main") {
if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
throw Scripting::SquirrelError(vm, "Couldn't unset sector in roottable");
sq_pop(vm, 1);
-
+
for(GameObjects::iterator i = gameobjects.begin();
i != gameobjects.end(); ++i) {
GameObject* object = *i;
-
+
try_unexpose(object);
}
GameObject* object = *i;
if(!object->is_valid())
continue;
-
+
object->update(elapsed_time);
}
-
+
/* Handle all possible collisions. */
handle_collisions();
update_game_objects();
for(std::vector<GameObject*>::iterator i = gameobjects.begin();
i != gameobjects.end(); /* nothing */) {
GameObject* object = *i;
-
+
if(object->is_valid()) {
++i;
continue;
}
before_object_remove(object);
-
+
object->unref();
i = gameobjects.erase(i);
}
GameObject* object = *i;
before_object_add(object);
-
+
gameobjects.push_back(object);
}
gameobjects_new.clear();
if(movingobject) {
moving_objects.push_back(movingobject);
}
-
+
TileMap* tilemap = dynamic_cast<TileMap*> (object);
- if(tilemap && tilemap->is_solid()) {
- if(solids == 0) {
- solids = tilemap;
- } else {
- log_warning << "Another solid tilemaps added. Ignoring" << std::endl;
- }
- }
+ if(tilemap && tilemap->is_solid()) solid_tilemaps.push_back(tilemap);
Camera* camera = dynamic_cast<Camera*> (object);
if(camera) {
if(_current == this) {
try_expose(object);
}
-
+
return true;
}
}
sq_settop(vm, oldtop);
}
-}
+}
void
Sector::draw(DrawingContext& context)
for(GameObjects::iterator i = gameobjects.begin();
i != gameobjects.end(); ++i) {
- GameObject* object = *i;
+ GameObject* object = *i;
if(!object->is_valid())
continue;
}
/*-------------------------------------------------------------------------
- * Collision Detection
+ * Collision Detection
*-------------------------------------------------------------------------*/
static const float SHIFT_DELTA = 7.0f;
float y1 = dest.get_top();
float y2 = dest.get_bottom();
- // test with all tiles in this rectangle
- int starttilex = int(x1) / 32;
- int starttiley = int(y1) / 32;
- int max_x = int(x2);
- int max_y = int(y2+1);
-
- for(int x = starttilex; x*32 < max_x; ++x) {
- for(int y = starttiley; y*32 < max_y; ++y) {
- const Tile* tile = solids->get_tile(x, y);
- if(!tile)
- continue;
- // skip non-solid tiles
- if((tile->getAttributes() & Tile::SOLID) == 0)
- continue;
- // only handle unisolid when the player is falling down and when he was
- // above the tile before
- if(tile->getAttributes() & Tile::UNISOLID) {
- if(movement.y <= 0 || dest.get_bottom() - movement.y - SHIFT_DELTA > y*32)
- continue;
- }
-
- if(tile->getAttributes() & Tile::SLOPE) { // slope tile
- AATriangle triangle;
- Vector p1(x*32, y*32);
- Vector p2((x+1)*32, (y+1)*32);
- triangle = AATriangle(p1, p2, tile->getData());
-
- collision::rectangle_aatriangle(constraints, dest, triangle);
- } else { // normal rectangular tile
- Rect rect(x*32, y*32, (x+1)*32, (y+1)*32);
- check_collisions(constraints, movement, dest, rect);
+ for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+
+ // test with all tiles in this rectangle
+ int starttilex = int(x1 - solids->get_x_offset()) / 32;
+ int starttiley = int(y1 - solids->get_y_offset()) / 32;
+ int max_x = int(x2 - solids->get_x_offset());
+ int max_y = int(y2+1 - solids->get_y_offset());
+
+ for(int x = starttilex; x*32 < max_x; ++x) {
+ for(int y = starttiley; y*32 < max_y; ++y) {
+ const Tile* tile = solids->get_tile(x, y);
+ if(!tile)
+ continue;
+ // skip non-solid tiles
+ if((tile->getAttributes() & Tile::SOLID) == 0)
+ continue;
+ // only handle unisolid when the player is falling down and when he was
+ // above the tile before
+ if(tile->getAttributes() & Tile::UNISOLID) {
+ if(movement.y <= 0 || dest.get_bottom() - movement.y - SHIFT_DELTA > y*32)
+ continue;
+ }
+
+ if(tile->getAttributes() & Tile::SLOPE) { // slope tile
+ AATriangle triangle;
+ Vector p1(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset());
+ Vector p2((x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
+ triangle = AATriangle(p1, p2, tile->getData());
+
+ collision::rectangle_aatriangle(constraints, dest, triangle);
+ } else { // normal rectangular tile
+ Rect rect(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset(), (x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
+ check_collisions(constraints, movement, dest, rect);
+ }
}
}
}
float x2 = dest.p2.x;
float y2 = dest.p2.y;
- // test with all tiles in this rectangle
- int starttilex = int(x1) / 32;
- int starttiley = int(y1) / 32;
- int max_x = int(x2);
- int max_y = int(y2);
-
uint32_t result = 0;
- for(int x = starttilex; x*32 < max_x; ++x) {
- for(int y = starttiley; y*32 < max_y; ++y) {
- const Tile* tile = solids->get_tile(x, y);
- if(!tile)
- continue;
- result |= tile->getAttributes();
+ for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+
+ // test with all tiles in this rectangle
+ int starttilex = int(x1 - solids->get_x_offset()) / 32;
+ int starttiley = int(y1 - solids->get_y_offset()) / 32;
+ int max_x = int(x2 - solids->get_x_offset());
+ int max_y = int(y2+1 - solids->get_y_offset());
+
+ for(int x = starttilex; x*32 < max_x; ++x) {
+ for(int y = starttiley; y*32 < max_y; ++y) {
+ const Tile* tile = solids->get_tile(x, y);
+ if(!tile)
+ continue;
+ result |= tile->getAttributes();
+ }
}
}
Sector::collision_object(MovingObject* object1, MovingObject* object2) const
{
using namespace collision;
-
+
const Rect& r1 = object1->dest;
const Rect& r2 = object2->dest;
if(moving_object->get_group() != COLGROUP_STATIC
|| !moving_object->is_valid())
continue;
-
+
check_collisions(constraints, movement, dest, moving_object->dest,
&object, moving_object);
}
}
-void
+void
Sector::collision_static_constrains(MovingObject& object)
{
using namespace collision;
}
if(constraints.has_constraints()) {
- if( constraints.hit.left || constraints.hit.right
- || constraints.hit.top || constraints.hit.bottom
+ if( constraints.hit.left || constraints.hit.right
+ || constraints.hit.top || constraints.hit.bottom
|| constraints.hit.crush )
object.collision_solid(constraints.hit);
- }
+ }
// an extra pass to make sure we're not crushed horizontally
constraints = Constraints();
h.top = true;
h.bottom = true;
h.crush = true;
- object.collision_solid(h);
+ object.collision_solid(h);
}
}
}
Sector::handle_collisions()
{
using namespace collision;
-
+
// calculate destination positions of the objects
for(MovingObjects::iterator i = moving_objects.begin();
i != moving_objects.end(); ++i) {
moving_object->collision(*moving_object_2, hit);
moving_object_2->collision(*moving_object, hit);
}
- }
+ }
}
// part3: COLGROUP_MOVING vs COLGROUP_MOVING
continue;
collision_object(moving_object, moving_object_2);
- }
+ }
}
// apply object movement
Sector::is_free_space(const Rect& rect) const
{
using namespace collision;
-
- // test with all tiles in this rectangle
- int starttilex = int(rect.p1.x) / 32;
- int starttiley = int(rect.p1.y) / 32;
- int max_x = int(rect.p2.x);
- int max_y = int(rect.p2.y);
-
- for(int x = starttilex; x*32 <= max_x; ++x) {
- for(int y = starttiley; y*32 <= max_y; ++y) {
- const Tile* tile = solids->get_tile(x, y);
- if(!tile)
- continue;
- if(tile->getAttributes() & Tile::SLOPE) {
- AATriangle triangle;
- Vector p1(x*32, y*32);
- Vector p2((x+1)*32, (y+1)*32);
- triangle = AATriangle(p1, p2, tile->getData());
- Constraints constraints;
- return collision::rectangle_aatriangle(&constraints, rect, triangle);
+
+ for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+
+ // test with all tiles in this rectangle
+ int starttilex = int(rect.p1.x - solids->get_x_offset()) / 32;
+ int starttiley = int(rect.p1.y - solids->get_y_offset()) / 32;
+ int max_x = int(rect.p2.x - solids->get_x_offset());
+ int max_y = int(rect.p2.y - solids->get_y_offset());
+
+ for(int x = starttilex; x*32 <= max_x; ++x) {
+ for(int y = starttiley; y*32 <= max_y; ++y) {
+ const Tile* tile = solids->get_tile(x, y);
+ if(!tile) continue;
+ if(tile->getAttributes() & Tile::SLOPE) {
+ AATriangle triangle;
+ Vector p1(x*32 + solids->get_x_offset(), y*32 + solids->get_y_offset());
+ Vector p2((x+1)*32 + solids->get_x_offset(), (y+1)*32 + solids->get_y_offset());
+ triangle = AATriangle(p1, p2, tile->getData());
+ Constraints constraints;
+ return collision::rectangle_aatriangle(&constraints, rect, triangle);
+ }
+ if(tile->getAttributes() & Tile::SOLID) return false;
}
- // FIXME: also test unisolid tiles
- if(tile->getAttributes() & Tile::SOLID)
- return false;
}
}
bool
Sector::inside(const Rect& rect) const
{
- if(rect.p1.x > solids->get_width() * 32
- || rect.p1.y > solids->get_height() * 32
- || rect.p2.x < 0)
- return false;
+ for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+ bool horizontally = ((rect.p2.x >= 0 + solids->get_x_offset()) && (rect.p1.x <= solids->get_width() * 32 + solids->get_x_offset()));
+ bool vertically = (rect.p1.y <= solids->get_height() * 32 + solids->get_y_offset());
+ if (horizontally && vertically) return true;
+ }
+ return false;
+}
- return true;
+float
+Sector::get_width() const
+{
+ float width = 0;
+ for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+ if ((solids->get_width() * 32 + solids->get_x_offset()) > width) width = (solids->get_width() * 32 + solids->get_x_offset());
+ }
+ return width;
+}
+
+float
+Sector::get_height() const
+{
+ float height = 0;
+ for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+ if ((solids->get_height() * 32 + solids->get_y_offset()) > height) height = (solids->get_height() * 32 + solids->get_y_offset());
+ }
+ return height;
+}
+
+void
+Sector::change_solid_tiles(uint32_t old_tile_id, uint32_t new_tile_id)
+{
+ for(std::list<TileMap*>::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
+ TileMap* solids = *i;
+ solids->change_all(old_tile_id, new_tile_id);
+ }
}