diff --git a/CMakeLists.txt b/CMakeLists.txt index d3d6567dd..d5ed9ddd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,7 +180,6 @@ set(OD_SOURCEFILES ${SRC}/CullingManager.cpp ${SRC}/CullingQuad.cpp ${SRC}/DummyArrayClass.cpp - ${SRC}/DirectionalTrap.cpp ${SRC}/EditorMode.cpp ${SRC}/FppMode.cpp ${SRC}/GameEntity.cpp @@ -207,7 +206,9 @@ set(OD_SOURCEFILES ${SRC}/MenuModeMultiplayerServer.cpp ${SRC}/MenuModeSkirmish.cpp ${SRC}/MiniMap.cpp + ${SRC}/MissileBoulder.cpp ${SRC}/MissileObject.cpp + ${SRC}/MissileOneHit.cpp ${SRC}/ModeManager.cpp ${SRC}/MortuaryQuad.cpp ${SRC}/MovableGameEntity.cpp diff --git a/CREDITS b/CREDITS index 81e9f2da2..a56cf3b0f 100644 --- a/CREDITS +++ b/CREDITS @@ -116,7 +116,8 @@ textures/ -> TentacleBed.png West CC0 http://forum.freegamedev.net/viewtopic.php?p=60091#p60091 -> TrainingDummy2_texture.png Danimal CC-BY-SA 3.0 http://forum.freegamedev.net/viewtopic.php?p=59239#p59239 -> TrainingDummy3.png P0ss CC-BY 3.0 http://forum.freegamedev.net/viewtopic.php?p=59351#p59351 --> TrainingDummy4.png Nobiax CC0 http://forum.freegamedev.net/viewtopic.php?p=59621#p59621p=59621#p59621 +-> TrainingDummy4.png Nobiax CC0 http://forum.freegamedev.net/viewtopic.php?p=59621#p59621 +-> Boulder.png Nobiax CC0 http://forum.freegamedev.net/viewtopic.php?p=59832#p59832 ====================== @@ -210,6 +211,7 @@ Troll_Rock.mesh Dm3d CC-BY-SA 3.0 Water* Skorpio CC-BY-SA 3.0, GPL 3.0 Wizard.* Skorpio CC-BY-SA 3.0, GPL 3.0 Wyvern.* Andrew Buck, Skorpio CC-BY-SA 3.0, GPL 3.0 +Boulder.* Danimal CC-BY-SA 3.0 http://forum.freegamedev.net/viewtopic.php?p=59832#p59832 ==================== diff --git a/gui/OpenDungeonsIcons.imageset b/gui/OpenDungeonsIcons.imageset index 20cec7a3f..c9c9b48f3 100644 --- a/gui/OpenDungeonsIcons.imageset +++ b/gui/OpenDungeonsIcons.imageset @@ -19,5 +19,6 @@ + \ No newline at end of file diff --git a/gui/OpenDungeonsIcons.png b/gui/OpenDungeonsIcons.png index 1363811ec..9b45e517a 100644 Binary files a/gui/OpenDungeonsIcons.png and b/gui/OpenDungeonsIcons.png differ diff --git a/gui/OpenDungeonsMenuTraps.layout b/gui/OpenDungeonsMenuTraps.layout index 4e470f6af..6ef4d152f 100644 --- a/gui/OpenDungeonsMenuTraps.layout +++ b/gui/OpenDungeonsMenuTraps.layout @@ -19,6 +19,12 @@ + + + + + + diff --git a/materials/scripts/Boulder.material b/materials/scripts/Boulder.material new file mode 100644 index 000000000..cd31bb8d2 --- /dev/null +++ b/materials/scripts/Boulder.material @@ -0,0 +1,42 @@ +// Boulder genrated by blender2ogre 0.6.0 + +material Boulder +{ + receive_shadows on + + technique + { + pass Boulder + { + ambient 0.800000011920929 0.800000011920929 0.800000011920929 1.0 + diffuse 0.6400000190734865 0.6400000190734865 0.6400000190734865 1.0 + specular 0.0 0.0 0.0 1.0 12.5 + emissive 0.0 0.0 0.0 1.0 + + alpha_to_coverage off + colour_write on + cull_hardware clockwise + depth_check on + depth_func less_equal + depth_write on + illumination_stage + light_clip_planes off + light_scissor off + lighting on + normalise_normals off + polygon_mode solid + scene_blend one zero + scene_blend_op add + shading gouraud + transparent_sorting on + + texture_unit + { + texture Boulder.png + tex_address_mode wrap + scale 1.0 1.0 + colour_op modulate + } + } + } +} diff --git a/materials/textures/Boulder.png b/materials/textures/Boulder.png new file mode 100644 index 000000000..d5ab3e5ae Binary files /dev/null and b/materials/textures/Boulder.png differ diff --git a/models/Boulder.mesh b/models/Boulder.mesh new file mode 100644 index 000000000..16547f112 Binary files /dev/null and b/models/Boulder.mesh differ diff --git a/source/ChickenEntity.cpp b/source/ChickenEntity.cpp index 65e650efb..ceb081349 100644 --- a/source/ChickenEntity.cpp +++ b/source/ChickenEntity.cpp @@ -18,7 +18,6 @@ #include "ChickenEntity.h" #include "ODPacket.h" #include "GameMap.h" -#include "RoomTreasury.h" #include "Random.h" #include "LogManager.h" @@ -30,16 +29,18 @@ const int32_t NB_TURNS_DIE_BEFORE_REMOVE = 5; ChickenEntity::ChickenEntity(GameMap* gameMap, const std::string& hatcheryName) : RenderedMovableEntity(gameMap, hatcheryName, "Chicken", 0.0f), mChickenState(ChickenState::free), - nbTurnOutsideHatchery(0), - nbTurnDie(0) + mNbTurnOutsideHatchery(0), + mNbTurnDie(0), + mIsDropped(false) { } ChickenEntity::ChickenEntity(GameMap* gameMap) : RenderedMovableEntity(gameMap), mChickenState(ChickenState::free), - nbTurnOutsideHatchery(0), - nbTurnDie(0) + mNbTurnOutsideHatchery(0), + mNbTurnDie(0), + mIsDropped(false) { setMeshName("Chicken"); } @@ -52,7 +53,7 @@ void ChickenEntity::doUpkeep() return; Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return; @@ -61,9 +62,9 @@ void ChickenEntity::doUpkeep() if(mChickenState == ChickenState::dying) { - if(nbTurnDie < NB_TURNS_DIE_BEFORE_REMOVE) + if(mNbTurnDie < NB_TURNS_DIE_BEFORE_REMOVE) { - nbTurnDie++; + ++mNbTurnDie; return; } mChickenState = ChickenState::dead; @@ -82,19 +83,19 @@ void ChickenEntity::doUpkeep() Room* currentHatchery = tile->getCoveringRoom(); if((currentHatchery != nullptr) && (currentHatchery->getType() == Room::RoomType::hatchery)) { - nbTurnOutsideHatchery = 0; + mNbTurnOutsideHatchery = 0; } else { // If we are outside a hatchery for too long, we die - if(nbTurnOutsideHatchery >= NB_TURNS_OUTSIDE_HATCHERY_BEFORE_DIE) + if(mNbTurnOutsideHatchery >= NB_TURNS_OUTSIDE_HATCHERY_BEFORE_DIE) { mChickenState = ChickenState::dying; tile->removeChickenEntity(this); setAnimationState("Die", false); return; } - ++nbTurnOutsideHatchery; + ++mNbTurnOutsideHatchery; } // Handle normal behaviour : move or pick (if not already moving) @@ -173,8 +174,8 @@ bool ChickenEntity::tryPickup(Seat* seat, bool isEditorMode) return false; Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != NULL, "tile=" + Tile::displayAsString(tile)); - if(tile == NULL) + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); + if(tile == nullptr) return false; if(!tile->isClaimedForSeat(seat) && !isEditorMode) @@ -187,7 +188,7 @@ void ChickenEntity::pickup() { Tile* tile = getPositionTile(); RenderedMovableEntity::pickup(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return; OD_ASSERT_TRUE(tile->removeChickenEntity(this)); @@ -209,6 +210,13 @@ bool ChickenEntity::tryDrop(Seat* seat, Tile* tile, bool isEditorMode) return false; } +void ChickenEntity::drop(const Ogre::Vector3& v) +{ + mIsDropped = true; + RenderedMovableEntity::drop(v); + mIsDropped = false; +} + void ChickenEntity::setPosition(const Ogre::Vector3& v) { if(!getIsOnMap()) @@ -220,21 +228,22 @@ void ChickenEntity::setPosition(const Ogre::Vector3& v) Tile* oldTile = getPositionTile(); RenderedMovableEntity::setPosition(v); Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return; - if(tile == oldTile) + if(!mIsDropped && (tile == oldTile)) return; + if(oldTile != nullptr) oldTile->removeChickenEntity(this); - tile->addChickenEntity(this); + OD_ASSERT_TRUE(tile->addChickenEntity(this)); } bool ChickenEntity::eatChicken(Creature* creature) { Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return false; @@ -246,72 +255,20 @@ bool ChickenEntity::eatChicken(Creature* creature) return true; } -const char* ChickenEntity::getFormat() -{ - // TODO : implement saving/loading in the level file - return "position"; -} - ChickenEntity* ChickenEntity::getChickenEntityFromStream(GameMap* gameMap, std::istream& is) { ChickenEntity* obj = new ChickenEntity(gameMap); - Ogre::Vector3 position; - Ogre::Real x, y, z; - OD_ASSERT_TRUE(is >> x >> y >> z); - obj->setPosition(Ogre::Vector3(x, y, z)); - Tile* tile = obj->getPositionTile(); - OD_ASSERT_TRUE(tile != nullptr); - if(tile != nullptr) - tile->addChickenEntity(obj); return obj; - } -ChickenEntity* ChickenEntity::getChickenEntityFromPacket(GameMap* gameMap, ODPacket& packet) +ChickenEntity* ChickenEntity::getChickenEntityFromPacket(GameMap* gameMap, ODPacket& is) { ChickenEntity* obj = new ChickenEntity(gameMap); - OD_ASSERT_TRUE(packet >> obj); - Tile* tile = obj->getPositionTile(); - OD_ASSERT_TRUE(tile != nullptr); - if(tile != nullptr) - tile->addChickenEntity(obj); - return obj; } -void ChickenEntity::exportToPacket(ODPacket& packet) -{ - packet << this; -} - -std::ostream& operator<<(std::ostream& os, ChickenEntity* obj) -{ - std::string name = obj->getName(); - Ogre::Vector3 position = obj->getPosition(); - os << name; - os << position.x; - os << position.y; - os << position.z; - return os; -} - -ODPacket& operator>>(ODPacket& is, ChickenEntity* obj) -{ - std::string name; - OD_ASSERT_TRUE(is >> name); - obj->setName(name); - Ogre::Vector3 position; - OD_ASSERT_TRUE(is >> position); - obj->setPosition(position); - return is; -} - -ODPacket& operator<<(ODPacket& os, ChickenEntity* obj) +const char* ChickenEntity::getFormat() { - std::string name = obj->getName(); - std::string meshName = obj->getMeshName(); - Ogre::Vector3 position = obj->getPosition(); - os << name; - os << position; - return os; + // TODO : implement saving/loading in the level file + return "position"; } diff --git a/source/ChickenEntity.h b/source/ChickenEntity.h index eea54bbfa..30a21492f 100644 --- a/source/ChickenEntity.h +++ b/source/ChickenEntity.h @@ -42,19 +42,16 @@ class ChickenEntity: public RenderedMovableEntity { return RenderedMovableEntityType::chickenEntity; } virtual bool tryPickup(Seat* seat, bool isEditorMode); + virtual void pickup(); virtual bool tryDrop(Seat* seat, Tile* tile, bool isEditorMode); + virtual void drop(const Ogre::Vector3& v); - virtual void exportToPacket(ODPacket& packet); - virtual void pickup(); virtual void setPosition(const Ogre::Vector3& v); bool eatChicken(Creature* creature); - static const char* getFormat(); static ChickenEntity* getChickenEntityFromStream(GameMap* gameMap, std::istream& is); - static ChickenEntity* getChickenEntityFromPacket(GameMap* gameMap, ODPacket& packet); - friend ODPacket& operator<<(ODPacket& os, ChickenEntity* obj); - friend ODPacket& operator>>(ODPacket& os, ChickenEntity* obj); - friend std::ostream& operator<<(std::ostream& os, ChickenEntity* obj); + static ChickenEntity* getChickenEntityFromPacket(GameMap* gameMap, ODPacket& is); + static const char* getFormat(); private: enum ChickenState { @@ -64,8 +61,9 @@ class ChickenEntity: public RenderedMovableEntity dead }; ChickenState mChickenState; - int32_t nbTurnOutsideHatchery; - int32_t nbTurnDie; + int32_t mNbTurnOutsideHatchery; + int32_t mNbTurnDie; + bool mIsDropped; void addTileToListIfPossible(int x, int y, Room* currentHatchery, std::vector& possibleTileMove); }; diff --git a/source/Creature.cpp b/source/Creature.cpp index a18797638..2937e8c17 100644 --- a/source/Creature.cpp +++ b/source/Creature.cpp @@ -1695,7 +1695,7 @@ bool Creature::handleDepositGoldAction() popAction(); Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return true; TreasuryObject* obj = new TreasuryObject(getGameMap(), mGold); @@ -1955,6 +1955,15 @@ bool Creature::handleEatingAction(bool isForced) return false; } + if ((isForced && mHunger < 5.0) || + (!isForced && mHunger <= Random::Double(0.0, 15.0))) + { + popAction(); + + stopEating(); + return true; + } + // If we are in a hatchery, we go to the closest chicken in it. If we are not // in a hatchery, we check if there is a free chicken and eat it if we see it Tile* closestChickenTile = nullptr; @@ -2026,15 +2035,6 @@ bool Creature::handleEatingAction(bool isForced) } } - if ((isForced && mHunger < 5.0) || - (!isForced && mHunger <= Random::Double(0.0, 25.0))) - { - popAction(); - - stopEating(); - return true; - } - if(mEatRoom != nullptr) return false; diff --git a/source/DirectionalTrap.cpp b/source/DirectionalTrap.cpp deleted file mode 100644 index c5b835bd9..000000000 --- a/source/DirectionalTrap.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2011-2014 OpenDungeons Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "DirectionalTrap.h" - -#include "Tile.h" -#include "GameMap.h" - -DirectionalTrap::DirectionalTrap(GameMap* gameMap, int xdir, int ydir): - Trap(gameMap) -{ - mDir = std::pair(xdir, ydir); -} - -DirectionalTrap::DirectionalTrap(GameMap* gameMap): - Trap(gameMap) -{ - mDir = std::pair(0, 0); -} - -std::pair DirectionalTrap::projectionOnBorder(int xdir, int ydir) -{ - GameMap* gm = getGameMap(); - int a = (ydir - mCoveredTiles[0]->y) / (xdir - mCoveredTiles[0]->x); - int b = ydir - a * xdir; - - if(b >= 0 && b < gm->getMapSizeY()) - { - return std::pair(0, b); - } - else if(-(b/a) >= 0 && -(b/a) < gm->getMapSizeX()) - { - return std::pair((-b)/a, 0); - } - - int tmp = a * (gm->getMapSizeY() - 1) + b; - if(tmp >= 0 && tmp < gm->getMapSizeY()) - return std::pair(gm->getMapSizeX() - 1, tmp); - - return std::pair((gm->getMapSizeY() - b - 1)/a, gm->getMapSizeY() - 1); -} diff --git a/source/DirectionalTrap.h b/source/DirectionalTrap.h deleted file mode 100644 index 67b5ca369..000000000 --- a/source/DirectionalTrap.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2011-2014 OpenDungeons Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef DIRECTIONAL_TRAP_H -#define DIRECTIONAL_TRAP_H - -#include -#include "Trap.h" - -class DirectionalTrap : public Trap -{ -public: - DirectionalTrap(GameMap* gameMap, int xdir, int ydir); - -protected: - DirectionalTrap(GameMap* gameMap); - std::pair mDir; - std::pair projectionOnBorder(int, int); -}; - -#endif // DIRECTIONAL_TRAP_H diff --git a/source/GameEntity.h b/source/GameEntity.h index 64b4974a7..80fa14fb4 100644 --- a/source/GameEntity.h +++ b/source/GameEntity.h @@ -57,7 +57,7 @@ class GameEntity public: enum ObjectType { - unknown, creature, room, trap, weapon, renderedMovableEntity, missileobject, tile + unknown, creature, room, trap, weapon, renderedMovableEntity, tile }; //! \brief Default constructor with default values diff --git a/source/GameMap.cpp b/source/GameMap.cpp index a188c697b..46ff71d8d 100644 --- a/source/GameMap.cpp +++ b/source/GameMap.cpp @@ -36,7 +36,6 @@ #include "Seat.h" #include "MapLight.h" #include "TileCoordinateMap.h" -#include "MissileObject.h" #include "Weapon.h" #include "MapLoader.h" #include "LogManager.h" @@ -211,7 +210,6 @@ void GameMap::clearAll() clearCreatures(); clearClasses(); clearTraps(); - clearMissileObjects(); clearMapLights(); clearRooms(); @@ -292,7 +290,7 @@ void GameMap::resetUniqueNumbers() mUniqueNumberFloodFilling = 0; mUniqueNumberMissileObj = 0; mUniqueNumberRoom = 0; - mUniqueNumberRoomObj = 0; + mUniqueNumberRenderedMovableEntity = 0; mUniqueNumberTrap = 0; mUniqueNumberMapLight = 0; } @@ -431,10 +429,9 @@ void GameMap::addRenderedMovableEntity(RenderedMovableEntity *obj) try { - RenderedMovableEntity::RenderedMovableEntityType objType = obj->getRenderedMovableEntityType(); ServerNotification *serverNotification = new ServerNotification( - ServerNotification::addRenderedMovableEntity, NULL); - serverNotification->mPacket << objType; + ServerNotification::addRenderedMovableEntity, nullptr); + obj->exportHeadersToPacket(serverNotification->mPacket); obj->exportToPacket(serverNotification->mPacket); ODServer::getSingleton().queueServerNotification(serverNotification); } @@ -1287,102 +1284,62 @@ Player* GameMap::getPlayerBySeat(Seat* seat) return NULL; } -std::list GameMap::lineOfSight(int x0, int y0, int x1, int y1) +std::list GameMap::tilesBetween(int x1, int y1, int x2, int y2) { std::list path; - // Calculate the components of the 'manhattan distance' - int Dx = x1 - x0; - int Dy = y1 - y0; - - // Determine if the slope of the line is greater than 1 - int steep = (abs(Dy) >= abs(Dx)); - if (steep) + if(x2 == x1) { - std::swap(x0, y0); - std::swap(x1, y1); - // recompute Dx, Dy after swap - Dx = x1 - x0; - Dy = y1 - y0; - } + // Vertical line, no need to compute + int diffY = 1; + if(y1 > y2) + diffY = -1; - // Determine whether the x component is increasing or decreasing - int xstep = 1; - if (Dx < 0) - { - xstep = -1; - Dx = -Dx; - } + for(int y = y1; y != y2; y += diffY) + { + Tile* tile = getTile(x1, y); + if(tile == nullptr) + break; - // Determine whether the y component is increasing or decreasing - int ystep = 1; - if (Dy < 0) - { - ystep = -1; - Dy = -Dy; + path.push_back(tile); + } } - - // Loop over the pixels on the line and add them to the return list - int TwoDy = 2 * Dy; - int TwoDyTwoDx = TwoDy - 2 * Dx; // 2*Dy - 2*Dx - int E = TwoDy - Dx; //2*Dy - Dx - int y = y0; - int xDraw, yDraw; - for (int x = x0; x != x1; x += xstep) + else { - // Treat a steep line as if it were actually its inverse - if (steep) - { - xDraw = y; - yDraw = x; - } - else - { - xDraw = x; - yDraw = y; - } + double deltax = x2 - x1; + double deltay = y2 - y1; + double error = 0; + double deltaerr = std::abs(deltay / deltax); + int diffX = 1; + if(x1 > x2) + diffX = -1; - // If the tile exists, add it to the path. - Tile *currentTile = getTile(xDraw, yDraw); - if (currentTile != NULL) - { - path.push_back(currentTile); - } - else - { - // This should fix a bug where creatures "cut across" null sections of the map if they can see the other side. - path.clear(); - return path; - } + int diffY = 1; + if(y1 > y2) + diffY = -1; - // If the error has accumulated to the next tile, "increment" the y coordinate - if (E > 0) + int y = y1; + for(int x = x1; x != x2; x += diffX) { - // Also add the tile for this y-value for the next row over so that the line of sight consists of a 4-connected - // path (i.e. you can traverse the path without ever having to move "diagonal" on the square grid). - currentTile = getTile(xDraw + 1, y); - if (currentTile != NULL) - { - path.push_back(currentTile); - } - else + Tile* tile = getTile(x, y); + if(tile == nullptr) + break; + + path.push_back(tile); + error += deltaerr; + if(error >= 0.5) { - // This should fix a bug where creatures "cut across" null sections of the map if they can see the other side. - path.clear(); - return path; + y += diffY; + error = error - 1.0; } - - // Now increment y to the value it will be for the next x-value. - E += TwoDyTwoDx; //E += 2*Dy - 2*Dx; - y = y + ystep; - - } - else - { - E += TwoDy; //E += 2*Dy; } } + // We add the last tile + Tile* tile = getTile(x2, y2); + if(tile != nullptr) + path.push_back(tile); + return path; } @@ -1488,10 +1445,32 @@ std::vector GameMap::getVisibleForce(std::vector visibleTile OD_ASSERT_TRUE(tile != NULL); if(tile == NULL) continue; - tile->fillAttackableObjects(returnList, seat, invert); + + tile->fillAttackableCreatures(returnList, seat, invert); + tile->fillAttackableRoom(returnList, seat, invert); + tile->fillAttackableTrap(returnList, seat, invert); + } + + return returnList; +} + +std::vector GameMap::getVisibleCreatures(std::vector visibleTiles, Seat* seat, bool invert) +{ + std::vector returnList; + + // Loop over the visible tiles + for (std::vector::iterator itr = visibleTiles.begin(); itr != visibleTiles.end(); ++itr) + { + Tile* tile = *itr; + OD_ASSERT_TRUE(tile != NULL); + if(tile == NULL) + continue; + + tile->fillAttackableCreatures(returnList, seat, invert); } return returnList; + } void GameMap::clearRooms() @@ -1511,13 +1490,12 @@ void GameMap::addRoom(Room *r) { if(isServerGameMap()) { - Room::RoomType type = r->getType(); int nbTiles = r->getCoveredTiles().size(); LogManager::getSingleton().logMessage("Adding room " + r->getName() + ", nbTiles=" + Ogre::StringConverter::toString(nbTiles) + ", seatId=" + Ogre::StringConverter::toString(r->getSeat()->getId())); ServerNotification notif(ServerNotification::buildRoom, getPlayerBySeat(r->getSeat())); - notif.mPacket << type; + r->exportHeadersToPacket(notif.mPacket); r->exportToPacket(notif.mPacket); ODServer::getSingleton().sendAsyncMsgToAllClients(notif); } @@ -1663,13 +1641,12 @@ void GameMap::addTrap(Trap *trap) { if(isServerGameMap()) { - Trap::TrapType type = trap->getType(); int nbTiles = trap->getCoveredTiles().size(); LogManager::getSingleton().logMessage("Adding trap " + trap->getName() + ", nbTiles=" + Ogre::StringConverter::toString(nbTiles) + ", seatId=" + Ogre::StringConverter::toString(trap->getSeat()->getId())); ServerNotification notif(ServerNotification::buildTrap, getPlayerBySeat(trap->getSeat())); - notif.mPacket << type; + trap->exportHeadersToPacket(notif.mPacket); trap->exportToPacket(notif.mPacket); ODServer::getSingleton().sendAsyncMsgToAllClients(notif); } @@ -2007,106 +1984,6 @@ void GameMap::clearGoalsForAllSeats() } } -void GameMap::clearMissileObjects() -{ - for (unsigned int i = 0; i < missileObjects.size(); ++i) - { - MissileObject* mo = missileObjects[i]; - removeActiveObject(mo); - - for (std::vector::iterator it = animatedObjects.begin(); it != animatedObjects.end(); ++it) - { - MovableGameEntity* ao = *it; - if (mo == ao) - { - animatedObjects.erase(it); - break; - } - } - mo->deleteYourself(); - } - - missileObjects.clear(); -} - -void GameMap::addMissileObject(MissileObject *m) -{ - if(isServerGameMap()) - { - LogManager::getSingleton().logMessage("Adding MissileObject " + m->getName()); - try - { - ServerNotification *serverNotification = new ServerNotification( - ServerNotification::addMissileObject, NULL); - serverNotification->mPacket << m; - ODServer::getSingleton().queueServerNotification(serverNotification); - } - catch (std::bad_alloc&) - { - Ogre::LogManager::getSingleton().logMessage("ERROR: bad alloc in GameMap::addMissileObject", Ogre::LML_CRITICAL); - exit(1); - } - } - - missileObjects.push_back(m); - addActiveObject(m); - addAnimatedObject(m); -} - -void GameMap::removeMissileObject(MissileObject *m) -{ - if(isServerGameMap()) - { - LogManager::getSingleton().logMessage("Removing MissileObject " + m->getName()); - try - { - ServerNotification *serverNotification = new ServerNotification( - ServerNotification::removeMissileObject, NULL); - std::string name = m->getName(); - serverNotification->mPacket << name; - ODServer::getSingleton().queueServerNotification(serverNotification); - } - catch (std::bad_alloc&) - { - Ogre::LogManager::getSingleton().logMessage("ERROR: bad alloc in GameMap::removeMissileObject", Ogre::LML_CRITICAL); - exit(1); - } - } - - for (unsigned int i = 0; i < missileObjects.size(); ++i) - { - if (m == missileObjects[i]) - { - missileObjects.erase(missileObjects.begin() + i); - break; - } - } - - removeActiveObject(m); - removeAnimatedObject(m); -} - -MissileObject* GameMap::getMissileObject(int index) -{ - return missileObjects[index]; -} - -MissileObject* GameMap::getMissileObject(const std::string& name) -{ - for(std::vector::iterator it = missileObjects.begin(); it != missileObjects.end(); ++it) - { - MissileObject* mo = *it; - if(mo->getName().compare(name) == 0) - return mo; - } - return NULL; -} - -unsigned int GameMap::numMissileObjects() -{ - return missileObjects.size(); -} - Ogre::Real GameMap::crowDistance(Tile *t1, Tile *t2) { if (t1 != NULL && t2 != NULL) @@ -2586,17 +2463,6 @@ int GameMap::nextUniqueNumberFloodFilling() return ++mUniqueNumberFloodFilling; } -std::string GameMap::nextUniqueNameMissileObj() -{ - std::string ret; - do - { - ++mUniqueNumberMissileObj; - ret = MissileObject::MISSILEOBJECT_NAME_PREFIX + Ogre::StringConverter::toString(mUniqueNumberMissileObj); - } while(getAnimatedObject(ret) != NULL); - return ret; -} - std::string GameMap::nextUniqueNameRoom(const std::string& meshName) { std::string ret; @@ -2608,13 +2474,13 @@ std::string GameMap::nextUniqueNameRoom(const std::string& meshName) return ret; } -std::string GameMap::nextUniqueNameRoomObj(const std::string& baseName) +std::string GameMap::nextUniqueNameRenderedMovableEntity(const std::string& baseName) { std::string ret; do { - ++mUniqueNumberRoomObj; - ret = RenderedMovableEntity::RENDEREDMOVABLEENTITY_PREFIX + baseName + "_" + Ogre::StringConverter::toString(mUniqueNumberRoomObj); + ++mUniqueNumberRenderedMovableEntity; + ret = RenderedMovableEntity::RENDEREDMOVABLEENTITY_PREFIX + baseName + "_" + Ogre::StringConverter::toString(mUniqueNumberRenderedMovableEntity); } while(getAnimatedObject(ret) != NULL); return ret; } @@ -2648,7 +2514,9 @@ void GameMap::logFloodFileTiles() for(int xx = 0; xx < getMapSizeX(); ++xx) { Tile* tile = getTile(xx, yy); - std::string str = "Tile floodfill : " + Tile::displayAsString(tile) + " - fullness=" + Ogre::StringConverter::toString(tile->getFullness()); + std::string str = "Tile floodfill : " + Tile::displayAsString(tile) + + " - fullness=" + Ogre::StringConverter::toString(tile->getFullness()) + + " - seatId=" + std::string(tile->getSeat() == nullptr ? "0" : Ogre::StringConverter::toString(tile->getSeat()->getId())); for(int i = 0; i < Tile::FloodFillTypeMax; ++i) { str += ", [" + Ogre::StringConverter::toString(i) + "]=" + diff --git a/source/GameMap.h b/source/GameMap.h index 260aae546..d3df08f23 100644 --- a/source/GameMap.h +++ b/source/GameMap.h @@ -42,7 +42,6 @@ class Trap; class Seat; class Goal; class MapLight; -class MissileObject; class MovableGameEntity; class CreatureDefinition; @@ -182,13 +181,6 @@ friend class ODServer; Trap* getTrap(int index); unsigned int numTraps(); - void clearMissileObjects(); - void addMissileObject(MissileObject *m); - void removeMissileObject(MissileObject *m); - MissileObject* getMissileObject(int index); - MissileObject* getMissileObject(const std::string& name); - unsigned int numMissileObjects(); - //! \brief Map Lights related functions. void clearMapLights(); void addMapLight(MapLight *m); @@ -340,21 +332,24 @@ friend class ODServer; std::list path(Creature *c1, Creature *c2, const CreatureDefinition* creatureDef, Seat* seat, bool throughDiggableTiles = false); std::list path(Tile *t1, Tile *t2, const CreatureDefinition* creatureDef, Seat* seat, bool throughDiggableTiles = false); - /*! \brief Returns a list of valid tiles along a straight line from (x1, y1) to (x2, y2), NOTE: in spite of - * the name, you do not need to be able to see through the tiles returned by this method. + /*! \brief Returns a list of valid tiles along a straight line from (x1, y1) to (x2, y2) + * independently from their fullness or type. * * This algorithm is from - * http://en.wikipedia.org/w/index.php?title=Bresenham%27s_line_algorithm&oldid=295047020 + * http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm * A more detailed description of how it works can be found there. */ - std::list lineOfSight(int x1, int y1, int x2, int y2); + std::list tilesBetween(int x1, int y1, int x2, int y2); //! \brief Returns the tiles visible from the given start tile out to the specified sight radius. std::vector visibleTiles(Tile *startTile, double sightRadius); - //! \brief Loops over the visibleTiles and returns any creatures in those tiles allied with the given seat (or if invert is true, is not allied) + //! \brief Loops over the visibleTiles and returns any creature/room/trap in those tiles allied with the given seat (or if invert is true, is not allied) std::vector getVisibleForce(std::vector visibleTiles, Seat* seat, bool invert); + //! \brief Loops over the visibleTiles and returns any creature in those tiles allied with the given seat (or if invert is true, is not allied) + std::vector getVisibleCreatures(std::vector visibleTiles, Seat* seat, bool invert); + /** \brief Returns the as the crow flies distance between tiles located at the two coordinates given. * If tiles do not exist at these locations the function returns -1.0. */ @@ -437,9 +432,9 @@ friend class ODServer; //! \brief This functions create unique names. They check that there //! is no entity with the same name before returning std::string nextUniqueNameCreature(const std::string& className); - std::string nextUniqueNameMissileObj(); + std::string nextUniqueNameMissileObj(const std::string& baseName); std::string nextUniqueNameRoom(const std::string& meshName); - std::string nextUniqueNameRoomObj(const std::string& baseName); + std::string nextUniqueNameRenderedMovableEntity(const std::string& baseName); std::string nextUniqueNameTrap(const std::string& meshName); std::string nextUniqueNameMapLight(); @@ -479,7 +474,7 @@ friend class ODServer; int mUniqueNumberFloodFilling; int mUniqueNumberMissileObj; int mUniqueNumberRoom; - int mUniqueNumberRoomObj; + int mUniqueNumberRenderedMovableEntity; int mUniqueNumberTrap; int mUniqueNumberMapLight; @@ -506,7 +501,6 @@ friend class ODServer; std::vector rooms; std::vector traps; std::vector mapLights; - std::vector missileObjects; //! \brief Players and available game player slots (Seats) std::vector players; diff --git a/source/Gui.cpp b/source/Gui.cpp index f737fcd76..596ed216c 100644 --- a/source/Gui.cpp +++ b/source/Gui.cpp @@ -188,6 +188,10 @@ void Gui::assignEventHandlers() CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&spikeTrapButtonPressed)); + sheets[inGameMenu]->getChild(BUTTON_TRAP_BOULDER)->subscribeEvent( + CEGUI::PushButton::EventClicked, + CEGUI::Event::Subscriber(&boulderTrapButtonPressed)); + sheets[inGameMenu]->getChild(BUTTON_DESTROY_TRAP)->subscribeEvent( CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&destroyTrapButtonPressed)); @@ -265,6 +269,10 @@ void Gui::assignEventHandlers() CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&spikeTrapButtonPressed)); + sheets[editorModeGui]->getChild(BUTTON_TRAP_BOULDER)->subscribeEvent( + CEGUI::PushButton::EventClicked, + CEGUI::Event::Subscriber(&boulderTrapButtonPressed)); + sheets[editorModeGui]->getChild(BUTTON_DESTROY_TRAP)->subscribeEvent( CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&destroyTrapButtonPressed)); @@ -476,6 +484,16 @@ bool Gui::spikeTrapButtonPressed(const CEGUI::EventArgs& e) return true; } +bool Gui::boulderTrapButtonPressed(const CEGUI::EventArgs& e) +{ + GameMap* gameMap = ODFrameListener::getSingleton().getClientGameMap(); + gameMap->getLocalPlayer()->setNewRoomType(Room::nullRoomType); + gameMap->getLocalPlayer()->setNewTrapType(Trap::boulder); + gameMap->getLocalPlayer()->setCurrentAction(Player::SelectedAction::buildTrap); + SoundEffectsManager::getSingleton().playInterfaceSound(SoundEffectsManager::BUTTONCLICK); + return true; +} + bool Gui::destroyTrapButtonPressed(const CEGUI::EventArgs& e) { GameMap* gameMap = ODFrameListener::getSingleton().getClientGameMap(); @@ -789,6 +807,7 @@ const std::string Gui::BUTTON_DESTROY_ROOM = "MainTabControl/Rooms/DestroyRoomBu const std::string Gui::TAB_TRAPS = "MainTabControl/Traps"; const std::string Gui::BUTTON_TRAP_CANNON = "MainTabControl/Traps/CannonButton"; const std::string Gui::BUTTON_TRAP_SPIKE = "MainTabControl/Traps/SpikeTrapButton"; +const std::string Gui::BUTTON_TRAP_BOULDER = "MainTabControl/Traps/BoulderTrapButton"; const std::string Gui::BUTTON_DESTROY_TRAP = "MainTabControl/Traps/DestroyTrapButton"; const std::string Gui::TAB_SPELLS = "MainTabControl/Spells"; const std::string Gui::TAB_CREATURES = "MainTabControl/Creatures"; diff --git a/source/Gui.h b/source/Gui.h index a46800c85..15f3e1bd9 100644 --- a/source/Gui.h +++ b/source/Gui.h @@ -91,6 +91,7 @@ class Gui : public Ogre::Singleton static const std::string TAB_TRAPS; static const std::string BUTTON_TRAP_CANNON; static const std::string BUTTON_TRAP_SPIKE; + static const std::string BUTTON_TRAP_BOULDER; static const std::string BUTTON_DESTROY_TRAP; static const std::string TAB_SPELLS; static const std::string TAB_CREATURES; @@ -206,6 +207,7 @@ class Gui : public Ogre::Singleton static bool hatcheryButtonPressed (const CEGUI::EventArgs& e); static bool cannonButtonPressed (const CEGUI::EventArgs& e); static bool spikeTrapButtonPressed (const CEGUI::EventArgs& e); + static bool boulderTrapButtonPressed(const CEGUI::EventArgs& e); static bool destroyTrapButtonPressed(const CEGUI::EventArgs& e); static bool confirmExitYesButtonPressed (const CEGUI::EventArgs& e); static bool confirmExitNoButtonPressed (const CEGUI::EventArgs& e); diff --git a/source/MissileBoulder.cpp b/source/MissileBoulder.cpp new file mode 100644 index 000000000..fcfbb497e --- /dev/null +++ b/source/MissileBoulder.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011-2014 OpenDungeons Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "MissileBoulder.h" +#include "ODPacket.h" +#include "GameMap.h" +#include "Random.h" +#include "LogManager.h" + +#include + +MissileBoulder::MissileBoulder(GameMap* gameMap, Seat* seat, const std::string& senderName, const std::string& meshName, + const Ogre::Vector3& direction, double damage) : + MissileObject(gameMap, seat, senderName, meshName, direction, true), + mDamage(damage), + nbHits(0) +{ +} + +MissileBoulder::MissileBoulder(GameMap* gameMap) : + MissileObject(gameMap), + mDamage(0.0), + nbHits(0) +{ +} + +bool MissileBoulder::hitCreature(GameEntity* entity) +{ + std::vector tiles = entity->getCoveredTiles(); + if(tiles.empty()) + return true; + + Tile* hitTile = tiles[0]; + entity->takeDamage(this, mDamage, hitTile); + ++nbHits; + if(Random::Uint(0, 10 - nbHits) <= 0) + return false; + + return true; +} + +bool MissileBoulder::wallHitNextDirection(const Ogre::Vector3& actDirection, Tile* tile, Ogre::Vector3& nextDirection) +{ + // When we hit a wall, we might break + if(Random::Uint(1, 2) == 1) + return false; + + if(Random::Uint(1, 2) == 1) + { + nextDirection.x = actDirection.y; + nextDirection.y = actDirection.x; + nextDirection.z = actDirection.z; + } + else + { + nextDirection.x = -actDirection.y; + nextDirection.y = -actDirection.x; + nextDirection.z = actDirection.z; + } + return true; +} + +MissileBoulder* MissileBoulder::getMissileBoulderFromStream(GameMap* gameMap, std::istream& is) +{ + MissileBoulder* obj = new MissileBoulder(gameMap); + return obj; +} + +MissileBoulder* MissileBoulder::getMissileBoulderFromPacket(GameMap* gameMap, ODPacket& packet) +{ + MissileBoulder* obj = new MissileBoulder(gameMap); + return obj; +} diff --git a/source/MissileBoulder.h b/source/MissileBoulder.h new file mode 100644 index 000000000..c3d8c8a1e --- /dev/null +++ b/source/MissileBoulder.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011-2014 OpenDungeons Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MISSILEBOULDER_H +#define MISSILEBOULDER_H + +#include "MissileObject.h" + +#include +#include +#include + +class Creature; +class Room; +class GameMap; +class Tile; +class ODPacket; + +class MissileBoulder: public MissileObject +{ +public: + MissileBoulder(GameMap* gameMap, Seat* seat, const std::string& senderName, const std::string& meshName, + const Ogre::Vector3& direction, double damage); + MissileBoulder(GameMap* gameMap); + + virtual MissileType getMissileType() + { return MissileType::boulder; } + + virtual bool hitCreature(GameEntity* entity); + virtual bool wallHitNextDirection(const Ogre::Vector3& actDirection, Tile* tile, Ogre::Vector3& nextDirection); + + static MissileBoulder* getMissileBoulderFromStream(GameMap* gameMap, std::istream& is); + static MissileBoulder* getMissileBoulderFromPacket(GameMap* gameMap, ODPacket& packet); +private: + double mDamage; + int nbHits; +}; + +#endif // MISSILEBOULDER_H diff --git a/source/MissileObject.cpp b/source/MissileObject.cpp index 2b28c90e8..fab130b2b 100644 --- a/source/MissileObject.cpp +++ b/source/MissileObject.cpp @@ -16,122 +16,233 @@ */ #include "MissileObject.h" - -#include "RenderRequest.h" -#include "RenderManager.h" #include "ODPacket.h" #include "GameMap.h" +#include "MissileBoulder.h" +#include "MissileOneHit.h" +#include "LogManager.h" #include -#include - -const std::string MissileObject::MISSILEOBJECT_NAME_PREFIX = "Missile_Object_"; -MissileObject::MissileObject(GameMap* gameMap, const std::string& nMeshName, const Ogre::Vector3& nPosition) : - MovableGameEntity(gameMap) +MissileObject::MissileObject(GameMap* gameMap, Seat* seat, const std::string& senderName, + const std::string& meshName, const Ogre::Vector3& direction, bool damageAllies) : + RenderedMovableEntity(gameMap, senderName, meshName, 0.0f), + mDirection(direction), + mIsMissileAlive(true), + mDamageAllies(damageAllies) { - setObjectType(GameEntity::missileobject); - - setName(gameMap->nextUniqueNameMissileObj()); - - setMeshName(nMeshName); - setMeshExisting(false); - setPosition(nPosition); + setSeat(seat); } MissileObject::MissileObject(GameMap* gameMap) : - MovableGameEntity(gameMap) + RenderedMovableEntity(gameMap), + mDirection(Ogre::Vector3::ZERO), + mIsMissileAlive(true), + mDamageAllies(false) { - setObjectType(GameEntity::missileobject); - setMeshExisting(false); } -void MissileObject::createMeshLocal() +void MissileObject::doUpkeep() { - MovableGameEntity::createMeshLocal(); + if(!getIsOnMap()) + return; - if(getGameMap()->isServerGameMap()) + if(!mIsMissileAlive) + { + if(!isMoving()) + { + getGameMap()->removeRenderedMovableEntity(this); + deleteYourself(); + } return; + } - RenderRequest* request = new RenderRequest; - request->type = RenderRequest::createMissileObject; - request->p = static_cast(this); - RenderManager::queueRenderRequest(request); -} + Tile* tile = getPositionTile(); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); + if(tile == nullptr) + return; -void MissileObject::destroyMeshLocal() -{ - MovableGameEntity::destroyMeshLocal(); + // We check if a creature is in our way. We start by taking the tile we will be on + Ogre::Vector3 position = getPosition(); + double moveDist = getMoveSpeed(); + Ogre::Vector3 destination = position + (moveDist * mDirection); - if(getGameMap()->isServerGameMap()) + std::list tiles = getGameMap()->tilesBetween(static_cast(position.x), + static_cast(position.y), static_cast(destination.x), static_cast(destination.y)); + + OD_ASSERT_TRUE(!tiles.empty()); + if(tiles.empty()) + { + getGameMap()->removeRenderedMovableEntity(this); + deleteYourself(); return; + } - RenderRequest* request = new RenderRequest; - request->type = RenderRequest::destroyMissileObject; - request->p = static_cast(this); - RenderManager::queueRenderRequest(request); + Tile* lastTile = nullptr; + while(!tiles.empty() && mIsMissileAlive) + { + Tile* tmpTile = tiles.front(); + tiles.pop_front(); + + if(tmpTile->getFullness() > 0.0) + { + Ogre::Vector3 nextDirection; + mIsMissileAlive = wallHitNextDirection(mDirection, lastTile, nextDirection); + if(!mIsMissileAlive) + { + destination -= moveDist * mDirection; + break; + } + else + { + position.x = static_cast(lastTile->getX()); + position.y = static_cast(lastTile->getY()); + addDestination(position.x, position.y, position.z); + // We compute next position + mDirection = nextDirection; + destination = position + (moveDist * mDirection); + tiles = getGameMap()->tilesBetween(static_cast(position.x), + static_cast(position.y), static_cast(destination.x), static_cast(destination.y)); + + continue; + } + } + + if(lastTile != nullptr) + { + Ogre::Vector3 lastPos; + lastPos.x = static_cast(lastTile->getX()); + lastPos.y = static_cast(lastTile->getY()); + lastPos.z = position.z; + Ogre::Vector3 curPos; + curPos.x = static_cast(tmpTile->getX()); + curPos.y = static_cast(tmpTile->getY()); + curPos.z = position.z; + moveDist -= lastPos.distance(curPos); + } + lastTile = tmpTile; + + std::vector tileVector; + tileVector.push_back(tmpTile); + std::vector enemyCreatures = getGameMap()->getVisibleCreatures(tileVector, getSeat(), true); + for(std::vector::iterator it = enemyCreatures.begin(); it != enemyCreatures.end(); ++it) + { + GameEntity* creature = *it; + if(!hitCreature(creature)) + { + destination -= moveDist * mDirection; + mIsMissileAlive = false; + break; + } + } + + if(!mDamageAllies || !mIsMissileAlive) + continue; + + std::vector alliedCreatures = getGameMap()->getVisibleCreatures(tileVector, getSeat(), false); + for(std::vector::iterator it = alliedCreatures.begin(); it != alliedCreatures.end(); ++it) + { + GameEntity* creature = *it; + if(!hitCreature(creature)) + { + destination -= moveDist * mDirection; + mIsMissileAlive = false; + break; + } + } + } + + addDestination(destination.x, destination.y, destination.z); } -void MissileObject::deleteYourselfLocal() +void MissileObject::exportHeadersToStream(std::ostream& os) { - MovableGameEntity::deleteYourselfLocal(); - if(getGameMap()->isServerGameMap()) - return; + RenderedMovableEntity::exportHeadersToStream(os); + os << getMissileType() << "\t"; +} - RenderRequest* request = new RenderRequest; - request->type = RenderRequest::deleteMissileObject; - request->p = static_cast(this); - RenderManager::queueRenderRequest(request); +void MissileObject::exportHeadersToPacket(ODPacket& os) +{ + RenderedMovableEntity::exportHeadersToPacket(os); + os << getMissileType(); } -void MissileObject::doUpkeep() +MissileObject* MissileObject::getMissileObjectFromStream(GameMap* gameMap, std::istream& is) { - // TODO: check if we collide with a creature, if yes, do some damage and delete ourselves - if(!isMoving()) + MissileObject* obj = nullptr; + MissileType type; + OD_ASSERT_TRUE(is >> type); + switch(type) { - getGameMap()->removeMissileObject(this); - deleteYourself(); - return; + case MissileType::oneHit: + { + obj = MissileOneHit::getMissileOneHitFromStream(gameMap, is); + break; + } + case MissileType::boulder: + { + obj = MissileBoulder::getMissileBoulderFromStream(gameMap, is); + break; + } + default: + OD_ASSERT_TRUE_MSG(false, "Unknown enum value : " + Ogre::StringConverter::toString( + static_cast(type))); + break; } + return obj; } -void MissileObject::setPosition(const Ogre::Vector3& v) +MissileObject* MissileObject::getMissileObjectFromPacket(GameMap* gameMap, ODPacket& is) { - MovableGameEntity::setPosition(v); - if(getGameMap()->isServerGameMap()) - return; + MissileObject* obj = nullptr; + MissileType type; + OD_ASSERT_TRUE(is >> type); + switch(type) + { + case MissileType::oneHit: + { + obj = MissileOneHit::getMissileOneHitFromPacket(gameMap, is); + break; + } + case MissileType::boulder: + { + obj = MissileBoulder::getMissileBoulderFromPacket(gameMap, is); + break; + } + default: + OD_ASSERT_TRUE_MSG(false, "Unknown enum value : " + Ogre::StringConverter::toString( + static_cast(type))); + break; + } + return obj; +} - RenderRequest* request = new RenderRequest; - request->type = RenderRequest::moveSceneNode; - request->str = getOgreNamePrefix() + "_node"; - request->vec = v; - RenderManager::queueRenderRequest(request); +ODPacket& operator<<(ODPacket& os, const MissileObject::MissileType& type) +{ + uint32_t intType = static_cast(type); + os << intType; + return os; } -ODPacket& operator<<(ODPacket& os, MissileObject *mo) +ODPacket& operator>>(ODPacket& is, MissileObject::MissileType& type) { - std::string name = mo->getName(); - std::string meshName = mo->getMeshName(); - double moveSpeed = mo->getMoveSpeed(); - Ogre::Vector3 position = mo->getPosition(); - os << meshName << position << name << moveSpeed; + uint32_t intType; + is >> intType; + type = static_cast(intType); + return is; +} +std::ostream& operator<<(std::ostream& os, const MissileObject::MissileType& type) +{ + uint32_t intType = static_cast(type); + os << intType; return os; } -ODPacket& operator>>(ODPacket& is, MissileObject *mo) +std::istream& operator>>(std::istream& is, MissileObject::MissileType& type) { - std::string name; - std::string meshName; - Ogre::Vector3 position; - double moveSpeed; - is >> meshName; - mo->setMeshName(meshName); - is >> position; - mo->setPosition(position); - is >> name; - mo->setName(name); - is >> moveSpeed; - mo->setMoveSpeed(moveSpeed); + uint32_t intType; + is >> intType; + type = static_cast(intType); return is; } diff --git a/source/MissileObject.h b/source/MissileObject.h index 0a2223e7c..d3d6261be 100644 --- a/source/MissileObject.h +++ b/source/MissileObject.h @@ -18,61 +18,64 @@ #ifndef MISSILEOBJECT_H #define MISSILEOBJECT_H -#include "MovableGameEntity.h" +#include "RenderedMovableEntity.h" -#include #include +#include +#include -#include - +class Creature; +class Room; class GameMap; +class Tile; class ODPacket; -//! \brief This class implements missile object launched by traps when they're triggered. -class MissileObject: public MovableGameEntity +class MissileObject: public RenderedMovableEntity { -friend class ODClient; - public: - MissileObject(GameMap* gameMap, const std::string& nMeshName, const Ogre::Vector3& nPosition); - - static const std::string MISSILEOBJECT_NAME_PREFIX; - - /*! \brief Changes the missile's position to a new position. - * Moves the creature to a new location in 3d space. This function is - * responsible for informing OGRE anything it needs to know. - */ - void setPosition(const Ogre::Vector3& v); - - std::string getOgreNamePrefix() const { return "MissileObject_"; } + enum MissileType + { + oneHit, + boulder + }; + MissileObject(GameMap* gameMap, Seat* seat, const std::string& senderName, + const std::string& meshName, const Ogre::Vector3& direction, bool damageAllies); + MissileObject(GameMap* gameMap); virtual void doUpkeep(); - void receiveExp(double experience) - {} + /*! brief Function called when the missile hits a wall. If it returns true, the missile direction + * will be set to nextDirection. + * If it returns false, the missile will be destroyed + */ + virtual bool wallHitNextDirection(const Ogre::Vector3& actDirection, Tile* tile, Ogre::Vector3& nextDirection) + { return false; } - void takeDamage(GameEntity* attacker, double damage, Tile* tileTakingDamage) - {} + /*! brief Function called when the missile hits a creature. If it returns true, the missile continues + * If it returns false, the missile will be destroyed + */ + virtual bool hitCreature(GameEntity* entity) + { return false; } - double getDefense() const - { return 0.0; } + virtual RenderedMovableEntityType getRenderedMovableEntityType() + { return RenderedMovableEntityType::missileObject; } - double getHP(Tile* tile) const - { return 0; } + virtual MissileType getMissileType() = 0; - std::vector getCoveredTiles() - { return std::vector(); } + virtual void exportHeadersToStream(std::ostream& os); + virtual void exportHeadersToPacket(ODPacket& os); - friend ODPacket& operator<<(ODPacket& os, MissileObject *mo); - friend ODPacket& operator>>(ODPacket& is, MissileObject *mo); + static MissileObject* getMissileObjectFromStream(GameMap* gameMap, std::istream& is); + static MissileObject* getMissileObjectFromPacket(GameMap* gameMap, ODPacket& is); -protected: - virtual void createMeshLocal(); - virtual void destroyMeshLocal(); - virtual void deleteYourselfLocal(); + friend ODPacket& operator<<(ODPacket& os, const MissileObject::MissileType& rot); + friend ODPacket& operator>>(ODPacket& is, MissileObject::MissileType& rot); + friend std::ostream& operator<<(std::ostream& os, const MissileObject::MissileType& rot); + friend std::istream& operator>>(std::istream& is, MissileObject::MissileType& rot); private: - //!\brief For copy in ODClient - MissileObject(GameMap* gameMap); + Ogre::Vector3 mDirection; + bool mIsMissileAlive; + bool mDamageAllies; }; #endif // MISSILEOBJECT_H diff --git a/source/MissileOneHit.cpp b/source/MissileOneHit.cpp new file mode 100644 index 000000000..28758c41c --- /dev/null +++ b/source/MissileOneHit.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011-2014 OpenDungeons Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "MissileOneHit.h" +#include "ODPacket.h" +#include "GameMap.h" +#include "Random.h" +#include "LogManager.h" + +#include + +MissileOneHit::MissileOneHit(GameMap* gameMap, Seat* seat, const std::string& senderName, const std::string& meshName, + const Ogre::Vector3& direction, double damage, bool damageAllies) : + MissileObject(gameMap, seat, senderName, meshName, direction, damageAllies), + mDamage(damage) +{ +} + +MissileOneHit::MissileOneHit(GameMap* gameMap) : + MissileObject(gameMap), + mDamage(0.0) +{ +} + +bool MissileOneHit::hitCreature(GameEntity* entity) +{ + std::vector tiles = entity->getCoveredTiles(); + if(tiles.empty()) + return true; + + Tile* hitTile = tiles[0]; + entity->takeDamage(this, mDamage, hitTile); + return false; +} + +MissileOneHit* MissileOneHit::getMissileOneHitFromStream(GameMap* gameMap, std::istream& is) +{ + MissileOneHit* obj = new MissileOneHit(gameMap); + return obj; +} + +MissileOneHit* MissileOneHit::getMissileOneHitFromPacket(GameMap* gameMap, ODPacket& packet) +{ + MissileOneHit* obj = new MissileOneHit(gameMap); + return obj; +} diff --git a/source/MissileOneHit.h b/source/MissileOneHit.h new file mode 100644 index 000000000..87aba1152 --- /dev/null +++ b/source/MissileOneHit.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011-2014 OpenDungeons Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MISSILEONEHIT_H +#define MISSILEONEHIT_H + +#include "MissileObject.h" + +#include +#include +#include + +class Creature; +class Room; +class GameMap; +class Tile; +class ODPacket; + +class MissileOneHit: public MissileObject +{ +public: + MissileOneHit(GameMap* gameMap, Seat* seat, const std::string& senderName, const std::string& meshName, + const Ogre::Vector3& direction, double damage, bool damageAllies); + MissileOneHit(GameMap* gameMap); + + virtual MissileType getMissileType() + { return MissileType::oneHit; } + + virtual bool hitCreature(GameEntity* entity); + + static MissileOneHit* getMissileOneHitFromStream(GameMap* gameMap, std::istream& is); + static MissileOneHit* getMissileOneHitFromPacket(GameMap* gameMap, ODPacket& packet); +private: + double mDamage; +}; + +#endif // MISSILEONEHIT_H diff --git a/source/ODApplication.cpp b/source/ODApplication.cpp index c6f6284e1..713f095d4 100644 --- a/source/ODApplication.cpp +++ b/source/ODApplication.cpp @@ -37,7 +37,6 @@ #include "GameMap.h" #include "Random.h" #include "MapLight.h" -#include "MissileObject.h" #include "ODServer.h" #include "ODClient.h" diff --git a/source/ODClient.cpp b/source/ODClient.cpp index e2eb9f4da..ab209f813 100644 --- a/source/ODClient.cpp +++ b/source/ODClient.cpp @@ -30,7 +30,6 @@ #include "Weapon.h" #include "ODApplication.h" #include "RoomTreasury.h" -#include "MissileObject.h" #include "TreasuryObject.h" #include "RenderedMovableEntity.h" #include "LogManager.h" @@ -343,7 +342,7 @@ bool ODClient::processOneClientSocketMessage() MovableGameEntity *tempAnimatedObject = gameMap->getAnimatedObject(objName); OD_ASSERT_TRUE_MSG(tempAnimatedObject != NULL, "objName=" + objName); if (tempAnimatedObject != NULL) - tempAnimatedObject->addDestination(vect.x, vect.y); + tempAnimatedObject->addDestination(vect.x, vect.y, vect.z); break; } @@ -403,12 +402,12 @@ bool ODClient::processOneClientSocketMessage() Tile tmpTile(gameMap); OD_ASSERT_TRUE(packetReceived >> seatId >> &tmpTile); Player *tempPlayer = gameMap->getPlayerBySeatId(seatId); - OD_ASSERT_TRUE_MSG(tempPlayer != NULL, "seatId=" + Ogre::StringConverter::toString(seatId)); + OD_ASSERT_TRUE_MSG(tempPlayer != nullptr, "seatId=" + Ogre::StringConverter::toString(seatId)); Tile* tile = gameMap->getTile(tmpTile.getX(), tmpTile.getY()); - OD_ASSERT_TRUE_MSG(tile != NULL, "tile=" + Tile::displayAsString(&tmpTile)); - if (tempPlayer != NULL && tile != NULL) + OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(&tmpTile)); + if (tempPlayer != nullptr && tile != nullptr) { - OD_ASSERT_TRUE(tempPlayer->dropHand(tile) != NULL); + OD_ASSERT_TRUE(tempPlayer->dropHand(tile) != nullptr); } break; } @@ -553,10 +552,10 @@ bool ODClient::processOneClientSocketMessage() Tile tmpTile(gameMap); OD_ASSERT_TRUE(packetReceived >> roomName>> &tmpTile); Room* room = gameMap->getRoomByName(roomName); - OD_ASSERT_TRUE_MSG(room != NULL, "roomName=" + roomName); + OD_ASSERT_TRUE_MSG(room != nullptr, "roomName=" + roomName); Tile* tile = gameMap->getTile(tmpTile.getX(), tmpTile.getY()); - OD_ASSERT_TRUE_MSG(tile != NULL, "tile=" + Tile::displayAsString(&tmpTile)); - if((room != NULL) && (tile != NULL)) + OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(&tmpTile)); + if((room != nullptr) && (tile != nullptr)) { room->removeCoveredTile(tile); // If no more tiles, the room is removed @@ -578,10 +577,10 @@ bool ODClient::processOneClientSocketMessage() Tile tmpTile(gameMap); OD_ASSERT_TRUE(packetReceived >> trapName>> &tmpTile); Trap* trap = gameMap->getTrapByName(trapName); - OD_ASSERT_TRUE_MSG(trap != NULL, "trapName=" + trapName); + OD_ASSERT_TRUE_MSG(trap != nullptr, "trapName=" + trapName); Tile* tile = gameMap->getTile(tmpTile.getX(), tmpTile.getY()); - OD_ASSERT_TRUE_MSG(tile != NULL, "tile=" + Tile::displayAsString(&tmpTile)); - if((trap != NULL) && (tile != NULL)) + OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(&tmpTile)); + if((trap != nullptr) && (tile != nullptr)) { trap->removeCoveredTile(tile); // If no more tiles, the room is removed @@ -644,31 +643,6 @@ bool ODClient::processOneClientSocketMessage() break; } - case ServerNotification::addMissileObject: - { - MissileObject* missile = new MissileObject(gameMap); - OD_ASSERT_TRUE(packetReceived >> missile); - gameMap->addMissileObject(missile); - missile->createMesh(); - SoundEffectsManager::getSingleton().playInterfaceSound(SoundEffectsManager::CANNONFIRING, - missile->getPosition()); - break; - } - - case ServerNotification::removeMissileObject: - { - std::string name; - OD_ASSERT_TRUE(packetReceived >> name); - MissileObject* missile = gameMap->getMissileObject(name); - OD_ASSERT_TRUE_MSG(missile != NULL, "name=" + name); - if(missile != NULL) - { - gameMap->removeMissileObject(missile); - missile->deleteYourself(); - } - break; - } - case ServerNotification::addRenderedMovableEntity: { RenderedMovableEntity* tempRenderedMovableEntity = RenderedMovableEntity::getRenderedMovableEntityFromPacket(gameMap, packetReceived); diff --git a/source/ODServer.cpp b/source/ODServer.cpp index af71fe709..529034f58 100644 --- a/source/ODServer.cpp +++ b/source/ODServer.cpp @@ -691,7 +691,7 @@ bool ODServer::processClientNotifications(ODSocketClient* clientSocket) OD_ASSERT_TRUE(packetReceived >> &tmpTile); Player *player = clientSocket->getPlayer(); Tile* tile = gameMap->getTile(tmpTile.getX(), tmpTile.getY()); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(&tmpTile)); if(tile != nullptr) { if(player->isDropHandPossible(tile, 0, mServerMode == ServerMode::ModeEditor)) @@ -752,7 +752,7 @@ bool ODServer::processClientNotifications(ODSocketClient* clientSocket) std::vector tiles; int goldRequired; - gameMap->fillBuildableTilesAndPriceForPlayerInArea(x1, y1, x2, y2, player, Room::RoomType::dormitory, tiles, goldRequired); + gameMap->fillBuildableTilesAndPriceForPlayerInArea(x1, y1, x2, y2, player, type, tiles, goldRequired); if(tiles.empty()) break; @@ -941,9 +941,7 @@ bool ODServer::processClientNotifications(ODSocketClient* clientSocket) } case Trap::TrapType::boulder: { - int x, y; - OD_ASSERT_TRUE(packetReceived >> x >> y); - trap = new TrapBoulder(gameMap, x, y); + trap = new TrapBoulder(gameMap); break; } default: @@ -1297,9 +1295,7 @@ bool ODServer::processClientNotifications(ODSocketClient* clientSocket) } case Trap::TrapType::boulder: { - int x, y; - OD_ASSERT_TRUE(packetReceived >> x >> y); - trap = new TrapBoulder(gameMap, x, y); + trap = new TrapBoulder(gameMap); break; } default: diff --git a/source/RenderManager.cpp b/source/RenderManager.cpp index 6216142ef..cf4ba381b 100644 --- a/source/RenderManager.cpp +++ b/source/RenderManager.cpp @@ -29,7 +29,6 @@ #include "MapLight.h" #include "Creature.h" #include "Weapon.h" -#include "MissileObject.h" #include "Trap.h" #include "Player.h" #include "ResourceManager.h" @@ -275,14 +274,6 @@ bool RenderManager::handleRenderRequest(const RenderRequest& renderRequest) rrDestroyWeapon(renderRequest); break; - case RenderRequest::createMissileObject: - rrCreateMissileObject(renderRequest); - break; - - case RenderRequest::destroyMissileObject: - rrDestroyMissileObject(renderRequest); - break; - case RenderRequest::createMapLight: rrCreateMapLight(renderRequest); break; @@ -333,13 +324,6 @@ bool RenderManager::handleRenderRequest(const RenderRequest& renderRequest) break; } - case RenderRequest::deleteMissileObject: - { - MissileObject* curMissileObject = static_cast(renderRequest.p); - delete curMissileObject; - break; - } - case RenderRequest::moveSceneNode: rrMoveSceneNode(renderRequest); break; @@ -863,34 +847,6 @@ void RenderManager::rrDestroyWeapon(const RenderRequest& renderRequest) } } -void RenderManager::rrCreateMissileObject(const RenderRequest& renderRequest) -{ - MissileObject* curMissileObject = static_cast(renderRequest.p); - Ogre::Entity* ent = mSceneManager->createEntity(curMissileObject->getOgreNamePrefix() - + curMissileObject->getName(), curMissileObject->getMeshName() + ".mesh"); - //TODO: Make a new subroot scene node for these so lookups are faster - // since only a few missile objects should be onscreen at once. - Ogre::SceneNode* node = mCreatureSceneNode->createChildSceneNode( - ent->getName() + "_node"); - node->setPosition(curMissileObject->getPosition()); - node->attachObject(ent); -} - -void RenderManager::rrDestroyMissileObject(const RenderRequest& renderRequest) -{ - MissileObject* curMissileObject = static_cast(renderRequest.p); - std::string moName = curMissileObject->getOgreNamePrefix() + curMissileObject->getName(); - if (mSceneManager->hasEntity(moName)) - { - Ogre::Entity* ent = mSceneManager->getEntity(moName); - Ogre::SceneNode* node = mSceneManager->getSceneNode(moName + "_node"); - node->detachObject(ent); - mCreatureSceneNode->removeChild(node); - mSceneManager->destroyEntity(ent); - mSceneManager->destroySceneNode(node->getName()); - } -} - void RenderManager::rrCreateMapLight(const RenderRequest& renderRequest) { MapLight* curMapLight = static_cast (renderRequest.p); diff --git a/source/RenderManager.h b/source/RenderManager.h index f9ef96166..94d1d41d6 100644 --- a/source/RenderManager.h +++ b/source/RenderManager.h @@ -118,8 +118,6 @@ class RenderManager: public Ogre::Singleton void rrScaleSceneNode(const RenderRequest& renderRequest); void rrCreateWeapon(const RenderRequest& renderRequest); void rrDestroyWeapon(const RenderRequest& renderRequest); - void rrCreateMissileObject(const RenderRequest& renderRequest); - void rrDestroyMissileObject(const RenderRequest& renderRequest); void rrCreateMapLight(const RenderRequest& renderRequest); void rrDestroyMapLight(const RenderRequest& renderRequest); void rrDestroyMapLightVisualIndicator(const RenderRequest& renderRequest); diff --git a/source/RenderRequest.h b/source/RenderRequest.h index 478fb2fa3..c53419954 100644 --- a/source/RenderRequest.h +++ b/source/RenderRequest.h @@ -73,9 +73,6 @@ class RenderRequest orientSceneNodeToward, reorientSceneNode, scaleSceneNode, - createMissileObject, - destroyMissileObject, - deleteMissileObject, //setMissileObjectAnimationState, noRequest }; diff --git a/source/RenderedMovableEntity.cpp b/source/RenderedMovableEntity.cpp index 83c0c5ac2..da331848b 100644 --- a/source/RenderedMovableEntity.cpp +++ b/source/RenderedMovableEntity.cpp @@ -23,6 +23,7 @@ #include "RenderManager.h" #include "TreasuryObject.h" #include "ChickenEntity.h" +#include "MissileObject.h" #include "LogManager.h" #include @@ -38,11 +39,12 @@ RenderedMovableEntity::RenderedMovableEntity(GameMap* gameMap, const std::string setObjectType(GameEntity::renderedMovableEntity); setMeshName(nMeshName); // Set a unique name for the object - setName(gameMap->nextUniqueNameRoomObj(baseName)); + setName(gameMap->nextUniqueNameRenderedMovableEntity(baseName)); } RenderedMovableEntity::RenderedMovableEntity(GameMap* gameMap) : MovableGameEntity(gameMap), + mRotationAngle(0.0), mIsOnMap(true) { setObjectType(GameEntity::renderedMovableEntity); @@ -108,19 +110,29 @@ const char* RenderedMovableEntity::getFormat() RenderedMovableEntity* RenderedMovableEntity::getRenderedMovableEntityFromLine(GameMap* gameMap, const std::string& line) { RenderedMovableEntity* obj = nullptr; - std::stringstream ss(line); + std::stringstream is(line); RenderedMovableEntity::RenderedMovableEntityType rot; - OD_ASSERT_TRUE(ss >> rot); + OD_ASSERT_TRUE(is >> rot); switch(rot) { case RenderedMovableEntityType::buildingObject: { - // Default type. Used in buildings. Should not be saved in level file + obj = new RenderedMovableEntity(gameMap); break; } case RenderedMovableEntityType::treasuryObject: { - obj = TreasuryObject::getTreasuryObjectFromStream(gameMap, ss); + obj = TreasuryObject::getTreasuryObjectFromStream(gameMap, is); + break; + } + case RenderedMovableEntityType::chickenEntity: + { + obj = ChickenEntity::getChickenEntityFromStream(gameMap, is); + break; + } + case RenderedMovableEntityType::missileObject: + { + obj = MissileObject::getMissileObjectFromStream(gameMap, is); break; } default: @@ -130,6 +142,11 @@ RenderedMovableEntity* RenderedMovableEntity::getRenderedMovableEntityFromLine(G break; } } + + if(obj == nullptr) + return nullptr; + + obj->importFromStream(is); return obj; } @@ -143,7 +160,6 @@ RenderedMovableEntity* RenderedMovableEntity::getRenderedMovableEntityFromPacket case RenderedMovableEntityType::buildingObject: { obj = new RenderedMovableEntity(gameMap); - OD_ASSERT_TRUE(is >> obj); break; } case RenderedMovableEntityType::treasuryObject: @@ -156,6 +172,11 @@ RenderedMovableEntity* RenderedMovableEntity::getRenderedMovableEntityFromPacket obj = ChickenEntity::getChickenEntityFromPacket(gameMap, is); break; } + case RenderedMovableEntityType::missileObject: + { + obj = MissileObject::getMissileObjectFromPacket(gameMap, is); + break; + } default: { OD_ASSERT_TRUE_MSG(false, "Unknown enum value : " + Ogre::StringConverter::toString( @@ -163,36 +184,69 @@ RenderedMovableEntity* RenderedMovableEntity::getRenderedMovableEntityFromPacket break; } } + + if(obj == nullptr) + return nullptr; + + obj->importFromPacket(is); return obj; } -void RenderedMovableEntity::exportToPacket(ODPacket& packet) +void RenderedMovableEntity::exportHeadersToStream(std::ostream& os) +{ + os << getRenderedMovableEntityType() << "\t"; +} + +void RenderedMovableEntity::exportHeadersToPacket(ODPacket& os) { - packet << this; + os << getRenderedMovableEntityType(); } -ODPacket& operator<<(ODPacket& os, RenderedMovableEntity* ro) +void RenderedMovableEntity::exportToPacket(ODPacket& os) { - std::string name = ro->getName(); - std::string meshName = ro->getMeshName(); - Ogre::Vector3 position = ro->getPosition(); + std::string name = getName(); + std::string meshName = getMeshName(); + Ogre::Vector3 position = getPosition(); os << name << meshName; - os << position << ro->mRotationAngle; - return os; + os << position << mRotationAngle; } -ODPacket& operator>>(ODPacket& is, RenderedMovableEntity* ro) +void RenderedMovableEntity::importFromPacket(ODPacket& is) { std::string name; + std::string meshName; Ogre::Vector3 position; - is >> name; - ro->setName(name); - is >> name; - ro->setMeshName(name); - is >> position; - ro->setPosition(position); - is >> ro->mRotationAngle; - return is; + OD_ASSERT_TRUE(is >> name); + setName(name); + OD_ASSERT_TRUE(is >> meshName); + setMeshName(meshName); + OD_ASSERT_TRUE(is >> position); + setPosition(position); + OD_ASSERT_TRUE(is >> mRotationAngle); +} + +void RenderedMovableEntity::exportToStream(std::ostream& os) +{ + std::string name = getName(); + std::string meshName = getMeshName(); + Ogre::Vector3 position = getPosition(); + os << name << "\t" << meshName << "\t"; + os << position.x << "\t" << position.y << "\t" << position.z << "\t"; + os << mRotationAngle << "\t"; +} + +void RenderedMovableEntity::importFromStream(std::istream& is) +{ + std::string name; + std::string meshName; + Ogre::Vector3 position; + OD_ASSERT_TRUE(is >> name); + setName(name); + OD_ASSERT_TRUE(is >> meshName); + setMeshName(meshName); + OD_ASSERT_TRUE(is >> position.x >> position.y >> position.z); + setPosition(position); + OD_ASSERT_TRUE(is >> mRotationAngle); } ODPacket& operator<<(ODPacket& os, const RenderedMovableEntity::RenderedMovableEntityType& rot) diff --git a/source/RenderedMovableEntity.h b/source/RenderedMovableEntity.h index f80d8f55b..ca5969671 100644 --- a/source/RenderedMovableEntity.h +++ b/source/RenderedMovableEntity.h @@ -36,7 +36,8 @@ class RenderedMovableEntity: public MovableGameEntity { buildingObject, treasuryObject, - chickenEntity + chickenEntity, + missileObject }; //! \brief Creates a RenderedMovableEntity. It's name is built from baseName and some unique id from the gamemap. //! We use baseName to help understand what's this object for when getting a log @@ -81,13 +82,22 @@ class RenderedMovableEntity: public MovableGameEntity virtual void pickup(); virtual void drop(const Ogre::Vector3& v); - virtual void exportToPacket(ODPacket& packet); + /*! \brief Exports the headers needed to recreate the RenderedMovableEntity. For example, for + * missile objects type cannon, it exports RenderedMovableEntity::missileObject + * and MissileType::oneHit. The content of the RenderedMovableEntity will be exported + * by exportToPacket + */ + virtual void exportHeadersToStream(std::ostream& os); + virtual void exportHeadersToPacket(ODPacket& os); + //! \brief Exports the data of the RenderedMovableEntity + virtual void exportToStream(std::ostream& os); + virtual void importFromStream(std::istream& is); + virtual void exportToPacket(ODPacket& os); + virtual void importFromPacket(ODPacket& is); static RenderedMovableEntity* getRenderedMovableEntityFromLine(GameMap* gameMap, const std::string& line); static RenderedMovableEntity* getRenderedMovableEntityFromPacket(GameMap* gameMap, ODPacket& is); static const char* getFormat(); - friend ODPacket& operator<<(ODPacket& os, RenderedMovableEntity* o); - friend ODPacket& operator>>(ODPacket& is, RenderedMovableEntity* o); friend ODPacket& operator<<(ODPacket& os, const RenderedMovableEntity::RenderedMovableEntityType& rot); friend ODPacket& operator>>(ODPacket& is, RenderedMovableEntity::RenderedMovableEntityType& rot); @@ -101,8 +111,8 @@ class RenderedMovableEntity: public MovableGameEntity virtual void createMeshLocal(); virtual void destroyMeshLocal(); virtual void deleteYourselfLocal(); - Ogre::Real mRotationAngle; private: + Ogre::Real mRotationAngle; bool mIsOnMap; }; diff --git a/source/Room.cpp b/source/Room.cpp index 616fc1cd9..a21f2f4da 100644 --- a/source/Room.cpp +++ b/source/Room.cpp @@ -304,41 +304,38 @@ Room* Room::getRoomFromStream(GameMap* gameMap, std::istream& is) break; case dormitory: tempRoom = new RoomDormitory(gameMap); - is >> tempRoom; break; case treasury: tempRoom = new RoomTreasury(gameMap); - is >> tempRoom; break; case portal: tempRoom = new RoomPortal(gameMap); - is >> tempRoom; break; case dungeonTemple: tempRoom = new RoomDungeonTemple(gameMap); - is >> tempRoom; break; case forge: tempRoom = new RoomForge(gameMap); - is >> tempRoom; break; case trainingHall: tempRoom = new RoomTrainingHall(gameMap); - is >> tempRoom; break; case library: tempRoom = new RoomLibrary(gameMap); - is >> tempRoom; break; case hatchery: tempRoom = new RoomHatchery(gameMap); - is >> tempRoom; break; default: OD_ASSERT_TRUE_MSG(false, "Unknown enum value : " + Ogre::StringConverter::toString( static_cast(nType))); } + if(tempRoom == nullptr) + return nullptr; + + tempRoom->importFromStream(is); + return tempRoom; } @@ -355,126 +352,39 @@ Room* Room::getRoomFromPacket(GameMap* gameMap, ODPacket& is) break; case dormitory: tempRoom = new RoomDormitory(gameMap); - is >> tempRoom; break; case treasury: tempRoom = new RoomTreasury(gameMap); - is >> tempRoom; break; case portal: tempRoom = new RoomPortal(gameMap); - is >> tempRoom; break; case dungeonTemple: tempRoom = new RoomDungeonTemple(gameMap); - is >> tempRoom; break; case forge: tempRoom = new RoomForge(gameMap); - is >> tempRoom; break; case trainingHall: tempRoom = new RoomTrainingHall(gameMap); - is >> tempRoom; break; case library: tempRoom = new RoomLibrary(gameMap); - is >> tempRoom; break; case hatchery: tempRoom = new RoomHatchery(gameMap); - is >> tempRoom; break; default: OD_ASSERT_TRUE_MSG(false, "Unknown enum value : " + Ogre::StringConverter::toString( static_cast(nType))); } - return tempRoom; -} - -void Room::exportToPacket(ODPacket& packet) -{ - packet << this; -} + if(tempRoom == nullptr) + return nullptr; -void Room::exportToStream(std::ostream& os) -{ - os << this; -} + tempRoom->importFromPacket(is); -std::istream& operator>>(std::istream& is, Room* room) -{ - int tilesToLoad, tempX, tempY; - int tempInt = 0; - is >> tempInt; - Seat* seat = room->getGameMap()->getSeatById(tempInt); - OD_ASSERT_TRUE_MSG(seat != NULL, "seatId=" + Ogre::StringConverter::toString(tempInt)); - room->setSeat(seat); - - is >> tilesToLoad; - for (int i = 0; i < tilesToLoad; ++i) - { - is >> tempX >> tempY; - Tile* tempTile = room->getGameMap()->getTile(tempX, tempY); - if (tempTile != NULL) - room->addCoveredTile(tempTile, Room::DEFAULT_TILE_HP, false); - } - - return is; -} - -std::ostream& operator<<(std::ostream& os, Room *room) -{ - int seatId = room->getSeat()->getId(); - int nbTiles = room->mCoveredTiles.size(); - os << seatId << "\t" << nbTiles << "\n"; - for (std::vector::iterator it = room->mCoveredTiles.begin(); it != room->mCoveredTiles.end(); ++it) - { - Tile *tempTile = *it; - os << tempTile->x << "\t" << tempTile->y << "\n"; - } - - return os; -} - -ODPacket& operator>>(ODPacket& is, Room* room) -{ - std::string name; - int tilesToLoad, tempX, tempY; - is >> name; - room->setName(name); - int tempInt = 0; - is >> tempInt; - Seat* seat = room->getGameMap()->getSeatById(tempInt); - OD_ASSERT_TRUE_MSG(seat != NULL, "seatId=" + Ogre::StringConverter::toString(tempInt)); - room->setSeat(seat); - - is >> tilesToLoad; - for (int i = 0; i < tilesToLoad; ++i) - { - is >> tempX >> tempY; - Tile* tempTile = room->getGameMap()->getTile(tempX, tempY); - if (tempTile != NULL) - room->addCoveredTile(tempTile, Room::DEFAULT_TILE_HP, false); - } - - return is; -} - -ODPacket& operator<<(ODPacket& os, Room *room) -{ - const std::string& name = room->getName(); - int seatId = room->getSeat()->getId(); - int nbTiles = room->mCoveredTiles.size(); - os << name << seatId << nbTiles; - for (std::vector::iterator it = room->mCoveredTiles.begin(); it != room->mCoveredTiles.end(); ++it) - { - Tile* tempTile = *it; - os << tempTile->x << tempTile->y; - } - - return os; + return tempRoom; } const char* Room::getRoomNameFromRoomType(RoomType t) @@ -850,6 +760,84 @@ void Room::notifyActiveSpotRemoved(ActiveSpotPlace place, Tile* tile) removeBuildingObject(tile); } +void Room::exportHeadersToStream(std::ostream& os) +{ + os << getType() << "\t"; +} + +void Room::exportHeadersToPacket(ODPacket& os) +{ + os << getType(); +} + +void Room::exportToPacket(ODPacket& os) +{ + const std::string& name = getName(); + int seatId = getSeat()->getId(); + int nbTiles = mCoveredTiles.size(); + os << name << seatId << nbTiles; + for (std::vector::iterator it = mCoveredTiles.begin(); it != mCoveredTiles.end(); ++it) + { + Tile* tempTile = *it; + os << tempTile->x << tempTile->y; + } +} + +void Room::importFromPacket(ODPacket& is) +{ + std::string name; + int tilesToLoad, tempX, tempY; + OD_ASSERT_TRUE(is >> name); + setName(name); + int tempInt = 0; + OD_ASSERT_TRUE(is >> tempInt); + Seat* seat = getGameMap()->getSeatById(tempInt); + OD_ASSERT_TRUE_MSG(seat != NULL, "seatId=" + Ogre::StringConverter::toString(tempInt)); + setSeat(seat); + + OD_ASSERT_TRUE(is >> tilesToLoad); + for (int i = 0; i < tilesToLoad; ++i) + { + OD_ASSERT_TRUE(is >> tempX >> tempY); + Tile* tempTile = getGameMap()->getTile(tempX, tempY); + OD_ASSERT_TRUE_MSG(tempTile != NULL, "tile=" + Ogre::StringConverter::toString(tempX) + "," + Ogre::StringConverter::toString(tempY)); + if (tempTile != NULL) + addCoveredTile(tempTile, Room::DEFAULT_TILE_HP, false); + } +} + +void Room::exportToStream(std::ostream& os) +{ + int seatId = getSeat()->getId(); + int nbTiles = mCoveredTiles.size(); + os << seatId << "\t" << nbTiles << "\n"; + for (std::vector::iterator it = mCoveredTiles.begin(); it != mCoveredTiles.end(); ++it) + { + Tile *tempTile = *it; + os << tempTile->x << "\t" << tempTile->y << "\n"; + } +} + +void Room::importFromStream(std::istream& is) +{ + int tilesToLoad, tempX, tempY; + int tempInt = 0; + OD_ASSERT_TRUE(is >> tempInt); + Seat* seat = getGameMap()->getSeatById(tempInt); + OD_ASSERT_TRUE_MSG(seat != NULL, "seatId=" + Ogre::StringConverter::toString(tempInt)); + setSeat(seat); + + OD_ASSERT_TRUE(is >> tilesToLoad); + for (int i = 0; i < tilesToLoad; ++i) + { + OD_ASSERT_TRUE(is >> tempX >> tempY); + Tile* tempTile = getGameMap()->getTile(tempX, tempY); + OD_ASSERT_TRUE_MSG(tempTile != NULL, "tile=" + Ogre::StringConverter::toString(tempX) + "," + Ogre::StringConverter::toString(tempY)); + if (tempTile != NULL) + addCoveredTile(tempTile, Room::DEFAULT_TILE_HP, false); + } +} + bool Room::sortForMapSave(Room* r1, Room* r2) { // We sort room by seat id then meshName diff --git a/source/Room.h b/source/Room.h index 86c6b31f9..72eb280e8 100644 --- a/source/Room.h +++ b/source/Room.h @@ -57,16 +57,20 @@ class Room : public Building virtual void absorbRoom(Room* r); static std::string getFormat(); - friend std::ostream& operator<<(std::ostream& os, Room *room); - friend std::istream& operator>>(std::istream& is, Room *room); - friend ODPacket& operator<<(ODPacket& os, Room *room); - friend ODPacket& operator>>(ODPacket& is, Room *room); static Room* getRoomFromStream(GameMap* gameMap, std::istream& is); static Room* getRoomFromPacket(GameMap* gameMap, ODPacket& is); + /*! \brief Exports the headers needed to recreate the Room. It allows to extend Room as much as wanted. + * The content of the Room will be exported by exportToPacket. + */ + virtual void exportHeadersToStream(std::ostream& os); + virtual void exportHeadersToPacket(ODPacket& os); + //! \brief Exports the data of the RenderedMovableEntity virtual void exportToStream(std::ostream& os); - virtual void exportToPacket(ODPacket& packet); + virtual void importFromStream(std::istream& is); + virtual void exportToPacket(ODPacket& os); + virtual void importFromPacket(ODPacket& is); void createBuildingObjectMeshes(); void destroyBuildingObjectMeshes(); diff --git a/source/ServerNotification.cpp b/source/ServerNotification.cpp index 90dda17a9..98781918c 100644 --- a/source/ServerNotification.cpp +++ b/source/ServerNotification.cpp @@ -98,10 +98,6 @@ std::string ServerNotification::typeString(ServerNotificationType type) return "tileClaimed"; case ServerNotificationType::refreshPlayerSeat: return "refreshPlayerSeat"; - case ServerNotificationType::addMissileObject: - return "addMissileObject"; - case ServerNotificationType::removeMissileObject: - return "removeMissileObject"; case ServerNotificationType::addRenderedMovableEntity: return "addRenderedMovableEntity"; case ServerNotificationType::removeRenderedMovableEntity: diff --git a/source/ServerNotification.h b/source/ServerNotification.h index d75d66264..e2c448ba8 100644 --- a/source/ServerNotification.h +++ b/source/ServerNotification.h @@ -79,8 +79,6 @@ class ServerNotification creatureRefresh, tileClaimed, refreshPlayerSeat, - addMissileObject, - removeMissileObject, addRenderedMovableEntity, removeRenderedMovableEntity, depositGoldSound, // Makes the client play a deposit gold sound at tile coordinates. diff --git a/source/Tile.cpp b/source/Tile.cpp index 695e727db..96101a4f5 100644 --- a/source/Tile.cpp +++ b/source/Tile.cpp @@ -1290,7 +1290,7 @@ int Tile::getFloodFill(FloodFillType type) return mFloodFillColor[type]; } -void Tile::fillAttackableObjects(std::vector& entities, Seat* seat, bool invert) +void Tile::fillAttackableCreatures(std::vector& entities, Seat* seat, bool invert) { for(std::vector::iterator it = creaturesInCell.begin(); it != creaturesInCell.end(); ++it) { @@ -1305,10 +1305,14 @@ void Tile::fillAttackableObjects(std::vector& entities, Seat* seat, && creature->getSeat()->isAlliedSeat(seat))) { // Add the current creature - entities.push_back(creature); + if (std::find(entities.begin(), entities.end(), creature) == entities.end()) + entities.push_back(creature); } } +} +void Tile::fillAttackableRoom(std::vector& entities, Seat* seat, bool invert) +{ Room *room = getCoveringRoom(); if((room != NULL) && room->isAttackable()) { @@ -1320,7 +1324,10 @@ void Tile::fillAttackableObjects(std::vector& entities, Seat* seat, entities.push_back(room); } } +} +void Tile::fillAttackableTrap(std::vector& entities, Seat* seat, bool invert) +{ Trap *trap = getCoveringTrap(); if((trap != NULL) && trap->isAttackable()) { diff --git a/source/Tile.h b/source/Tile.h index 1573a398a..54cb7cb16 100644 --- a/source/Tile.h +++ b/source/Tile.h @@ -291,10 +291,13 @@ friend class ODServer; std::vector getCoveredTiles() { return std::vector() ;} void refreshFromTile(const Tile& tile); - //! \brief Fills entities with all the attackable entities in the Tile. If invert is true, + //! \brief Fills entities with all the attackable creatures in the Tile. If invert is true, //! the list will be filled with the ennemies with the given seat. If invert is false, it will be filled - //! with allies with the given seat. - void fillAttackableObjects(std::vector& entities, Seat* seat, bool invert); + //! with allies with the given seat. For all theses functions, the list is checked to be sure + //! no entity is added twice + void fillAttackableCreatures(std::vector& entities, Seat* seat, bool invert); + void fillAttackableRoom(std::vector& entities, Seat* seat, bool invert); + void fillAttackableTrap(std::vector& entities, Seat* seat, bool invert); bool addChickenEntity(ChickenEntity* chicken); bool removeChickenEntity(ChickenEntity* chicken); diff --git a/source/Trap.cpp b/source/Trap.cpp index 4a885e335..bfbf34f9f 100644 --- a/source/Trap.cpp +++ b/source/Trap.cpp @@ -101,12 +101,10 @@ Trap* Trap::getTrapFromStream(GameMap* gameMap, std::istream &is) tempTrap = nullptr; break; case cannon: - tempTrap = new TrapCannon(gameMap); - is >> tempTrap; + tempTrap = TrapCannon::getTrapCannonFromStream(gameMap, is); break; case spike: - tempTrap = new TrapSpike(gameMap); - is >> tempTrap; + tempTrap = TrapSpike::getTrapSpikeFromStream(gameMap, is); break; case boulder: tempTrap = TrapBoulder::getTrapBoulderFromStream(gameMap, is); @@ -116,6 +114,11 @@ Trap* Trap::getTrapFromStream(GameMap* gameMap, std::istream &is) static_cast(nType))); } + if(tempTrap == nullptr) + return nullptr; + + tempTrap->importFromStream(is); + return tempTrap; } @@ -131,12 +134,10 @@ Trap* Trap::getTrapFromPacket(GameMap* gameMap, ODPacket &is) tempTrap = nullptr; break; case cannon: - tempTrap = new TrapCannon(gameMap); - is >> tempTrap; + tempTrap = TrapCannon::getTrapCannonFromPacket(gameMap, is); break; case spike: - tempTrap = new TrapSpike(gameMap); - is >> tempTrap; + tempTrap = TrapSpike::getTrapSpikeFromPacket(gameMap, is); break; case boulder: tempTrap = TrapBoulder::getTrapBoulderFromPacket(gameMap, is); @@ -146,17 +147,12 @@ Trap* Trap::getTrapFromPacket(GameMap* gameMap, ODPacket &is) static_cast(nType))); } - return tempTrap; -} + if(tempTrap == nullptr) + return nullptr; -void Trap::exportToPacket(ODPacket& packet) -{ - packet << this; -} + tempTrap->importFromPacket(is); -void Trap::exportToStream(std::ostream& os) -{ - os << this; + return tempTrap; } const char* Trap::getTrapNameFromTrapType(TrapType t) @@ -359,84 +355,85 @@ std::string Trap::getFormat() return "typeTrap\tseatId\tnumTiles\t\tSubsequent Lines: tileX\ttileY\t\tSubsequent Lines: optional specific data"; } -std::istream& operator>>(std::istream& is, Trap *t) +void Trap::exportHeadersToStream(std::ostream& os) +{ + os << getType() << "\t"; +} + +void Trap::exportHeadersToPacket(ODPacket& os) +{ + os << getType(); +} + +void Trap::exportToPacket(ODPacket& os) +{ + int nbTiles = mCoveredTiles.size(); + const std::string& name = getName(); + int seatId = getSeat()->getId(); + os << name << seatId; + os << nbTiles; + for(std::vector::iterator it = mCoveredTiles.begin(); it != mCoveredTiles.end(); ++it) + { + Tile *tempTile = *it; + os << tempTile->x << tempTile->y; + } +} + +void Trap::importFromPacket(ODPacket& is) { int tilesToLoad, tempX, tempY, tempInt; + std::string name; + OD_ASSERT_TRUE(is >> name); + setName(name); - is >> tempInt; - t->setSeat(t->getGameMap()->getSeatById(tempInt)); + OD_ASSERT_TRUE(is >> tempInt); + setSeat(getGameMap()->getSeatById(tempInt)); - is >> tilesToLoad; + OD_ASSERT_TRUE(is >> tilesToLoad); for (int i = 0; i < tilesToLoad; ++i) { - is >> tempX >> tempY; - Tile *tempTile = t->getGameMap()->getTile(tempX, tempY); + OD_ASSERT_TRUE(is >> tempX >> tempY); + Tile *tempTile = getGameMap()->getTile(tempX, tempY); + OD_ASSERT_TRUE_MSG(tempTile != NULL, "tile=" + Ogre::StringConverter::toString(tempX) + "," + Ogre::StringConverter::toString(tempY)); if (tempTile != NULL) { - t->addCoveredTile(tempTile, Trap::DEFAULT_TILE_HP); - tempTile->setSeat(t->getSeat()); + addCoveredTile(tempTile, Trap::DEFAULT_TILE_HP); + tempTile->setSeat(getSeat()); } } - return is; } -std::ostream& operator<<(std::ostream& os, Trap *t) +void Trap::exportToStream(std::ostream& os) { - int32_t nbTiles = t->mCoveredTiles.size(); - int seatId = t->getSeat()->getId(); + int32_t nbTiles = mCoveredTiles.size(); + int seatId = getSeat()->getId(); os << seatId << "\t" << nbTiles << "\n"; - for(std::vector::iterator it = t->mCoveredTiles.begin(); it != t->mCoveredTiles.end(); ++it) + for(std::vector::iterator it = mCoveredTiles.begin(); it != mCoveredTiles.end(); ++it) { Tile *tempTile = *it; os << tempTile->x << "\t" << tempTile->y << "\n"; } - - return os; } -ODPacket& operator>>(ODPacket& is, Trap *t) +void Trap::importFromStream(std::istream& is) { int tilesToLoad, tempX, tempY, tempInt; - std::string name; - is >> name; - t->setName(name); - is >> tempInt; - t->setSeat(t->getGameMap()->getSeatById(tempInt)); + OD_ASSERT_TRUE(is >> tempInt); + setSeat(getGameMap()->getSeatById(tempInt)); - is >> tilesToLoad; + OD_ASSERT_TRUE(is >> tilesToLoad); for (int i = 0; i < tilesToLoad; ++i) { - is >> tempX >> tempY; - Tile *tempTile = t->getGameMap()->getTile(tempX, tempY); + OD_ASSERT_TRUE(is >> tempX >> tempY); + Tile *tempTile = getGameMap()->getTile(tempX, tempY); + OD_ASSERT_TRUE_MSG(tempTile != NULL, "tile=" + Ogre::StringConverter::toString(tempX) + "," + Ogre::StringConverter::toString(tempY)); if (tempTile != NULL) { - t->addCoveredTile(tempTile, Trap::DEFAULT_TILE_HP); - tempTile->setSeat(t->getSeat()); - } - else - { - LogManager::getSingleton().logMessage("ERROR : trying to add trap on unkown tile " - + Ogre::StringConverter::toString(tempX) + "," + Ogre::StringConverter::toString(tempY)); + addCoveredTile(tempTile, Trap::DEFAULT_TILE_HP); + tempTile->setSeat(getSeat()); } } - return is; -} - -ODPacket& operator<<(ODPacket& os, Trap *t) -{ - int nbTiles = t->mCoveredTiles.size(); - const std::string& name = t->getName(); - int seatId = t->getSeat()->getId(); - os << name << seatId; - os << nbTiles; - for(std::vector::iterator it = t->mCoveredTiles.begin(); it != t->mCoveredTiles.end(); ++it) - { - Tile *tempTile = *it; - os << tempTile->x << tempTile->y; - } - - return os; } std::istream& operator>>(std::istream& is, Trap::TrapType& tt) diff --git a/source/Trap.h b/source/Trap.h index 236f11061..c5c5818d6 100644 --- a/source/Trap.h +++ b/source/Trap.h @@ -56,9 +56,6 @@ class Trap : public Building static Trap* getTrapFromStream(GameMap* gameMap, std::istream &is); static Trap* getTrapFromPacket(GameMap* gameMap, ODPacket &is); - virtual void exportToStream(std::ostream& os); - virtual void exportToPacket(ODPacket& packet); - virtual const TrapType getType() const = 0; static const char* getTrapNameFromTrapType(TrapType t); @@ -80,11 +77,18 @@ class Trap : public Building virtual bool removeCoveredTile(Tile* t); virtual void updateActiveSpots(); + /*! \brief Exports the headers needed to recreate the Trap. It allows to extend Traps as much as wanted. + * The content of the Trap will be exported by exportToPacket. + */ + virtual void exportHeadersToStream(std::ostream& os); + virtual void exportHeadersToPacket(ODPacket& os); + //! \brief Exports the data of the RenderedMovableEntity + virtual void exportToStream(std::ostream& os); + virtual void importFromStream(std::istream& is); + virtual void exportToPacket(ODPacket& os); + virtual void importFromPacket(ODPacket& is); + static std::string getFormat(); - friend std::istream& operator>>(std::istream& is, Trap *t); - friend std::ostream& operator<<(std::ostream& os, Trap *t); - friend ODPacket& operator>>(ODPacket& is, Trap *t); - friend ODPacket& operator<<(ODPacket& os, Trap *t); friend std::istream& operator>>(std::istream& is, Trap::TrapType& tt); friend std::ostream& operator<<(std::ostream& os, const Trap::TrapType& tt); friend ODPacket& operator>>(ODPacket& is, Trap::TrapType& tt); diff --git a/source/TrapBoulder.cpp b/source/TrapBoulder.cpp index b29ee72f6..4895cd257 100644 --- a/source/TrapBoulder.cpp +++ b/source/TrapBoulder.cpp @@ -18,122 +18,74 @@ #include "TrapBoulder.h" #include "ODPacket.h" #include "GameMap.h" +#include "Random.h" +#include "MissileBoulder.h" #include "LogManager.h" -TrapBoulder::TrapBoulder(GameMap* gameMap, int x, int y) : - DirectionalTrap(gameMap, x, y) -{ - mReloadTime = 20; - mMinDamage = 30; - mMaxDamage = 40; - setMeshName("Boulder"); -} - TrapBoulder::TrapBoulder(GameMap* gameMap) : - DirectionalTrap(gameMap) + Trap(gameMap) { - mReloadTime = 20; - mMinDamage = 30; - mMaxDamage = 40; + mReloadTime = 100; + mMinDamage = 100; + mMaxDamage = 120; setMeshName("Boulder"); } -TrapBoulder* TrapBoulder::getTrapBoulderFromStream(GameMap* gameMap, std::istream& is) +TrapBoulder* TrapBoulder::getTrapBoulderFromStream(GameMap* gameMap, std::istream &is) { TrapBoulder* trap = new TrapBoulder(gameMap); - is >> trap; return trap; } -TrapBoulder* TrapBoulder::getTrapBoulderFromPacket(GameMap* gameMap, ODPacket& is) +TrapBoulder* TrapBoulder::getTrapBoulderFromPacket(GameMap* gameMap, ODPacket &is) { TrapBoulder* trap = new TrapBoulder(gameMap); - is >> trap; return trap; } -std::istream& operator>>(std::istream& is, TrapBoulder *trap) +bool TrapBoulder::shoot(Tile* tile) { - int tilesToLoad, tempX, tempY, tempInt; - - is >> tempInt; - trap->setSeat(trap->getGameMap()->getSeatById(tempInt)); - - is >> tilesToLoad; - for (int i = 0; i < tilesToLoad; ++i) + std::vector tiles = tile->getAllNeighbors(); + for(std::vector::iterator it = tiles.begin(); it != tiles.end();) { - is >> tempX >> tempY; - Tile *tempTile = trap->getGameMap()->getTile(tempX, tempY); - if (tempTile != NULL) - { - trap->addCoveredTile(tempTile, Trap::DEFAULT_TILE_HP); - tempTile->setSeat(trap->getSeat()); - } - } - is >> tempX >> tempY; - trap->mDir = std::pair(tempX, tempY); - - return is; -} + Tile* tmpTile = *it; + std::vector vecTile; + vecTile.push_back(tmpTile); -std::ostream& operator<<(std::ostream& os, TrapBoulder *trap) -{ - int32_t nbTiles = trap->mCoveredTiles.size(); - int seatId = trap->getSeat()->getId(); - os << seatId << "\t" << nbTiles << "\n"; - for(std::vector::iterator it = trap->mCoveredTiles.begin(); it != trap->mCoveredTiles.end(); ++it) - { - Tile *tempTile = *it; - os << tempTile->x << "\t" << tempTile->y << "\n"; + if(getGameMap()->getVisibleCreatures(vecTile, getSeat(), true).empty()) + it = tiles.erase(it); + else + ++it; } - os << trap->mDir.first << "\t" << trap->mDir.second << "\n"; - return os; -} + if(tiles.empty()) + return false; -ODPacket& operator>>(ODPacket& is, TrapBoulder *trap) -{ - int tilesToLoad, tempX, tempY, tempInt; - std::string name; - is >> name; - trap->setName(name); + // We take a random tile and launch boulder it + Tile* tileChoosen = tiles[Random::Uint(0, tiles.size() - 1)]; + // We launch the boulder + Ogre::Vector3 direction(static_cast(tileChoosen->getX() - tile->getX()), + static_cast(tileChoosen->getY() - tile->getY()), + 0); + Ogre::Vector3 position; + position.x = static_cast(tile->getX()); + position.y = static_cast(tile->getY()); + position.z = 0; + direction.normalise(); + MissileBoulder* missile = new MissileBoulder(getGameMap(), getSeat(), getName(), "Boulder", + direction, Random::Double(mMinDamage, mMaxDamage)); + missile->setPosition(position); + getGameMap()->addRenderedMovableEntity(missile); + missile->setMoveSpeed(1.0); + missile->createMesh(); + // We don't want the missile to stay idle for 1 turn. Because we are in a doUpkeep context, + // we can safely call the missile doUpkeep as we know the engine will not call it the turn + // it has been added + missile->doUpkeep(); - is >> tempInt; - trap->setSeat(trap->getGameMap()->getSeatById(tempInt)); - - is >> tilesToLoad; - for (int i = 0; i < tilesToLoad; ++i) - { - is >> tempX >> tempY; - Tile *tempTile = trap->getGameMap()->getTile(tempX, tempY); - if (tempTile != NULL) - { - trap->addCoveredTile(tempTile, Trap::DEFAULT_TILE_HP); - tempTile->setSeat(trap->getSeat()); - } - else - { - LogManager::getSingleton().logMessage("ERROR : trying to add trap on unkown tile " - + Ogre::StringConverter::toString(tempX) + "," + Ogre::StringConverter::toString(tempY)); - } - } - is >> tempX >> tempY; - trap->mDir = std::pair(tempX, tempY); - return is; + return true; } -ODPacket& operator<<(ODPacket& os, TrapBoulder *trap) +RenderedMovableEntity* TrapBoulder::notifyActiveSpotCreated(Tile* tile) { - int nbTiles = trap->mCoveredTiles.size(); - const std::string& name = trap->getName(); - int seatId = trap->getSeat()->getId(); - os << name << seatId; - os << nbTiles; - for(std::vector::iterator it = trap->mCoveredTiles.begin(); it != trap->mCoveredTiles.end(); ++it) - { - Tile *tempTile = *it; - os << tempTile->x << tempTile->y; - } - os << trap->mDir.first << trap->mDir.second; - - return os; + return loadBuildingObject(getGameMap(), "Boulder", tile, 0.0); } diff --git a/source/TrapBoulder.h b/source/TrapBoulder.h index 97fdb7a6b..57d9022df 100644 --- a/source/TrapBoulder.h +++ b/source/TrapBoulder.h @@ -18,25 +18,31 @@ #ifndef TRAPBOULDER_H #define TRAPBOULDER_H -#include "DirectionalTrap.h" +#include "Trap.h" -class TrapBoulder : public DirectionalTrap +class TrapBoulder : public Trap { public: - TrapBoulder(GameMap* gameMap, int x, int y); + TrapBoulder(GameMap* gameMap); - static TrapBoulder* getTrapBoulderFromStream(GameMap* gameMap, std::istream& is); - static TrapBoulder* getTrapBoulderFromPacket(GameMap* gameMap, ODPacket& is); + static TrapBoulder* getTrapBoulderFromStream(GameMap* gameMap, std::istream &is); + static TrapBoulder* getTrapBoulderFromPacket(GameMap* gameMap, ODPacket &is); virtual const TrapType getType() const { return TrapType::boulder; } - friend std::istream& operator>>(std::istream& is, TrapBoulder *trap); - friend std::ostream& operator<<(std::ostream& os, TrapBoulder *trap); - friend ODPacket& operator>>(ODPacket& is, TrapBoulder *trap); - friend ODPacket& operator<<(ODPacket& os, TrapBoulder *trap); -private: - TrapBoulder(GameMap* gameMap); + virtual bool shoot(Tile* tile); + virtual bool isAttackable() const + { + return false; + } + + virtual bool shouldDisplayMeshOnGround() + { + return false; + } + + virtual RenderedMovableEntity* notifyActiveSpotCreated(Tile* tile); }; #endif // TRAPBOULDER_H diff --git a/source/TrapCannon.cpp b/source/TrapCannon.cpp index d3867e128..10f321fa9 100644 --- a/source/TrapCannon.cpp +++ b/source/TrapCannon.cpp @@ -19,13 +19,15 @@ #include "ODPacket.h" #include "Tile.h" #include "GameMap.h" -#include "MissileObject.h" +#include "MissileOneHit.h" #include "Random.h" #include "LogManager.h" +const Ogre::Real CANNON_MISSILE_HEIGHT = 0.3; +const Ogre::Real CANNON_MISSILE_SPEED = 5; + TrapCannon::TrapCannon(GameMap* gameMap) : - ProximityTrap(gameMap), - mCannonHeight(1.5) + ProximityTrap(gameMap) { mReloadTime = 5; mRange = 10; @@ -37,7 +39,7 @@ TrapCannon::TrapCannon(GameMap* gameMap) : bool TrapCannon::shoot(Tile* tile) { std::vector visibleTiles = getGameMap()->visibleTiles(tile, mRange); - std::vector enemyObjects = getGameMap()->getVisibleForce(visibleTiles, getSeat(), true); + std::vector enemyObjects = getGameMap()->getVisibleCreatures(visibleTiles, getSeat(), true); if(enemyObjects.empty()) return false; @@ -45,22 +47,27 @@ bool TrapCannon::shoot(Tile* tile) // Select an enemy to shoot at. GameEntity* targetEnemy = enemyObjects[Random::Uint(0, enemyObjects.size()-1)]; - // TODO : instead of dealing damages here, add to MissileObject the needed infos to make it damage the - // target when hit (to allow pickup before getting hurt or dodging) - targetEnemy->takeDamage(this, Random::Double(mMinDamage, mMaxDamage), targetEnemy->getCoveredTiles()[0]); // Create the cannonball to move toward the enemy creature. - MissileObject *tempMissileObject = new MissileObject(getGameMap(), - "Cannonball", Ogre::Vector3((Ogre::Real)tile->x, (Ogre::Real)tile->y, - (Ogre::Real)mCannonHeight)); + Ogre::Vector3 direction(static_cast(targetEnemy->getCoveredTiles()[0]->x), + static_cast(targetEnemy->getCoveredTiles()[0]->y), + CANNON_MISSILE_HEIGHT); - //TODO: Make this a pseudo newtonian mechanics solver which computes a parabola passing through the cannon - // and the enemy it is shooting at, add this as 10 or so destinations in the queue instead of just one. - getGameMap()->addMissileObject(tempMissileObject); - tempMissileObject->setMoveSpeed(8.0); - tempMissileObject->createMesh(); - tempMissileObject->addDestination((Ogre::Real)targetEnemy->getCoveredTiles()[0]->x, - (Ogre::Real)targetEnemy->getCoveredTiles()[0]->y, - (Ogre::Real)mCannonHeight); + Ogre::Vector3 position; + position.x = static_cast(tile->x); + position.y = static_cast(tile->y); + position.z = CANNON_MISSILE_HEIGHT; + direction = direction - position; + direction.normalise(); + MissileOneHit* missile = new MissileOneHit(getGameMap(), getSeat(), getName(), "Cannonball", + direction, Random::Double(mMinDamage, mMaxDamage), false); + missile->setPosition(position); + getGameMap()->addRenderedMovableEntity(missile); + missile->setMoveSpeed(CANNON_MISSILE_SPEED); + missile->createMesh(); + // We don't want the missile to stay idle for 1 turn. Because we are in a doUpkeep context, + // we can safely call the missile doUpkeep as we know the engine will not call it the turn + // it has been added + missile->doUpkeep(); return true; } @@ -68,3 +75,15 @@ RenderedMovableEntity* TrapCannon::notifyActiveSpotCreated(Tile* tile) { return loadBuildingObject(getGameMap(), "Cannon", tile, 90.0); } + +TrapCannon* TrapCannon::getTrapCannonFromStream(GameMap* gameMap, std::istream &is) +{ + TrapCannon* trap = new TrapCannon(gameMap); + return trap; +} + +TrapCannon* TrapCannon::getTrapCannonFromPacket(GameMap* gameMap, ODPacket &is) +{ + TrapCannon* trap = new TrapCannon(gameMap); + return trap; +} diff --git a/source/TrapCannon.h b/source/TrapCannon.h index 544c3ef3a..f3dfe2625 100644 --- a/source/TrapCannon.h +++ b/source/TrapCannon.h @@ -27,6 +27,9 @@ class TrapCannon : public ProximityTrap public: TrapCannon(GameMap* gameMap); + static TrapCannon* getTrapCannonFromStream(GameMap* gameMap, std::istream &is); + static TrapCannon* getTrapCannonFromPacket(GameMap* gameMap, ODPacket &is); + virtual const TrapType getType() const { return TrapType::cannon; } @@ -36,11 +39,6 @@ class TrapCannon : public ProximityTrap return false; } virtual RenderedMovableEntity* notifyActiveSpotCreated(Tile* tile); - - static TrapCannon* getTrapCannonFromPacket(GameMap* gameMap, ODPacket& packet); - -private: - double mCannonHeight; }; #endif // TRAPCANNON_H diff --git a/source/TrapSpike.cpp b/source/TrapSpike.cpp index e8027aa8f..118c14e38 100644 --- a/source/TrapSpike.cpp +++ b/source/TrapSpike.cpp @@ -19,7 +19,6 @@ #include "Tile.h" #include "GameMap.h" -#include "MissileObject.h" #include "Random.h" #include "RenderedMovableEntity.h" #include "LogManager.h" @@ -38,36 +37,41 @@ bool TrapSpike::shoot(Tile* tile) { std::vector visibleTiles; visibleTiles.push_back(tile); - std::vector enemyObjects = getGameMap()->getVisibleForce(visibleTiles, getSeat(), true); - if(enemyObjects.empty()) + std::vector enemyCreatures = getGameMap()->getVisibleCreatures(visibleTiles, getSeat(), true); + if(enemyCreatures.empty()) return false; RenderedMovableEntity* spike = getBuildingObjectFromTile(tile); spike->setAnimationState("Triggered", false); // We damage every creature standing on the trap - for(std::vector::iterator it = enemyObjects.begin(); it != enemyObjects.end(); ++it) + for(std::vector::iterator it = enemyCreatures.begin(); it != enemyCreatures.end(); ++it) { GameEntity* target = *it; - if(target->getObjectType() != GameEntity::ObjectType::creature) - continue; - target->takeDamage(this, Random::Double(mMinDamage, mMaxDamage), target->getCoveredTiles()[0]); } - std::vector alliedObjects = getGameMap()->getVisibleForce(visibleTiles, getSeat(), false); - for(std::vector::iterator it = alliedObjects.begin(); it != alliedObjects.end(); ++it) + std::vector alliedCreatures = getGameMap()->getVisibleCreatures(visibleTiles, getSeat(), false); + for(std::vector::iterator it = alliedCreatures.begin(); it != alliedCreatures.end(); ++it) { GameEntity* target = *it; - if(target->getObjectType() != GameEntity::ObjectType::creature) - continue; - target->takeDamage(this, Random::Double(mMinDamage, mMaxDamage), target->getCoveredTiles()[0]); } return true; } - RenderedMovableEntity* TrapSpike::notifyActiveSpotCreated(Tile* tile) { return loadBuildingObject(getGameMap(), "Spiketrap", tile, 0.0); } + +TrapSpike* TrapSpike::getTrapSpikeFromStream(GameMap* gameMap, std::istream &is) +{ + TrapSpike* trap = new TrapSpike(gameMap); + return trap; +} + +TrapSpike* TrapSpike::getTrapSpikeFromPacket(GameMap* gameMap, ODPacket &is) +{ + TrapSpike* trap = new TrapSpike(gameMap); + return trap; +} diff --git a/source/TrapSpike.h b/source/TrapSpike.h index 7a801f63a..a29c5b1a3 100644 --- a/source/TrapSpike.h +++ b/source/TrapSpike.h @@ -25,6 +25,9 @@ class TrapSpike : public ProximityTrap public: TrapSpike(GameMap* gameMap); + static TrapSpike* getTrapSpikeFromStream(GameMap* gameMap, std::istream &is); + static TrapSpike* getTrapSpikeFromPacket(GameMap* gameMap, ODPacket &is); + virtual const TrapType getType() const { return TrapType::spike; } diff --git a/source/TreasuryObject.cpp b/source/TreasuryObject.cpp index 07887d10a..2667ed705 100644 --- a/source/TreasuryObject.cpp +++ b/source/TreasuryObject.cpp @@ -54,7 +54,7 @@ void TreasuryObject::doUpkeep() // We check if we are on a tile where there is a treasury room. If so, we add gold there Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return; @@ -93,8 +93,8 @@ bool TreasuryObject::tryPickup(Seat* seat, bool isEditorMode) return false; Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != NULL, "tile=" + Tile::displayAsString(tile)); - if(tile == NULL) + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); + if(tile == nullptr) return false; if(!tile->isClaimedForSeat(seat) && !isEditorMode) @@ -107,7 +107,7 @@ void TreasuryObject::pickup() { Tile* tile = getPositionTile(); RenderedMovableEntity::pickup(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return; @@ -134,7 +134,7 @@ void TreasuryObject::setPosition(const Ogre::Vector3& v) { RenderedMovableEntity::setPosition(v); Tile* tile = getPositionTile(); - OD_ASSERT_TRUE_MSG(tile != nullptr, "tile=" + Tile::displayAsString(tile)); + OD_ASSERT_TRUE_MSG(tile != nullptr, "entityName=" + getName()); if(tile == nullptr) return; @@ -151,56 +151,35 @@ const char* TreasuryObject::getFormat() TreasuryObject* TreasuryObject::getTreasuryObjectFromStream(GameMap* gameMap, std::istream& is) { TreasuryObject* obj = new TreasuryObject(gameMap); - Ogre::Vector3 position; - Ogre::Real x, y, z; - OD_ASSERT_TRUE(is >> x >> y >> z); - obj->setPosition(Ogre::Vector3(x, y, z)); - OD_ASSERT_TRUE(is >> obj->mGoldValue); return obj; - } -TreasuryObject* TreasuryObject::getTreasuryObjectFromPacket(GameMap* gameMap, ODPacket& packet) +TreasuryObject* TreasuryObject::getTreasuryObjectFromPacket(GameMap* gameMap, ODPacket& is) { TreasuryObject* obj = new TreasuryObject(gameMap); - OD_ASSERT_TRUE(packet >> obj); return obj; } -void TreasuryObject::exportToPacket(ODPacket& packet) +void TreasuryObject::exportToPacket(ODPacket& os) { - packet << this; + RenderedMovableEntity::exportToPacket(os); + os << mGoldValue; } -std::ostream& operator<<(std::ostream& os, TreasuryObject* obj) +void TreasuryObject::importFromPacket(ODPacket& is) { - std::string name = obj->getName(); - Ogre::Vector3 position = obj->getPosition(); - os << name; - os << position.x; - os << position.y; - os << position.z; - os << obj->mGoldValue; - return os; + RenderedMovableEntity::importFromPacket(is); + OD_ASSERT_TRUE(is >> mGoldValue); } -ODPacket& operator>>(ODPacket& is, TreasuryObject* obj) +void TreasuryObject::exportToStream(std::ostream& os) { - std::string name; - OD_ASSERT_TRUE(is >> name); - obj->setName(name); - Ogre::Vector3 position; - OD_ASSERT_TRUE(is >> position); - obj->setPosition(position); - return is; + RenderedMovableEntity::exportToStream(os); + os << mGoldValue << "\t"; } -ODPacket& operator<<(ODPacket& os, TreasuryObject* obj) +void TreasuryObject::importFromStream(std::istream& is) { - std::string name = obj->getName(); - std::string meshName = obj->getMeshName(); - Ogre::Vector3 position = obj->getPosition(); - os << name; - os << position; - return os; + RenderedMovableEntity::importFromStream(is); + OD_ASSERT_TRUE(is >> mGoldValue); } diff --git a/source/TreasuryObject.h b/source/TreasuryObject.h index a3922409f..e4cd60b28 100644 --- a/source/TreasuryObject.h +++ b/source/TreasuryObject.h @@ -44,16 +44,17 @@ class TreasuryObject: public RenderedMovableEntity void mergeGold(TreasuryObject* obj); void addGold(int goldValue); - virtual void exportToPacket(ODPacket& packet); + virtual void exportToStream(std::ostream& os); + virtual void importFromStream(std::istream& is); + virtual void exportToPacket(ODPacket& os); + virtual void importFromPacket(ODPacket& is); + virtual void pickup(); virtual void setPosition(const Ogre::Vector3& v); static const char* getFormat(); static TreasuryObject* getTreasuryObjectFromStream(GameMap* gameMap, std::istream& is); - static TreasuryObject* getTreasuryObjectFromPacket(GameMap* gameMap, ODPacket& packet); - friend ODPacket& operator<<(ODPacket& os, TreasuryObject* obj); - friend ODPacket& operator>>(ODPacket& os, TreasuryObject* obj); - friend std::ostream& operator<<(std::ostream& os, TreasuryObject* obj); + static TreasuryObject* getTreasuryObjectFromPacket(GameMap* gameMap, ODPacket& is); private: int mGoldValue; };