Id: | To index | |
Original: | Legend | |
Status: | ||
Mutant: | Show |
Testcases to display
Filter by kind
Filter by status
1: # include "mobsystem.h" |
2: |
3: # include "game.h" |
4: # include "rendersystem.h" |
5: |
6: # include < string > |
7: using namespace std :: string_literals ; |
8: |
9: MobInfo MI ( MobCategory category , std :: string name , int32_t health , int32_t speed ) { |
10: MobInfo mi ; |
11: mi . category = category ; |
12: mi . name = name ; |
13: mi . health = health ; |
14: mi . speed = speed ; |
15: return mi ; |
16: } |
17: |
18: MobInfo MI ( MobCategory category , std :: string name , int32_t health , int32_t speed , |
19: int32_t strength ) { |
20: MobInfo mi ; |
21: mi . category = category ; |
22: mi . name = name ; |
23: mi . health = health ; |
24: mi . speed = speed ; |
25: mi . attacks = true ; |
26: mi . strength = strength ; |
27: return mi ; |
28: } |
29: |
30: const std :: unordered_map < MobType , MobInfo > MobDatabase { |
31: { MobType :: Unknown , MI ( MobCategory :: Unknown , "Unknown"s , 0 , 1 ) } , |
32: { MobType :: Rabbit , MI ( MobCategory :: Rabbit , "Rabbit"s , 1 , 7 ) } , |
33: { MobType :: RabbitWere , MI ( MobCategory :: Rabbit , "Were-Rabbit"s , 1 , 6 , 1 ) } , |
34: { MobType :: Snake , MI ( MobCategory :: Snake , "Snake"s , 1 , 5 ) } , |
35: { MobType :: OrcWeak , MI ( MobCategory :: Orc , "Little Orc"s , 5 , 3 , 3 ) } , |
36: { MobType :: OrcStrong , MI ( MobCategory :: Orc , "Big Orc"s , 6 , 2 , 5 ) } , |
37: { MobType :: Player , MI ( MobCategory :: Player , "Player"s , 5 , 6 , 3 ) } , |
38: } ; |
39: |
40: void MobSystem :: update ( ) { |
41: for ( auto & mob : game_ . mobs . values ( ) ) { |
42: if ( mob . info -> category == MobCategory :: Player ) |
43: continue ; |
44: |
45: mob . tick += mob . info -> speed ; |
46: mob . tick = std :: min ( mob . tick , 2 * Mob :: TicksPerAction - 1 ) ; |
47: if ( mob . tick >= Mob :: TicksPerAction ) { |
48: auto & e = game_ . entities [ mob . entity ] ; |
49: updateMob ( e , mob ) ; |
50: mob . tick -= Mob :: TicksPerAction ; |
51: } |
52: } |
53: } |
54: |
55: void MobSystem :: handleEvent ( const EvAny & any ) { |
56: if ( any . is < EvTryWalk > ( ) ) { |
57: const auto & ev = any . get < EvTryWalk > ( ) ; |
58: auto & mob = game_ . mobs [ ev . mob ] ; |
59: auto & info = * mob . info ; |
60: |
61: // check position is clear |
62: bool blocked = false ; |
63: for ( auto & other : game_ . mobs . values ( ) ) { |
64: if other . id != mob . id other . position == ev . to ) { |
65: blocked = true ; |
66: break ; |
67: } |
68: } |
69: |
70: if ( ! game_ . worldBounds . contains ( ev . to ) ) { |
71: blocked = true ; |
72: } |
73: |
74: if ( ! blocked ) { |
75: mob . position = ev . to ; |
76: |
77: // Mob overrides sprite position |
78: auto & sprite = game_ . sprites [ game_ . entities [ mob . entity ] . sprite ] ; |
79: sprite . position = mob . position ; |
80: |
81: // Additional pieces |
82: switch ( info . category ) { |
83: default : |
84: break ; |
85: case MobCategory :: Snake : { |
86: if ( randInt ( 0 , 3 ) < 3 ) { |
87: game_ . groundTile ( mob . position ) = '_' ; |
88: } |
89: |
90: game_ . sprites [ mob . extraSprite ] . position = mob . position + mob . dir ; |
91: break ; |
92: } |
93: case MobCategory :: Orc : { |
94: if ( randInt ( 0 , 1 ) == 0 ) { |
95: // smash ground |
96: game_ . groundTile ( mob . position ) = '_' ; |
97: } |
98: game_ . sprites [ mob . extraSprite ] . position = mob . position + vec2i { - 1 , 1 } ; |
99: game_ . sprites [ mob . extraSprite2 ] . position = mob . position + vec2i { 1 , 1 } ; |
100: break ; |
101: } |
102: } |
103: |
104: game_ . queueEvent ( EvWalked { mob . id , ev . from , mob . position } ) ; |
105: } |
106: } else if ( any . is < EvWalked > ( ) ) { |
107: // ... |
108: } else if ( any . is < EvAttack > ( ) ) { |
109: const auto & ev = any . get < EvAttack > ( ) ; |
110: auto & mob = game_ . mobs [ ev . mob ] ; |
111: auto & mobInfo = * mob . info ; |
112: auto & targetMob = game_ . mobs [ ev . target ] ; |
113: // auto& targetMobInfo = *targetMob.info; |
114: |
115: if mob targetMob ) { |
116: targetMob . health -= mobInfo . strength ; |
117: if ( targetMob . health <= 0 ) { |
118: game_ . queueEvent ( EvKillMob { targetMob . id } ) ; |
119: } else { |
120: // Flash-hit |
121: const int flashDuration = 2 ; |
122: auto & e = game_ . entities [ targetMob . entity ] ; |
123: game_ . sprites [ e . sprite ] . flashTimer = flashDuration ; |
124: if ( targetMob . extraSprite ) |
125: game_ . sprites [ targetMob . extraSprite ] . flashTimer = flashDuration ; |
126: if ( targetMob . extraSprite2 ) |
127: game_ . sprites [ targetMob . extraSprite2 ] . flashTimer = flashDuration ; |
128: } |
129: } |
130: } |
131: } |
132: |
133: void MobSystem :: updateMob ( Entity & e , Mob & mob ) { |
134: auto & info = * mob . info ; |
135: auto & sprite = game_ . sprites [ e . sprite ] ; |
136: vec2i pos = mob . position ; |
137: |
138: const int margin = 6 ; // min distance from edge mobs prefer to be |
139: auto dirToNearestEdge = [ & ] ( vec2i pos ) -> vec2i { |
140: const auto & b = game_ . worldBounds ; |
141: |
142: if ( pos . y > b . top - margin ) |
143: return { 0 , - 1 } ; |
144: else if ( pos . y < b . top - b . height + margin ) |
145: return { 0 , 1 } ; |
146: else if ( pos . x < b . left + margin ) |
147: return { 1 , 0 } ; |
148: else if ( pos . x > b . left + b . width - margin ) |
149: return { - 1 , 0 } ; |
150: return { 0 , 0 } ; |
151: } ; |
152: |
153: switch ( info . category ) { |
154: case MobCategory :: Rabbit : { |
155: if ( randInt ( 0 , 500 ) == 0 ) { |
156: // Too many rabbits! |
157: // game_.queueEvent(EvSpawnMob { MobType::Rabbit, pos }); |
158: } else { |
159: // Move randomly |
160: vec2i dir = dirToNearestEdge ( pos ) ; |
161: if ( dir == vec2i { 0 , 0 } ) { |
162: dir = vec2i { randInt ( - 1 , 1 ) , randInt ( - 1 , 1 ) } ; |
163: } |
164: game_ . queueEvent ( EvTryWalk { mob . id , pos , pos + dir } ) ; |
165: } |
166: break ; |
167: } |
168: case MobCategory :: Snake : { |
169: if ( randInt ( 0 , 6 ) == 0 ) { |
170: if ( mob . dir . x != 0 ) { |
171: mob . dir = choose < vec2i > ( { { 0 , 1 } , { 0 , - 1 } } ) ; |
172: } else { |
173: mob . dir = choose < vec2i > ( { { 1 , 0 } , { - 1 , 0 } } ) ; |
174: } |
175: |
176: vec2i dir = dirToNearestEdge ( pos ) ; |
177: if ( dir != vec2i { 0 , 0 } ) |
178: mob . dir = dir ; |
179: } else { |
180: if ( mob . dir . y == 1 ) |
181: sprite . frame = 0 ; |
182: else if ( mob . dir . y == - 1 ) |
183: sprite . frame = 1 ; |
184: else if ( mob . dir . x == 1 ) |
185: sprite . frame = 2 ; |
186: else if ( mob . dir . x == - 1 ) |
187: sprite . frame = 3 ; |
188: |
189: game_ . queueEvent ( EvTryWalk { mob . id , pos , pos + mob . dir } ) ; |
190: } |
191: break ; |
192: } |
193: case MobCategory :: Orc : { |
194: if ( randInt ( 0 , 2 ) == 0 ) { |
195: game_ . groundTile ( pos ) = choose ( { '_' , '_' } ) ; |
196: } |
197: |
198: vec2i dir = dirToNearestEdge ( pos ) ; |
199: if ( dir == vec2i { 0 , 0 } ) { |
200: if ( randInt ( 0 , 3 ) == 0 ) { |
201: // stay here |
202: } else { |
203: // move randomly |
204: int32_t move = choose ( { - 1 , 1 } ) ; |
205: dir = choose ( { vec2i { move , 0 } , vec2i { 0 , move } } ) ; |
206: } |
207: } |
208: |
209: if ( dir != vec2i { 0 , 0 } ) { |
210: game_ . queueEvent ( EvTryWalk { mob . id , pos , pos + dir } ) ; |
211: } |
212: break ; |
213: } |
214: default : |
215: break ; |
216: } |
217: } |