summary refs log tree commit diff stats
path: root/src/game.cpp
blob: 1b2cda9b5e1242cd81f43368f02d051d25df3a3f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "game.h"
#include "transform_system.h"
#include "animation_system.h"
#include "character_system.h"
#include "camera_system.h"
#include "script_system.h"

int Game::emplaceSprite(std::string alias) {
  int id;

  if (idsToReuse_.empty()) {
    id = sprites_.size();
    sprites_.emplace_back();
    sprites_.back().alias = alias;
  } else {
    id = idsToReuse_.front();
    idsToReuse_.pop_front();
    sprites_[id] = Sprite();
    sprites_[id].alias = alias;
  }

  spriteIds_.insert(id);
  spritesByAlias_[alias] = id;
  return id;
}

void Game::destroySprite(int id) {
  for (std::unique_ptr<System>& system : systems_) {
    system->destroySprite(id);
  }

  spriteIds_.erase(id);
  idsToReuse_.push_back(id);
  spritesByAlias_.erase(sprites_.at(id).alias);
}

void Game::loadMap(std::string filename) {
  // Clear out non-persistent sprites.
  std::list<int> spritesToDelete;
  for (int spriteId : spriteIds_) {
    Sprite& sprite = sprites_.at(spriteId);

    if (!sprite.persistent) {
      spritesToDelete.push_back(spriteId);
    }
  }

  for (int spriteId : spritesToDelete) {
    destroySprite(spriteId);
  }

  // Load the new map.
  map_ = std::make_unique<Map>(filename);

  std::vector<std::tuple<int, std::string>> backgroundScripts;
  for (const Prototype& p : map_->getPrototypes()) {
    if (spritesByAlias_.count(p.name)) continue;

    int spriteId = emplaceSprite(p.name);
    getSystem<TransformSystem>().initSprite(spriteId, p.pos, p.masked ? SpriteLayer::Mask : SpriteLayer::Normal);
    getSystem<TransformSystem>().setUpCollision(spriteId, p.collisionOffset, p.collisionSize, true);
    if (!p.animationFilename.empty()) {
      getSystem<AnimationSystem>().initSprite(spriteId, p.animationFilename);
      getSprite(spriteId).normallyHasShadow = p.shadow;
      if (!p.animName.empty()) {
        getSystem<AnimationSystem>().setSpriteAnimation(spriteId, p.animName);
      }
      getSystem<AnimationSystem>().setSpriteDirection(spriteId, p.dir);
    }
    getSprite(spriteId).interactionScript = p.interactionScript;
    if (p.movementSpeed != -1) {
      getSystem<CharacterSystem>().initSprite(spriteId, p.movementSpeed);
      if (p.wander) {
        getSprite(spriteId).behaviourType = BehaviourType::Wander;
      }
      if (!p.bumpPlayerScript.empty()) {
        getSprite(spriteId).bumpPlayerScript = p.bumpPlayerScript;
      }
    }
    if (!p.enclosureZone.empty()) {
      getSprite(spriteId).enclosureZone = p.enclosureZone;
    }
    if (p.mirrorType != MirrorType::None) {
      getSprite(spriteId).mirrorType = p.mirrorType;
      getSprite(spriteId).mirrorAxis = p.mirrorAxis;
      getSprite(spriteId).mirroredSpriteId = getSpriteByAlias(p.spriteToMirror);
    }
    if (!p.backgroundScript.empty()) {
      backgroundScripts.push_back({spriteId, p.backgroundScript});
    }
    getSprite(spriteId).floating = p.floating;
  }

  for (const Trigger& t : map_->getTriggers()) {
    if (spritesByAlias_.count(t.name)) continue;

    int spriteId = emplaceSprite(t.name);
    getSystem<TransformSystem>().initSprite(spriteId, t.pos);
    getSystem<TransformSystem>().setUpCollision(spriteId, {0, 0}, t.size, false);
    getSprite(spriteId).walkthroughScript = t.script;
  }

  // Run the map's init script.
  if (getSystem<ScriptSystem>().mapHasScript(map_->getName(), "init")) {
    getSystem<ScriptSystem>().runScript(map_->getName(), "init");
  }

  // Run any background scripts associated with new sprites.
  for (auto& [spriteId, scriptName] : backgroundScripts) {
    getSystem<ScriptSystem>().runScript(map_->getName(), scriptName, spriteId);
  }
}