diff options
| author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-05-17 15:55:37 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-05-17 15:55:37 -0400 |
| commit | 90aadf3844386824140a20d7fbb847bc16009a94 (patch) | |
| tree | 6f83fce90e71abb22b1a8f3e09c79963b2a34d5d /src/systems/realizing.cpp | |
| parent | bc63fa57ced1c7329f7fdcfd168eaf7e290158bc (diff) | |
| parent | 86f0106d0523825549f1e74b835688c78a10cf6c (diff) | |
| download | therapy-90aadf3844386824140a20d7fbb847bc16009a94.tar.gz therapy-90aadf3844386824140a20d7fbb847bc16009a94.tar.bz2 therapy-90aadf3844386824140a20d7fbb847bc16009a94.zip | |
Merge pull request #7 from hatkirby/es-rewrite
The ECS rewrite exceeds the original branch in functionality, so it is time to merge it in.
Diffstat (limited to 'src/systems/realizing.cpp')
| -rw-r--r-- | src/systems/realizing.cpp | 438 |
1 files changed, 438 insertions, 0 deletions
| diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp new file mode 100644 index 0000000..baacf5a --- /dev/null +++ b/src/systems/realizing.cpp | |||
| @@ -0,0 +1,438 @@ | |||
| 1 | #include "realizing.h" | ||
| 2 | #include <stdexcept> | ||
| 3 | #include <libxml/parser.h> | ||
| 4 | #include <cstring> | ||
| 5 | #include <map> | ||
| 6 | #include "game.h" | ||
| 7 | #include "consts.h" | ||
| 8 | #include "animation.h" | ||
| 9 | #include "components/mappable.h" | ||
| 10 | #include "components/animatable.h" | ||
| 11 | #include "components/playable.h" | ||
| 12 | #include "components/ponderable.h" | ||
| 13 | #include "components/transformable.h" | ||
| 14 | #include "components/prototypable.h" | ||
| 15 | #include "components/automatable.h" | ||
| 16 | #include "systems/mapping.h" | ||
| 17 | #include "systems/animating.h" | ||
| 18 | #include "systems/pondering.h" | ||
| 19 | #include "systems/scripting.h" | ||
| 20 | |||
| 21 | inline xmlChar* getProp(xmlNodePtr node, const char* attr) | ||
| 22 | { | ||
| 23 | xmlChar* key = xmlGetProp(node, reinterpret_cast<const xmlChar*>(attr)); | ||
| 24 | if (key == nullptr) | ||
| 25 | { | ||
| 26 | throw std::invalid_argument("Error parsing world file"); | ||
| 27 | } | ||
| 28 | |||
| 29 | return key; | ||
| 30 | } | ||
| 31 | |||
| 32 | // TODO: neither the XML doc nor any of the emplaced entities are properly | ||
| 33 | // destroyed if this constructor throws an exception. | ||
| 34 | RealizingSystem::RealizingSystem( | ||
| 35 | Game& game, | ||
| 36 | std::string worldFile, | ||
| 37 | std::string prototypeFile) : | ||
| 38 | System(game), | ||
| 39 | worldFile_(std::move(worldFile)), | ||
| 40 | prototypeFile_(std::move(prototypeFile)) | ||
| 41 | { | ||
| 42 | auto& mapping = game_.getSystemManager().getSystem<MappingSystem>(); | ||
| 43 | |||
| 44 | xmlChar* key = nullptr; | ||
| 45 | |||
| 46 | // Create a mapping between prototype names and the XML trees defining them. | ||
| 47 | xmlDocPtr protoXml = xmlParseFile(prototypeFile_.c_str()); | ||
| 48 | if (protoXml == nullptr) | ||
| 49 | { | ||
| 50 | throw std::invalid_argument("Cannot find prototypes file"); | ||
| 51 | } | ||
| 52 | |||
| 53 | xmlNodePtr protoTop = xmlDocGetRootElement(protoXml); | ||
| 54 | if (protoTop == nullptr) | ||
| 55 | { | ||
| 56 | throw std::invalid_argument("Error parsing prototypes file"); | ||
| 57 | } | ||
| 58 | |||
| 59 | if (xmlStrcmp(protoTop->name, reinterpret_cast<const xmlChar*>("entities"))) | ||
| 60 | { | ||
| 61 | throw std::invalid_argument("Error parsing prototypes file"); | ||
| 62 | } | ||
| 63 | |||
| 64 | std::map<std::string, xmlNodePtr> prototypes; | ||
| 65 | |||
| 66 | for (xmlNodePtr node = protoTop->xmlChildrenNode; | ||
| 67 | node != nullptr; | ||
| 68 | node = node->next) | ||
| 69 | { | ||
| 70 | if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("entity"))) | ||
| 71 | { | ||
| 72 | key = getProp(node, "id"); | ||
| 73 | std::string prototypeId = reinterpret_cast<char*>(key); | ||
| 74 | xmlFree(key); | ||
| 75 | |||
| 76 | prototypes[prototypeId] = node; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | // Create entities from the world definition. | ||
| 81 | xmlDocPtr doc = xmlParseFile(worldFile_.c_str()); | ||
| 82 | if (doc == nullptr) | ||
| 83 | { | ||
| 84 | throw std::invalid_argument("Cannot find world file"); | ||
| 85 | } | ||
| 86 | |||
| 87 | xmlNodePtr top = xmlDocGetRootElement(doc); | ||
| 88 | if (top == nullptr) | ||
| 89 | { | ||
| 90 | throw std::invalid_argument("Error parsing world file"); | ||
| 91 | } | ||
| 92 | |||
| 93 | if (xmlStrcmp(top->name, reinterpret_cast<const xmlChar*>("world"))) | ||
| 94 | { | ||
| 95 | throw std::invalid_argument("Error parsing world file"); | ||
| 96 | } | ||
| 97 | |||
| 98 | key = getProp(top, "startx"); | ||
| 99 | startingPos_.x() = atoi(reinterpret_cast<char*>(key)); | ||
| 100 | xmlFree(key); | ||
| 101 | |||
| 102 | key = getProp(top, "starty"); | ||
| 103 | startingPos_.y() = atoi(reinterpret_cast<char*>(key)); | ||
| 104 | xmlFree(key); | ||
| 105 | |||
| 106 | key = getProp(top, "startmap"); | ||
| 107 | startingMapId_ = atoi(reinterpret_cast<char*>(key)); | ||
| 108 | xmlFree(key); | ||
| 109 | |||
| 110 | for (xmlNodePtr node = top->xmlChildrenNode; | ||
| 111 | node != nullptr; | ||
| 112 | node = node->next) | ||
| 113 | { | ||
| 114 | if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar*>("map"))) | ||
| 115 | { | ||
| 116 | id_type map = game_.getEntityManager().emplaceEntity(); | ||
| 117 | |||
| 118 | auto& mappable = game_.getEntityManager(). | ||
| 119 | emplaceComponent<MappableComponent>(map, | ||
| 120 | Texture("res/tiles.png"), | ||
| 121 | Texture("res/font.bmp")); | ||
| 122 | |||
| 123 | key = getProp(node, "id"); | ||
| 124 | mappable.mapId = atoi(reinterpret_cast<char*>(key)); | ||
| 125 | xmlFree(key); | ||
| 126 | |||
| 127 | key = getProp(node, "title"); | ||
| 128 | mappable.title = reinterpret_cast<char*>(key); | ||
| 129 | xmlFree(key); | ||
| 130 | |||
| 131 | for (xmlNodePtr mapNode = node->xmlChildrenNode; | ||
| 132 | mapNode != nullptr; | ||
| 133 | mapNode = mapNode->next) | ||
| 134 | { | ||
| 135 | if (!xmlStrcmp( | ||
| 136 | mapNode->name, | ||
| 137 | reinterpret_cast<const xmlChar*>("environment"))) | ||
| 138 | { | ||
| 139 | key = xmlNodeGetContent(mapNode); | ||
| 140 | if (key == nullptr) | ||
| 141 | { | ||
| 142 | throw std::invalid_argument("Error parsing world file"); | ||
| 143 | } | ||
| 144 | |||
| 145 | mappable.tiles.clear(); | ||
| 146 | mappable.tiles.push_back(atoi(strtok( | ||
| 147 | reinterpret_cast<char*>(key), | ||
| 148 | ",\n"))); | ||
| 149 | |||
| 150 | for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++) | ||
| 151 | { | ||
| 152 | mappable.tiles.push_back(atoi(strtok(nullptr, ",\n"))); | ||
| 153 | } | ||
| 154 | |||
| 155 | xmlFree(key); | ||
| 156 | } else if (!xmlStrcmp( | ||
| 157 | mapNode->name, | ||
| 158 | reinterpret_cast<const xmlChar*>("entity"))) | ||
| 159 | { | ||
| 160 | id_type mapObject = game_.getEntityManager().emplaceEntity(); | ||
| 161 | |||
| 162 | key = getProp(mapNode, "type"); | ||
| 163 | std::string prototypeId = reinterpret_cast<char*>(key); | ||
| 164 | xmlFree(key); | ||
| 165 | |||
| 166 | xmlNodePtr prototypeNode = prototypes[prototypeId]; | ||
| 167 | |||
| 168 | // Set the coordinates from the object definition. | ||
| 169 | auto& transformable = game_.getEntityManager(). | ||
| 170 | emplaceComponent<TransformableComponent>(mapObject); | ||
| 171 | |||
| 172 | key = getProp(mapNode, "x"); | ||
| 173 | transformable.origPos.x() = atoi(reinterpret_cast<char*>(key)); | ||
| 174 | xmlFree(key); | ||
| 175 | |||
| 176 | key = getProp(mapNode, "y"); | ||
| 177 | transformable.origPos.y() = atoi(reinterpret_cast<char*>(key)); | ||
| 178 | xmlFree(key); | ||
| 179 | |||
| 180 | // Set the sprite and size using the prototype definition. | ||
| 181 | key = getProp(prototypeNode, "sprite"); | ||
| 182 | std::string spritePath = reinterpret_cast<char*>(key); | ||
| 183 | xmlFree(key); | ||
| 184 | |||
| 185 | key = getProp(prototypeNode, "width"); | ||
| 186 | transformable.origSize.w() = atoi(reinterpret_cast<char*>(key)); | ||
| 187 | xmlFree(key); | ||
| 188 | |||
| 189 | key = getProp(prototypeNode, "height"); | ||
| 190 | transformable.origSize.h() = atoi(reinterpret_cast<char*>(key)); | ||
| 191 | xmlFree(key); | ||
| 192 | |||
| 193 | AnimationSet objectAnim( | ||
| 194 | spritePath.c_str(), | ||
| 195 | transformable.origSize.w(), | ||
| 196 | transformable.origSize.h(), | ||
| 197 | 1); | ||
| 198 | |||
| 199 | objectAnim.emplaceAnimation("static", 0, 1, 1); | ||
| 200 | |||
| 201 | auto& animatable = game_.getEntityManager(). | ||
| 202 | emplaceComponent<AnimatableComponent>( | ||
| 203 | mapObject, | ||
| 204 | std::move(objectAnim)); | ||
| 205 | |||
| 206 | animatable.origAnimation = "static"; | ||
| 207 | |||
| 208 | // Create a physics body. | ||
| 209 | game_.getSystemManager().getSystem<PonderingSystem>(). | ||
| 210 | initializeBody(mapObject, PonderableComponent::Type::vacuumed); | ||
| 211 | |||
| 212 | |||
| 213 | |||
| 214 | |||
| 215 | |||
| 216 | auto& prototypable = game_.getEntityManager(). | ||
| 217 | emplaceComponent<PrototypableComponent>(mapObject); | ||
| 218 | |||
| 219 | prototypable.prototypeId = prototypeId; | ||
| 220 | |||
| 221 | key = getProp(mapNode, "index"); | ||
| 222 | prototypable.mapObjectIndex = atoi(reinterpret_cast<char*>(key)); | ||
| 223 | xmlFree(key); | ||
| 224 | |||
| 225 | if (prototypeId == "movplat") | ||
| 226 | { | ||
| 227 | auto& automatable = game_.getEntityManager(). | ||
| 228 | emplaceComponent<AutomatableComponent>(mapObject); | ||
| 229 | |||
| 230 | automatable.table = prototypeId; | ||
| 231 | } else if (prototypeId == "checkpoint") | ||
| 232 | { | ||
| 233 | auto& ponderable = game_.getEntityManager(). | ||
| 234 | getComponent<PonderableComponent>(mapObject); | ||
| 235 | |||
| 236 | ponderable.colliderType = PonderableComponent::Collision::event; | ||
| 237 | } | ||
| 238 | |||
| 239 | mappable.objects.push_back(mapObject); | ||
| 240 | } else if (!xmlStrcmp( | ||
| 241 | mapNode->name, | ||
| 242 | reinterpret_cast<const xmlChar*>("adjacent"))) | ||
| 243 | { | ||
| 244 | key = getProp(mapNode, "type"); | ||
| 245 | std::string adjTypeStr(reinterpret_cast<char*>(key)); | ||
| 246 | xmlFree(key); | ||
| 247 | |||
| 248 | MappableComponent::Adjacent::Type adjType; | ||
| 249 | if (adjTypeStr == "wall") | ||
| 250 | { | ||
| 251 | adjType = MappableComponent::Adjacent::Type::wall; | ||
| 252 | } else if (adjTypeStr == "wrap") | ||
| 253 | { | ||
| 254 | adjType = MappableComponent::Adjacent::Type::wrap; | ||
| 255 | } else if (adjTypeStr == "warp") | ||
| 256 | { | ||
| 257 | adjType = MappableComponent::Adjacent::Type::warp; | ||
| 258 | } else if (adjTypeStr == "reverseWarp") | ||
| 259 | { | ||
| 260 | adjType = MappableComponent::Adjacent::Type::reverse; | ||
| 261 | } else { | ||
| 262 | throw std::logic_error("Invalid adjacency type"); | ||
| 263 | } | ||
| 264 | |||
| 265 | key = getProp(mapNode, "map"); | ||
| 266 | size_t adjMapId = atoi(reinterpret_cast<char*>(key)); | ||
| 267 | xmlFree(key); | ||
| 268 | |||
| 269 | key = getProp(mapNode, "dir"); | ||
| 270 | std::string adjDir(reinterpret_cast<char*>(key)); | ||
| 271 | xmlFree(key); | ||
| 272 | |||
| 273 | if (adjDir == "left") | ||
| 274 | { | ||
| 275 | mappable.leftAdjacent = {adjType, adjMapId}; | ||
| 276 | } else if (adjDir == "right") | ||
| 277 | { | ||
| 278 | mappable.rightAdjacent = {adjType, adjMapId}; | ||
| 279 | } else if (adjDir == "up") | ||
| 280 | { | ||
| 281 | mappable.upAdjacent = {adjType, adjMapId}; | ||
| 282 | } else if (adjDir == "down") | ||
| 283 | { | ||
| 284 | mappable.downAdjacent = {adjType, adjMapId}; | ||
| 285 | } else { | ||
| 286 | throw std::logic_error("Invalid adjacency direction"); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | mapping.generateBoundaries(map); | ||
| 292 | |||
| 293 | entityByMapId_[mappable.mapId] = map; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | xmlFreeDoc(doc); | ||
| 298 | xmlFreeDoc(protoXml); | ||
| 299 | |||
| 300 | activateMap(entityByMapId_[startingMapId_]); | ||
| 301 | } | ||
| 302 | |||
| 303 | void RealizingSystem::loadMap(id_type mapEntity) | ||
| 304 | { | ||
| 305 | deactivateMap(); | ||
| 306 | activateMap(mapEntity); | ||
| 307 | } | ||
| 308 | |||
| 309 | void RealizingSystem::deactivateMap() | ||
| 310 | { | ||
| 311 | id_type oldMap = activeMap_; | ||
| 312 | |||
| 313 | auto& oldMappable = game_.getEntityManager(). | ||
| 314 | getComponent<MappableComponent>(oldMap); | ||
| 315 | |||
| 316 | // Deactivate any map objects from the old map. | ||
| 317 | for (id_type prototype : oldMappable.objects) | ||
| 318 | { | ||
| 319 | leaveActiveMap(prototype); | ||
| 320 | } | ||
| 321 | |||
| 322 | // Deactivate players that were on the old map. | ||
| 323 | std::set<id_type> players = | ||
| 324 | game_.getEntityManager().getEntitiesWithComponents< | ||
| 325 | PlayableComponent>(); | ||
| 326 | |||
| 327 | for (id_type player : players) | ||
| 328 | { | ||
| 329 | auto& playable = game_.getEntityManager(). | ||
| 330 | getComponent<PlayableComponent>(player); | ||
| 331 | |||
| 332 | if (playable.mapId == oldMap) | ||
| 333 | { | ||
| 334 | leaveActiveMap(player); | ||
| 335 | } | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | void RealizingSystem::activateMap(id_type mapEntity) | ||
| 340 | { | ||
| 341 | auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>(); | ||
| 342 | auto& pondering = game_.getSystemManager().getSystem<PonderingSystem>(); | ||
| 343 | |||
| 344 | std::set<id_type> players = | ||
| 345 | game_.getEntityManager().getEntitiesWithComponents< | ||
| 346 | PlayableComponent>(); | ||
| 347 | |||
| 348 | activeMap_ = mapEntity; | ||
| 349 | |||
| 350 | auto& mappable = game_.getEntityManager(). | ||
| 351 | getComponent<MappableComponent>(mapEntity); | ||
| 352 | |||
| 353 | // Initialize the new map's objects. | ||
| 354 | for (id_type prototype : mappable.objects) | ||
| 355 | { | ||
| 356 | if (game_.getEntityManager(). | ||
| 357 | hasComponent<TransformableComponent>(prototype)) | ||
| 358 | { | ||
| 359 | auto& transformable = game_.getEntityManager(). | ||
| 360 | getComponent<TransformableComponent>(prototype); | ||
| 361 | |||
| 362 | transformable.pos = transformable.origPos; | ||
| 363 | transformable.size = transformable.origSize; | ||
| 364 | } | ||
| 365 | |||
| 366 | if (game_.getEntityManager().hasComponent<AnimatableComponent>(prototype)) | ||
| 367 | { | ||
| 368 | animating.initPrototype(prototype); | ||
| 369 | } | ||
| 370 | |||
| 371 | if (game_.getEntityManager().hasComponent<PonderableComponent>(prototype)) | ||
| 372 | { | ||
| 373 | pondering.initPrototype(prototype); | ||
| 374 | } | ||
| 375 | |||
| 376 | enterActiveMap(prototype); | ||
| 377 | } | ||
| 378 | |||
| 379 | // Activate any players on the map. | ||
| 380 | for (id_type player : players) | ||
| 381 | { | ||
| 382 | auto& playable = game_.getEntityManager(). | ||
| 383 | getComponent<PlayableComponent>(player); | ||
| 384 | |||
| 385 | if (playable.mapId == mapEntity) | ||
| 386 | { | ||
| 387 | enterActiveMap(player); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | void RealizingSystem::enterActiveMap(id_type entity) | ||
| 393 | { | ||
| 394 | if (game_.getEntityManager().hasComponent<AnimatableComponent>(entity)) | ||
| 395 | { | ||
| 396 | auto& animatable = game_.getEntityManager(). | ||
| 397 | getComponent<AnimatableComponent>(entity); | ||
| 398 | |||
| 399 | animatable.active = true; | ||
| 400 | } | ||
| 401 | |||
| 402 | if (game_.getEntityManager().hasComponent<PonderableComponent>(entity)) | ||
| 403 | { | ||
| 404 | auto& ponderable = game_.getEntityManager(). | ||
| 405 | getComponent<PonderableComponent>(entity); | ||
| 406 | |||
| 407 | ponderable.active = true; | ||
| 408 | } | ||
| 409 | |||
| 410 | if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity)) | ||
| 411 | { | ||
| 412 | game_.getSystemManager().getSystem<ScriptingSystem>().startBehavior(entity); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | void RealizingSystem::leaveActiveMap(id_type entity) | ||
| 417 | { | ||
| 418 | if (game_.getEntityManager().hasComponent<AnimatableComponent>(entity)) | ||
| 419 | { | ||
| 420 | auto& animatable = game_.getEntityManager(). | ||
| 421 | getComponent<AnimatableComponent>(entity); | ||
| 422 | |||
| 423 | animatable.active = false; | ||
| 424 | } | ||
| 425 | |||
| 426 | if (game_.getEntityManager().hasComponent<PonderableComponent>(entity)) | ||
| 427 | { | ||
| 428 | auto& ponderable = game_.getEntityManager(). | ||
| 429 | getComponent<PonderableComponent>(entity); | ||
| 430 | |||
| 431 | ponderable.active = false; | ||
| 432 | } | ||
| 433 | |||
| 434 | if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity)) | ||
| 435 | { | ||
| 436 | game_.getSystemManager().getSystem<ScriptingSystem>().stopBehavior(entity); | ||
| 437 | } | ||
| 438 | } | ||
