summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/animation_system.cpp20
-rw-r--r--src/animation_system.h3
-rw-r--r--src/character_system.cpp122
-rw-r--r--src/character_system.h3
-rw-r--r--src/map.cpp22
-rw-r--r--src/map.h4
-rw-r--r--src/sprite.h10
-rw-r--r--src/transform_system.cpp31
-rw-r--r--src/transform_system.h2
9 files changed, 182 insertions, 35 deletions
diff --git a/src/animation_system.cpp b/src/animation_system.cpp index d23eae2..a280aee 100644 --- a/src/animation_system.cpp +++ b/src/animation_system.cpp
@@ -65,7 +65,7 @@ void AnimationSystem::initSprite(int spriteId, std::string_view filename) {
65 std::string animLine; 65 std::string animLine;
66 std::getline(datafile, animLine); // blank 66 std::getline(datafile, animLine); // blank
67 while (std::getline(datafile, animLine)) { 67 while (std::getline(datafile, animLine)) {
68 std::regex re(R"(([a-z!_]+)\[([a-z_]+)\]: ([0-9,]+))"); 68 std::regex re(R"(([a-z!._]+)\[([a-z_]+)\]: ([0-9,]+))");
69 std::smatch m; 69 std::smatch m;
70 std::regex_match(animLine, m, re); 70 std::regex_match(animLine, m, re);
71 71
@@ -78,6 +78,8 @@ void AnimationSystem::initSprite(int spriteId, std::string_view filename) {
78 78
79 if (animName.back() == '!') { 79 if (animName.back() == '!') {
80 anim.looping = false; 80 anim.looping = false;
81 } else if (animName.back() == '.') {
82 anim.manual = true;
81 } 83 }
82 84
83 int animId = sprite.animations.size(); 85 int animId = sprite.animations.size();
@@ -96,7 +98,7 @@ void AnimationSystem::tick(double dt) {
96 animTimer_.accumulate(dt); 98 animTimer_.accumulate(dt);
97 while (animTimer_.step()) { 99 while (animTimer_.step()) {
98 for (Sprite& sprite : game_.getSprites() | game_.spriteView()) { 100 for (Sprite& sprite : game_.getSprites() | game_.spriteView()) {
99 if (sprite.isAnimated && !sprite.animFinished) { 101 if (sprite.isAnimated && !sprite.animFinished && !sprite.animPaused) {
100 sprite.animationFrame++; 102 sprite.animationFrame++;
101 103
102 if (sprite.animationFrame >= sprite.animations[sprite.animationId].frameIndices.size()) { 104 if (sprite.animationFrame >= sprite.animations[sprite.animationId].frameIndices.size()) {
@@ -112,6 +114,19 @@ void AnimationSystem::tick(double dt) {
112 } 114 }
113} 115}
114 116
117void AnimationSystem::advanceAnimation(int spriteId) {
118 Sprite& sprite = game_.getSprite(spriteId);
119 Animation& animation = sprite.animations[sprite.animationId];
120
121 if (animation.manual) {
122 sprite.animationFrame++;
123
124 if (sprite.animationFrame >= animation.frameIndices.size()) {
125 sprite.animationFrame = 0;
126 }
127 }
128}
129
115void AnimationSystem::setSpriteDirection(int spriteId, Direction dir) { 130void AnimationSystem::setSpriteDirection(int spriteId, Direction dir) {
116 Sprite& sprite = game_.getSprite(spriteId); 131 Sprite& sprite = game_.getSprite(spriteId);
117 if (sprite.dir != dir) { 132 if (sprite.dir != dir) {
@@ -133,4 +148,5 @@ void AnimationSystem::updateAnimation(int spriteId) {
133 sprite.animationId = sprite.nameDirToAnim[sprite.animationName][sprite.dir]; 148 sprite.animationId = sprite.nameDirToAnim[sprite.animationName][sprite.dir];
134 sprite.animationFrame = 0; 149 sprite.animationFrame = 0;
135 sprite.animFinished = false; 150 sprite.animFinished = false;
151 sprite.animPaused = false;
136} 152}
diff --git a/src/animation_system.h b/src/animation_system.h index a116673..8352c19 100644 --- a/src/animation_system.h +++ b/src/animation_system.h
@@ -17,6 +17,9 @@ public:
17 17
18 void tick(double dt) override; 18 void tick(double dt) override;
19 19
20 // Advances animation by a frame. Only to be used on manual animations.
21 void advanceAnimation(int spriteId);
22
20 void initSprite(int spriteId, std::string_view filename); 23 void initSprite(int spriteId, std::string_view filename);
21 24
22 void setSpriteDirection(int spriteId, Direction dir); 25 void setSpriteDirection(int spriteId, Direction dir);
diff --git a/src/character_system.cpp b/src/character_system.cpp index 99b6929..27c2280 100644 --- a/src/character_system.cpp +++ b/src/character_system.cpp
@@ -34,7 +34,7 @@ void CharacterSystem::addSpriteToParty(int leaderId, int followerId) {
34 34
35 for (int i=0; i<truePartyDelay; i++) { 35 for (int i=0; i<truePartyDelay; i++) {
36 vec2i tween = ((follower.loc - targetPos) * i) / static_cast<double>(truePartyDelay) + targetPos; 36 vec2i tween = ((follower.loc - targetPos) * i) / static_cast<double>(truePartyDelay) + targetPos;
37 follower.trail.push_front({.pos = tween, .dir = toFace}); 37 follower.trail.push_front({.pos = tween, .dir = toFace, .medium = CharacterMedium::Normal});
38 } 38 }
39 39
40 leader.followers.push_back(followerId); 40 leader.followers.push_back(followerId);
@@ -70,14 +70,31 @@ void CharacterSystem::transplantParty(int leaderId, vec2i pos, Direction dir) {
70 70
71void CharacterSystem::moveInDirection(int spriteId, Direction dir) { 71void CharacterSystem::moveInDirection(int spriteId, Direction dir) {
72 Sprite& sprite = game_.getSprite(spriteId); 72 Sprite& sprite = game_.getSprite(spriteId);
73 sprite.movementDir = dir;
73 74
74 game_.getSystem<AnimationSystem>().setSpriteDirection(spriteId, dir); 75 switch (sprite.characterMedium) {
76 case CharacterMedium::Normal: {
77 game_.getSystem<AnimationSystem>().setSpriteDirection(spriteId, dir);
78 break;
79 }
80 case CharacterMedium::Ladder: {
81 if (dirHasDir(dir, Direction::up)) {
82 game_.getSystem<AnimationSystem>().setSpriteDirection(spriteId, Direction::up);
83 } else if (dirHasDir(dir, Direction::down)) {
84 game_.getSystem<AnimationSystem>().setSpriteDirection(spriteId, Direction::down);
85 }
86 break;
87 }
88 }
75 89
76 if (sprite.characterState == CharacterState::Still) { 90 if (sprite.characterState == CharacterState::Still) {
77 setPartyState(spriteId, CharacterState::Walking); 91 setPartyState(spriteId, CharacterState::Walking);
78 } else if (sprite.characterState == CharacterState::Crouching) { 92 } else if (sprite.characterState == CharacterState::Crouching) {
79 for (int followerId : sprite.followers) { 93 for (int followerId : sprite.followers) {
80 game_.getSystem<AnimationSystem>().setSpriteDirection(followerId, dir); 94 Sprite& follower = game_.getSprite(followerId);
95 if (follower.characterMedium == CharacterMedium::Normal) {
96 game_.getSystem<AnimationSystem>().setSpriteDirection(followerId, dir);
97 }
81 } 98 }
82 } 99 }
83} 100}
@@ -107,14 +124,18 @@ void CharacterSystem::tick(double dt) {
107 } 124 }
108 125
109 int speed = sprite.movementSpeed; 126 int speed = sprite.movementSpeed;
110 if (sprite.characterState == CharacterState::Running) { 127 if (sprite.characterState == CharacterState::Running && sprite.characterMedium == CharacterMedium::Normal) {
111 speed *= 2; 128 speed *= 2;
112 } 129 }
113 130
114 pLoc += (unitVecInDirection(sprite.dir) * speed); 131 if (sprite.characterMedium == CharacterMedium::Ladder) {
132 //game_.getSystem<AnimationSystem>().advanceAnimation(spriteId);
133 }
134
135 pLoc += (unitVecInDirection(sprite.movementDir) * speed);
115 136
116 // Check collision. 137 // Check collision.
117 CollisionResult collision = game_.getSystem<TransformSystem>().checkCollision(spriteId, pLoc, sprite.dir); 138 CollisionResult collision = game_.getSystem<TransformSystem>().checkCollision(spriteId, pLoc, sprite.movementDir);
118 bool blocked = collision.horiz.blocked || collision.vert.blocked; 139 bool blocked = collision.horiz.blocked || collision.vert.blocked;
119 140
120 if (collision.horiz.blocked && !sprite.clipping) { 141 if (collision.horiz.blocked && !sprite.clipping) {
@@ -146,6 +167,12 @@ void CharacterSystem::tick(double dt) {
146 if (pLoc != sprite.loc) { 167 if (pLoc != sprite.loc) {
147 game_.getSystem<TransformSystem>().moveSprite(spriteId, pLoc); 168 game_.getSystem<TransformSystem>().moveSprite(spriteId, pLoc);
148 169
170 CharacterMedium newMedium = game_.getSystem<TransformSystem>().getMediumAtPosition(spriteId, pLoc);
171 if (newMedium != sprite.characterMedium) {
172 sprite.characterMedium = newMedium;
173 setAnimationFor(spriteId, sprite.characterState);
174 }
175
149 if (sprite.characterState == CharacterState::Running) { 176 if (sprite.characterState == CharacterState::Running) {
150 const Map& map = game_.getMap(); 177 const Map& map = game_.getMap();
151 178
@@ -164,12 +191,20 @@ void CharacterSystem::tick(double dt) {
164 191
165 for (int followerId : sprite.followers) { 192 for (int followerId : sprite.followers) {
166 Sprite& pNext = game_.getSprite(followerId); 193 Sprite& pNext = game_.getSprite(followerId);
194 if (pNext.characterMedium == CharacterMedium::Ladder) {
195 //game_.getSystem<AnimationSystem>().advanceAnimation(followerId);
196 }
197
167 const Movement& posdir = pNext.trail.front(); 198 const Movement& posdir = pNext.trail.front();
168 game_.getSystem<TransformSystem>().moveSprite(followerId, posdir.pos); 199 game_.getSystem<TransformSystem>().moveSprite(followerId, posdir.pos);
169 game_.getSystem<AnimationSystem>().setSpriteDirection(followerId, posdir.dir); 200 game_.getSystem<AnimationSystem>().setSpriteDirection(followerId, posdir.dir);
201 if (posdir.medium != pNext.characterMedium) {
202 pNext.characterMedium = posdir.medium;
203 setAnimationFor(followerId, sprite.characterState);
204 }
170 205
171 pNext.trail.pop_front(); 206 pNext.trail.pop_front();
172 pNext.trail.push_back({.pos = pLoc, .dir = sprite.dir}); 207 pNext.trail.push_back({.pos = pLoc, .dir = sprite.dir, .medium = sprite.characterMedium});
173 } 208 }
174 } 209 }
175 } 210 }
@@ -180,6 +215,10 @@ void CharacterSystem::tick(double dt) {
180void CharacterSystem::beginCrouch(int spriteId) { 215void CharacterSystem::beginCrouch(int spriteId) {
181 Sprite& sprite = game_.getSprite(spriteId); 216 Sprite& sprite = game_.getSprite(spriteId);
182 217
218 if (sprite.characterMedium == CharacterMedium::Ladder) {
219 return;
220 }
221
183 if (sprite.characterState == CharacterState::Running) { 222 if (sprite.characterState == CharacterState::Running) {
184 stopRunning(spriteId); 223 stopRunning(spriteId);
185 } else { 224 } else {
@@ -242,32 +281,12 @@ void CharacterSystem::stopRunning(int spriteId) {
242} 281}
243 282
244void CharacterSystem::setPartyState(int spriteId, CharacterState state) { 283void CharacterSystem::setPartyState(int spriteId, CharacterState state) {
245 std::string animName;
246 switch (state) {
247 case CharacterState::Still: {
248 animName = "still";
249 break;
250 }
251 case CharacterState::Walking: {
252 animName = "walk";
253 break;
254 }
255 case CharacterState::Crouching: {
256 animName = "crouch";
257 break;
258 }
259 case CharacterState::Running: {
260 animName = "run";
261 break;
262 }
263 }
264
265 Sprite& sprite = game_.getSprite(spriteId); 284 Sprite& sprite = game_.getSprite(spriteId);
266 sprite.characterState = state; 285 sprite.characterState = state;
267 286
268 game_.getSystem<AnimationSystem>().setSpriteAnimation(spriteId, animName); 287 setAnimationFor(spriteId, state);
269 for (int followerId : sprite.followers) { 288 for (int followerId : sprite.followers) {
270 game_.getSystem<AnimationSystem>().setSpriteAnimation(followerId, animName); 289 setAnimationFor(followerId, state);
271 } 290 }
272} 291}
273 292
@@ -297,3 +316,48 @@ void CharacterSystem::destroySprite(int spriteId) {
297 stopRunningSound(sprite); 316 stopRunningSound(sprite);
298 } 317 }
299} 318}
319
320void CharacterSystem::setAnimationFor(int spriteId, CharacterState state) {
321 Sprite& sprite = game_.getSprite(spriteId);
322 std::string animName;
323
324 switch (sprite.characterMedium) {
325 case CharacterMedium::Normal: {
326 std::string animName;
327
328 switch (state) {
329 case CharacterState::Still: {
330 animName = "still";
331 break;
332 }
333 case CharacterState::Walking: {
334 animName = "walk";
335 break;
336 }
337 case CharacterState::Crouching: {
338 animName = "crouch";
339 break;
340 }
341 case CharacterState::Running: {
342 animName = "run";
343 break;
344 }
345 }
346
347 game_.getSystem<AnimationSystem>().setSpriteAnimation(spriteId, animName);
348
349 break;
350 }
351 case CharacterMedium::Ladder: {
352 game_.getSystem<AnimationSystem>().setSpriteAnimation(spriteId, "climb.");
353
354 if (state == CharacterState::Still || state == CharacterState::Crouching) {
355 sprite.animPaused = true;
356 } else {
357 sprite.animPaused = false;
358 }
359
360 break;
361 }
362 }
363}
diff --git a/src/character_system.h b/src/character_system.h index 79c1710..ef49d0e 100644 --- a/src/character_system.h +++ b/src/character_system.h
@@ -47,6 +47,9 @@ private:
47 47
48 void stopRunningSound(Sprite& sprite); 48 void stopRunningSound(Sprite& sprite);
49 49
50 // state should be the party leader's state
51 void setAnimationFor(int spriteId, CharacterState state);
52
50 Game& game_; 53 Game& game_;
51 Timer inputTimer_ {33}; 54 Timer inputTimer_ {33};
52}; 55};
diff --git a/src/map.cpp b/src/map.cpp index 4781231..0425962 100644 --- a/src/map.cpp +++ b/src/map.cpp
@@ -44,6 +44,10 @@ Map::Map(std::string_view name) : name_(name) {
44 tile.blocked = true; 44 tile.blocked = true;
45 } else if (property.getName() == "runSound") { 45 } else if (property.getName() == "runSound") {
46 tile.step = stepTypeFromString(property.getStringValue()); 46 tile.step = stepTypeFromString(property.getStringValue());
47 } else if (property.getName() == "medium") {
48 if (property.getStringValue() == "ladder") {
49 tile.medium = CharacterMedium::Ladder;
50 }
47 } 51 }
48 } 52 }
49 53
@@ -178,3 +182,21 @@ StepType Map::getStepType(int x, int y) const {
178 182
179 return StepType::none; 183 return StepType::none;
180} 184}
185
186CharacterMedium Map::getMedium(int x, int y) const {
187 CharacterMedium ret = CharacterMedium::Normal;
188
189 if (x < 0 || y < 0 || x >= mapSize_.w() || y >= mapSize_.h()) {
190 return ret;
191 }
192
193 int i = x + y * mapSize_.w();
194
195 for (const std::vector<Tile>& layer : lowerLayers_) {
196 if (layer.at(i).medium > ret) {
197 ret = layer.at(i).medium;
198 }
199 }
200
201 return ret;
202}
diff --git a/src/map.h b/src/map.h index 9467d75..1a88cc8 100644 --- a/src/map.h +++ b/src/map.h
@@ -7,6 +7,7 @@
7#include <vector> 7#include <vector>
8#include "vector.h" 8#include "vector.h"
9#include "step_type.h" 9#include "step_type.h"
10#include "sprite.h"
10 11
11struct Tile { 12struct Tile {
12 unsigned int id = 0; 13 unsigned int id = 0;
@@ -14,6 +15,7 @@ struct Tile {
14 bool flipVertical = false; 15 bool flipVertical = false;
15 bool blocked = false; 16 bool blocked = false;
16 StepType step = StepType::none; 17 StepType step = StepType::none;
18 CharacterMedium medium = CharacterMedium::Normal;
17}; 19};
18 20
19struct Prototype { 21struct Prototype {
@@ -64,6 +66,8 @@ public:
64 66
65 StepType getStepType(int x, int y) const; 67 StepType getStepType(int x, int y) const;
66 68
69 CharacterMedium getMedium(int x, int y) const;
70
67 const std::vector<Prototype>& getPrototypes() const { return prototypes_; } 71 const std::vector<Prototype>& getPrototypes() const { return prototypes_; }
68 72
69 const vec2i& getWarpPoint(const std::string& name) const { return warpPoints_.at(name); } 73 const vec2i& getWarpPoint(const std::string& name) const { return warpPoints_.at(name); }
diff --git a/src/sprite.h b/src/sprite.h index 3d2e9df..59d2caf 100644 --- a/src/sprite.h +++ b/src/sprite.h
@@ -23,6 +23,7 @@ struct SpriteFrame {
23 23
24struct Animation { 24struct Animation {
25 bool looping = true; 25 bool looping = true;
26 bool manual = false;
26 std::vector<int> frameIndices; 27 std::vector<int> frameIndices;
27}; 28};
28 29
@@ -33,9 +34,15 @@ enum class CharacterState {
33 Running 34 Running
34}; 35};
35 36
37enum class CharacterMedium {
38 Normal,
39 Ladder
40};
41
36struct Movement { 42struct Movement {
37 vec2i pos; 43 vec2i pos;
38 Direction dir; 44 Direction dir;
45 CharacterMedium medium;
39}; 46};
40 47
41class Sprite { 48class Sprite {
@@ -68,6 +75,7 @@ public:
68 std::map<std::string, std::map<Direction, int>> nameDirToAnim; 75 std::map<std::string, std::map<Direction, int>> nameDirToAnim;
69 bool animFinished = false; 76 bool animFinished = false;
70 bool hasShadow = false; 77 bool hasShadow = false;
78 bool animPaused = false;
71 79
72 // Character 80 // Character
73 bool orientable = false; 81 bool orientable = false;
@@ -75,6 +83,8 @@ public:
75 std::vector<int> followers; 83 std::vector<int> followers;
76 std::deque<Movement> trail; 84 std::deque<Movement> trail;
77 CharacterState characterState = CharacterState::Still; 85 CharacterState characterState = CharacterState::Still;
86 CharacterMedium characterMedium = CharacterMedium::Normal;
87 Direction movementDir = Direction::down;
78 StepType stepType = StepType::none; 88 StepType stepType = StepType::none;
79 int runningSfxChannel = -1; 89 int runningSfxChannel = -1;
80 bool clipping = false; 90 bool clipping = false;
diff --git a/src/transform_system.cpp b/src/transform_system.cpp index ee392f1..4056f46 100644 --- a/src/transform_system.cpp +++ b/src/transform_system.cpp
@@ -72,7 +72,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire
72 enclosureZone = &map.getZone(sprite.enclosureZone); 72 enclosureZone = &map.getZone(sprite.enclosureZone);
73 } 73 }
74 74
75 if (dirHasDir(sprite.dir, Direction::right)) { 75 if (dirHasDir(dir, Direction::right)) {
76 if (newTileDR.x() > oldTileDR.x() && 76 if (newTileDR.x() > oldTileDR.x() &&
77 newColDR.x() < mapBounds.w()) { 77 newColDR.x() < mapBounds.w()) {
78 for (int y = newTileUL.y(); y <= newTileDR.y(); y++) { 78 for (int y = newTileUL.y(); y <= newTileDR.y(); y++) {
@@ -113,7 +113,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire
113 } 113 }
114 } 114 }
115 115
116 if (dirHasDir(sprite.dir, Direction::left)) { 116 if (dirHasDir(dir, Direction::left)) {
117 if (newTileUL.x() < oldTileUL.x() && 117 if (newTileUL.x() < oldTileUL.x() &&
118 newColUL.x() >= 0) { 118 newColUL.x() >= 0) {
119 for (int y = newTileUL.y(); y <= newTileDR.y(); y++) { 119 for (int y = newTileUL.y(); y <= newTileDR.y(); y++) {
@@ -154,7 +154,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire
154 } 154 }
155 } 155 }
156 156
157 if (dirHasDir(sprite.dir, Direction::down)) { 157 if (dirHasDir(dir, Direction::down)) {
158 if (newTileDR.y() > oldTileDR.y() && 158 if (newTileDR.y() > oldTileDR.y() &&
159 newColDR.y() < mapBounds.h()) { 159 newColDR.y() < mapBounds.h()) {
160 for (int x = newTileUL.x(); x <= newTileDR.x(); x++) { 160 for (int x = newTileUL.x(); x <= newTileDR.x(); x++) {
@@ -195,7 +195,7 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire
195 } 195 }
196 } 196 }
197 197
198 if (dirHasDir(sprite.dir, Direction::up)) { 198 if (dirHasDir(dir, Direction::up)) {
199 if (newTileUL.y() < oldTileUL.y() && 199 if (newTileUL.y() < oldTileUL.y() &&
200 newColUL.y() >= 0) { 200 newColUL.y() >= 0) {
201 for (int x = newTileUL.x(); x <= newTileDR.x(); x++) { 201 for (int x = newTileUL.x(); x <= newTileDR.x(); x++) {
@@ -239,6 +239,29 @@ CollisionResult TransformSystem::checkCollision(int spriteId, vec2i newLoc, Dire
239 return result; 239 return result;
240} 240}
241 241
242CharacterMedium TransformSystem::getMediumAtPosition(int spriteId, vec2i newLoc) {
243 Sprite& sprite = game_.getSprite(spriteId);
244
245 const Map& map = game_.getMap();
246
247 vec2i newColUL = newLoc + sprite.collisionOffset;
248 vec2i newColDR = newColUL + sprite.collisionSize;
249 vec2i newTileUL = newColUL / map.getTileSize();
250 vec2i newTileDR = newColDR / map.getTileSize();
251
252 CharacterMedium result = CharacterMedium::Normal;
253 for (int y=newTileUL.y(); y<=newTileDR.y(); y++) {
254 for (int x=newTileUL.x(); x<=newTileDR.x(); x++) {
255 CharacterMedium tileMedium = map.getMedium(x, y);
256 if (tileMedium > result) {
257 result = tileMedium;
258 }
259 }
260 }
261
262 return result;
263}
264
242void TransformSystem::addCollidable(int spriteId) { 265void TransformSystem::addCollidable(int spriteId) {
243 Sprite& sprite = game_.getSprite(spriteId); 266 Sprite& sprite = game_.getSprite(spriteId);
244 267
diff --git a/src/transform_system.h b/src/transform_system.h index d894b30..a07447c 100644 --- a/src/transform_system.h +++ b/src/transform_system.h
@@ -47,6 +47,8 @@ public:
47 47
48 CollisionResult checkCollision(int spriteId, vec2i newLoc, Direction dir); 48 CollisionResult checkCollision(int spriteId, vec2i newLoc, Direction dir);
49 49
50 CharacterMedium getMediumAtPosition(int spriteId, vec2i newLoc);
51
50 void destroySprite(int spriteId) override; 52 void destroySprite(int spriteId) override;
51 53
52private: 54private: