@@ -8,6 +8,8 @@ const towers = @import("tower.zig");
8
8
const creeps = @import ("creep.zig" );
9
9
const projectiles = @import ("projectile.zig" );
10
10
11
+ const never = a .never ;
12
+ const Values = objects .Values ;
11
13
const AABB = math .AABB ;
12
14
const GS = objects .gamestate .GameState ;
13
15
const Message = objects .message .Message ;
@@ -39,6 +41,13 @@ pub fn update(state: *GS, delta: i64) !void {
39
41
40
42
for (state .creeps .items ) | * c | {
41
43
creeps .update (c , state );
44
+
45
+ if (creeps .completed (c ) and c .alive ) {
46
+ creeps .kill (c , state );
47
+ if (getRandomTower (state , c .team )) | tid | {
48
+ towers .killById (tid , state );
49
+ }
50
+ }
42
51
}
43
52
44
53
for (state .projectile .items ) | * p | {
@@ -70,6 +79,36 @@ pub fn update(state: *GS, delta: i64) !void {
70
79
});
71
80
}
72
81
82
+ fn getRandomTower (self : * GS , team : u8 ) ? usize {
83
+ switch (team ) {
84
+ Values .TEAM_ONE = > {
85
+ if (self .oneTowerCount == 0 ) {
86
+ return null ;
87
+ }
88
+ },
89
+ Values .TEAM_TWO = > {
90
+ if (self .twoTowerCount == 0 ) {
91
+ return null ;
92
+ }
93
+ },
94
+ else = > never ("invalid team" ),
95
+ }
96
+
97
+ // TODO: Such a bad way to do this
98
+ // i am sure there is a better way...
99
+ while (true ) {
100
+ for (self .towers .items , 0.. ) | * t , idx | {
101
+ // 50% chance is not really random especially given the order...
102
+ if (t .alive and t .team == team and self .values .randBool ()) {
103
+ return idx ;
104
+ }
105
+ }
106
+ }
107
+
108
+ never ("i should select a tower" );
109
+ return null ;
110
+ }
111
+
73
112
pub fn init (self : * GS ) void {
74
113
self .fns = &.{
75
114
.placeProjectile = placeProjectile ,
@@ -96,9 +135,12 @@ pub fn init(self: *GS) void {
96
135
pub fn towerDied (self : * GS , t : * Tower ) void {
97
136
if (t .team == objects .Values .TEAM_ONE ) {
98
137
self .oneStats .towersLost += 1 ;
138
+ self .oneTowerCount -= 1 ;
99
139
} else {
100
140
self .twoStats .towersLost += 1 ;
141
+ self .twoTowerCount -= 1 ;
101
142
}
143
+
102
144
self .boardChanged += 1 ;
103
145
}
104
146
@@ -125,6 +167,11 @@ pub fn strike(self: *GS, p: *Projectile) void {
125
167
}
126
168
}
127
169
170
+ pub fn completed (self : * GS ) bool {
171
+ return ! self .noBuildZone and
172
+ (self .oneTowerCount == 0 or self .twoTowerCount == 0 );
173
+ }
174
+
128
175
pub fn roundPlayed (state : * GS ) bool {
129
176
return ! state .playing and state .round == state .one and state .round == state .two ;
130
177
}
@@ -173,9 +220,17 @@ pub fn message(state: *GS, msg: Message) !void {
173
220
a .never ("haven't programmed this yet" );
174
221
}
175
222
176
- if (try placeTower (state , aabb , c .team )) | id | {
177
- std .debug .print ("placed tower: {}\n " , .{id });
223
+ if (try placeTower (state , aabb , c .team )) | _ | {
178
224
} else {
225
+ var count : usize = 0 ;
226
+ while (creepByAABB (state , aabb )) | id | : (count += 1 ) {
227
+ creeps .kill (& state .creeps .items [id ], state );
228
+ }
229
+
230
+ if (count > 0 ) {
231
+ return ;
232
+ }
233
+
179
234
std .debug .print ("could not place tower: {s} {s}\n " , .{try aabb .string (), try c .string ()});
180
235
a .never ("haven't programmed this yet also" );
181
236
}
@@ -218,7 +273,7 @@ pub fn clone(self: *GS) !GS {
218
273
219
274
pub fn towerByAABB (self : * GS , aabb : AABB ) ? usize {
220
275
for (self .towers .items , 0.. ) | * t , i | {
221
- if (t .aabb .overlaps (aabb )) {
276
+ if (t .alive and t . aabb .overlaps (aabb )) {
222
277
return i ;
223
278
}
224
279
}
@@ -227,7 +282,7 @@ pub fn towerByAABB(self: *GS, aabb: AABB) ?usize {
227
282
228
283
pub fn creepByAABB (self : * GS , aabb : AABB ) ? usize {
229
284
for (self .creeps .items , 0.. ) | * c , i | {
230
- if (c .aabb .overlaps (aabb )) {
285
+ if (c .alive and c . aabb .overlaps (aabb )) {
231
286
return i ;
232
287
}
233
288
}
@@ -335,14 +390,15 @@ fn canPlaceTower(self: *GS, aabb: math.AABB, team: u8) bool {
335
390
}
336
391
337
392
if (creepByAABB (self , aabb )) | _ | {
338
- std .debug .print ("on creep" , .{});
339
393
return false ;
340
394
}
341
395
342
396
return true ;
343
397
}
344
398
345
399
pub fn placeTower (self : * GS , aabb : math.AABB , team : u8 ) ! ? usize {
400
+ Values .assertTeam (team );
401
+
346
402
const pos = aabb .min ;
347
403
assert (aabb .min .closeEnough (pos , 0.0001 ), "you must place towers on natural numbers" );
348
404
@@ -358,6 +414,11 @@ pub fn placeTower(self: *GS, aabb: math.AABB, team: u8) !?usize {
358
414
.tower (self .values );
359
415
360
416
try self .towers .append (t );
417
+ if (team == Values .TEAM_ONE ) {
418
+ self .oneTowerCount += 1 ;
419
+ } else {
420
+ self .twoTowerCount += 1 ;
421
+ }
361
422
362
423
updateBoard (self );
363
424
@@ -395,11 +456,35 @@ pub fn towerById(self: *GS, id: usize) *Tower {
395
456
396
457
pub fn validateState (self : * GS ) void {
397
458
for (self .creeps .items ) | * c | {
398
- if (tower (self , c .pos )) | t | {
459
+ if (! c .alive ) {
460
+ continue ;
461
+ }
462
+
463
+ if (towerByAABB (self , c .aabb )) | t | {
399
464
std .debug .print ("tower: {s} collided with creep {s}\n " , .{a .u (self .towers .items [t ].pos .string ()), a .u (c .string ())});
400
465
assert (false , "a creep is within a tower" );
401
466
}
402
467
}
468
+
469
+ var one : usize = 0 ;
470
+ var tuwu : usize = 0 ;
471
+
472
+ for (self .towers .items ) | * t | {
473
+ if (! t .alive ) {
474
+ continue ;
475
+ }
476
+
477
+ switch (t .team ) {
478
+ Values .TEAM_ONE = > one += 1 ,
479
+ Values .TEAM_TWO = > tuwu += 1 ,
480
+ else = > never ("how tf did i get here?" ),
481
+ }
482
+
483
+ }
484
+
485
+ std .debug .print ("one = {} / {} two = {} / {}\n " , .{one , self .oneTowerCount , tuwu , self .twoTowerCount });
486
+ assert (one == self .oneTowerCount , "one's tower count does not equal the alive towers" );
487
+ assert (tuwu == self .twoTowerCount , "two's tower count does not equal the alive towers" );
403
488
}
404
489
405
490
const testing = std .testing ;
0 commit comments