/** * Checks whether a collision occurs between self and other if self * moves from (x,y) to (new_x, new_y) in direction d. * * If other is a tile event, also indicates if the player can use it * as a "bridge" to step across without hitting the underlying tile * layer. */ static CollisionResult TestCollisionDuringMove( int x, int y, int new_x, int new_y, int d, const Game_Character& self, const Game_Event& other ) { if (!other.GetActive()) { return NoCollision; } if (&self == &other) { return NoCollision; } if (other.GetThrough()) { return NoCollision; } if (!other.IsInPosition(x, y) && !other.IsInPosition(new_x, new_y)) { return NoCollision; } if (&self != Main_Data::game_player.get()) { if (other.IsInPosition(new_x, new_y) && (self.IsOverlapForbidden() || other.IsOverlapForbidden())) { return Collision; } } if (other.IsInPosition(new_x, new_y) && self.GetLayer() == other.GetLayer()) { return Collision; } if (other.GetLayer() == RPG::EventPage::Layers_below) { int tile_id = other.GetTileId(); if ((passages_up[tile_id] & Passable::Above) != 0) { return NoCollision; } if (other.IsInPosition(x,y) && (passages_up[tile_id] & DirToMask(d)) != 0) { return CanStepOffCurrentTile; } else if (other.IsInPosition(new_x, new_y) && (passages_up[tile_id] & DirToMask(Game_Character::ReverseDir(d))) != 0) { return CanStepOntoNewTile; } else { return Collision; } } return NoCollision; }
bool Game_Map::MakeWay(int x, int y, int d, const Game_Character& self, bool force_through) { int new_x = RoundX(x + (d == Game_Character::Right ? 1 : d == Game_Character::Left ? -1 : 0)); int new_y = RoundY(y + (d == Game_Character::Down ? 1 : d == Game_Character::Up ? -1 : 0)); if (!Game_Map::IsValid(new_x, new_y)) return false; if (self.GetThrough() || force_through) return true; // A character can move to a position with an impassable tile by // standing on top of an event below it. These flags track whether // we stepped off an event and therefore don't need to check the // passability of the tile layer below. bool stepped_off_event = false; bool stepped_onto_event = false; for (Game_Event& other : GetEvents()) { CollisionResult result = TestCollisionDuringMove(x, y, new_x, new_y, d, self, other); if (result == Collision) { // Try updating the offending event to give it a chance to move out of the // way and recheck. other.UpdateParallel(); if (TestCollisionDuringMove(x, y, new_x, new_y, d, self, other) == Collision) { return false; } } else if (result == CanStepOffCurrentTile) { stepped_off_event = true; } else if (result == CanStepOntoNewTile) { stepped_onto_event = true; } } if (vehicles[0]->IsInPosition(new_x, new_y) || vehicles[1]->IsInPosition(new_x, new_y)) { return false; } if (Main_Data::game_player->IsInPosition(new_x, new_y) && !Main_Data::game_player->GetThrough() && self.GetLayer() == RPG::EventPage::Layers_same) { // Update the Player to see if they'll move and recheck. Main_Data::game_player->Update(!first_frame); if (Main_Data::game_player->IsInPosition(new_x, new_y)) { return false; } } return (stepped_off_event || IsPassableTile(DirToMask(d), x + y * GetWidth())) && (stepped_onto_event || IsPassableTile(DirToMask(Game_Character::ReverseDir(d)), new_x + new_y * GetWidth())); }
void Walk(const char* path,POINT &pos,POINT &dir, POINT &minpt,POINT &maxpt) { POINT enter_dir=dir;///enter direction for cell path++; pos+=dir; ///enter maze for(;*path;path++) { switch(*path) { case 'W': if(minpt.real()>pos.real())minpt.real()=pos.real(); if(minpt.imag()>pos.imag())minpt.imag()=pos.imag(); if(maxpt.real()<pos.real())maxpt.real()=pos.real(); if(maxpt.imag()<pos.imag())maxpt.imag()=pos.imag(); ///break walls in enter and exit directions maze[std::make_pair(pos.real(),pos.imag())]|=DirToMask(-enter_dir); maze[std::make_pair(pos.real(),pos.imag())]|=DirToMask(+dir); pos+=dir; enter_dir=dir; break; case 'L': dir*=POINT(0,1); break; case 'R': dir*=POINT(0,-1); break; } } }
bool Game_Map::IsPassable(int x, int y, int d, const Game_Character* self_event) { // TODO: this and MakeWay share a lot of code. if (!Game_Map::IsValid(x, y)) return false; int bit = DirToMask(d); int tile_id; if (self_event) { bool pass = false; std::vector<Game_Event*> events; std::vector<Game_Event*>::iterator it; Game_Map::GetEventsXY(events, x, y); for (it = events.begin(); it != events.end(); ++it) { if (*it == self_event || (*it)->GetThrough()) { continue; } if (self_event != Main_Data::game_player.get()) { if (self_event->IsOverlapForbidden() || (*it)->IsOverlapForbidden()) return false; } if ((*it)->GetLayer() == self_event->GetLayer()) { if (self_event->IsInPosition(x, y)) pass = true; else return false; } else if ((*it)->GetLayer() == RPG::EventPage::Layers_below) { // Event layer Chipset Tile tile_id = (*it)->GetTileId(); if ((passages_up[tile_id] & Passable::Above) != 0) continue; if ((passages_up[tile_id] & bit) != 0) pass = true; else return false; } } if (!self_event->IsInPosition(x, y) && (vehicles[0]->IsInPosition(x, y) || vehicles[1]->IsInPosition(x, y))) return false; if (pass) // All events here are passable return true; } return IsPassableTile(bit, x + y * GetWidth()); }