Mercurial
comparison color_game/main.c @ 63:fff1b048dda6
[Postdog] Fixed a problem where string did not wrap.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Tue, 23 Dec 2025 14:00:37 -0800 |
| parents | 9df5587cf23b |
| children | 35b1abc37969 |
comparison
equal
deleted
inserted
replaced
| 62:ea9ef388ab97 | 63:fff1b048dda6 |
|---|---|
| 7 | 7 |
| 8 #define INIT_SCREEN_WIDTH 1200 | 8 #define INIT_SCREEN_WIDTH 1200 |
| 9 #define INIT_SCREEN_HEIGHT 700 | 9 #define INIT_SCREEN_HEIGHT 700 |
| 10 #define PLAYER_SPEED 200.0f | 10 #define PLAYER_SPEED 200.0f |
| 11 #define PLAYER_RADIUS 20.0f | 11 #define PLAYER_RADIUS 20.0f |
| 12 #define PLAYER_MAX_HEALTH 100.0f | |
| 13 | |
| 12 #define MONSTER_SPEED 100.0f | 14 #define MONSTER_SPEED 100.0f |
| 13 #define MONSTER_RADIUS 15.0f | 15 #define MONSTER_RADIUS 15.0f |
| 16 | |
| 14 #define BULLET_SPEED 300.0f | 17 #define BULLET_SPEED 300.0f |
| 15 #define BULLET_RADIUS 5.0f | 18 #define BULLET_RADIUS 5.0f |
| 16 #define BULLET_LIFETIME 3.0f | 19 #define BULLET_LIFETIME 3.0f |
| 17 #define SHOOT_INTERVAL 0.5f | 20 #define SHOOT_INTERVAL 0.5f |
| 18 #define HIT_PROBABILITY 0.7f // 70% aim accuracy (0.0 = random, 1.0 = perfect) | 21 #define HIT_PROBABILITY 0.7f // 70% aim accuracy (0.0 = random, 1.0 = perfect) |
| 22 | |
| 19 #define MAX_PASSIVE_NODES 12 | 23 #define MAX_PASSIVE_NODES 12 |
| 20 #define PASSIVE_TREE_RADIUS 250.0f | 24 #define PASSIVE_TREE_RADIUS 250.0f |
| 21 #define PASSIVE_NODE_RADIUS 20.0f | 25 #define PASSIVE_NODE_RADIUS 20.0f |
| 26 | |
| 27 #define MONSTER_WEIGHT 10.0f | |
| 28 #define MONSTER_CONTACT_DAMAGE 5.0f | |
| 29 | |
| 22 #define BASE_DAMAGE 10.0f | 30 #define BASE_DAMAGE 10.0f |
| 23 #define PLAYER_MAX_HEALTH 100.0f | |
| 24 #define MONSTER_CONTACT_DAMAGE 5.0f | |
| 25 #define BOSS_HEALTH_MULTIPLIER 5.0f | 31 #define BOSS_HEALTH_MULTIPLIER 5.0f |
| 26 #define COLOR_UNLOCK_TIME 30.0f | 32 #define BOSS_MONSTER_WEIGHT 10.0f |
| 27 #define BOSS_SPAWN_TIME 60.0f | 33 #define BOSS_SPAWN_TIME 10.0f |
| 34 | |
| 35 #define COLOR_UNLOCK_TIME 5.0f | |
| 36 #define MAX_DAMAGE_NUMBERS 100 | |
| 37 #define DAMAGE_NUMBER_LIFETIME 1.0f | |
| 38 #define EXP_PER_MONSTER 10.0f | |
| 39 #define EXP_PER_BOSS 50.0f | |
| 40 #define EXP_TO_LEVEL 100.0f | |
| 28 | 41 |
| 29 typedef struct Player { | 42 typedef struct Player { |
| 30 Vector2 position; | 43 Vector2 position; |
| 31 Color color; | |
| 32 float health; | 44 float health; |
| 33 float maxHealth; | 45 float maxHealth; |
| 46 float invulnerabilityTimer; | |
| 34 int unlockedBulletTypes[MAX_PASSIVE_NODES]; | 47 int unlockedBulletTypes[MAX_PASSIVE_NODES]; |
| 35 int unlockedCount; | 48 int unlockedCount; |
| 36 int passivePoints; | 49 int passivePoints; |
| 37 float invulnerabilityTimer; | 50 int level; |
| 51 float experience; | |
| 52 float expToNextLevel; | |
| 53 Color color; | |
| 38 } Player; | 54 } Player; |
| 55 | |
| 56 typedef struct DamageNumber { | |
| 57 Vector2 position; | |
| 58 float damage; | |
| 59 float lifetime; | |
| 60 bool active; | |
| 61 Color color; | |
| 62 } DamageNumber; | |
| 39 | 63 |
| 40 typedef struct Map { | 64 typedef struct Map { |
| 41 float width; | 65 float width; |
| 42 float height; | 66 float height; |
| 43 } Map; | 67 } Map; |
| 46 Vector2 position; | 70 Vector2 position; |
| 47 float hue; | 71 float hue; |
| 48 float saturation; | 72 float saturation; |
| 49 float health; | 73 float health; |
| 50 float maxHealth; | 74 float maxHealth; |
| 75 float weight; | |
| 51 bool alive; | 76 bool alive; |
| 52 bool hasCollision; | 77 bool hasCollision; |
| 53 bool isBoss; | 78 bool isBoss; |
| 54 } Monster; | 79 } Monster; |
| 55 | 80 |
| 85 // Same color (0 degrees) = 0.5x damage | 110 // Same color (0 degrees) = 0.5x damage |
| 86 // Linear scale between them | 111 // Linear scale between them |
| 87 float damageMultiplier = 0.5f + (diff / 180.0f) * 1.5f; | 112 float damageMultiplier = 0.5f + (diff / 180.0f) * 1.5f; |
| 88 | 113 |
| 89 return baseDamage * damageMultiplier; | 114 return baseDamage * damageMultiplier; |
| 115 } | |
| 116 | |
| 117 void SpawnDamageNumber(DamageNumber* damageNumbers, int maxCount, Vector2 position, float damage, Color color) | |
| 118 { | |
| 119 for (int i = 0; i < maxCount; i++) | |
| 120 { | |
| 121 if (!damageNumbers[i].active) | |
| 122 { | |
| 123 damageNumbers[i].position = position; | |
| 124 damageNumbers[i].damage = damage; | |
| 125 damageNumbers[i].lifetime = DAMAGE_NUMBER_LIFETIME; | |
| 126 damageNumbers[i].active = true; | |
| 127 damageNumbers[i].color = color; | |
| 128 break; | |
| 129 } | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 void UpdateDamageNumbers(DamageNumber* damageNumbers, int count, float deltaTime) | |
| 134 { | |
| 135 for (int i = 0; i < count; i++) | |
| 136 { | |
| 137 if (!damageNumbers[i].active) continue; | |
| 138 | |
| 139 damageNumbers[i].lifetime -= deltaTime; | |
| 140 damageNumbers[i].position.y -= 30.0f * deltaTime; // Float upward | |
| 141 | |
| 142 if (damageNumbers[i].lifetime <= 0) | |
| 143 { | |
| 144 damageNumbers[i].active = false; | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 void AddExperience(Player* player, float exp) | |
| 150 { | |
| 151 player->experience += exp; | |
| 152 | |
| 153 // Check for level up | |
| 154 while (player->experience >= player->expToNextLevel) | |
| 155 { | |
| 156 player->experience -= player->expToNextLevel; | |
| 157 player->level++; | |
| 158 player->passivePoints++; | |
| 159 // Increase exp requirement for next level | |
| 160 player->expToNextLevel = EXP_TO_LEVEL * player->level; | |
| 161 } | |
| 90 } | 162 } |
| 91 | 163 |
| 92 void InitializePassiveTree(PassiveNode* nodes) | 164 void InitializePassiveTree(PassiveNode* nodes) |
| 93 { | 165 { |
| 94 const char* nodeDescriptions[MAX_PASSIVE_NODES] = { | 166 const char* nodeDescriptions[MAX_PASSIVE_NODES] = { |
| 173 }; | 245 }; |
| 174 | 246 |
| 175 // Check collision with other monsters if this monster has collision enabled | 247 // Check collision with other monsters if this monster has collision enabled |
| 176 if (monsters[i].hasCollision) | 248 if (monsters[i].hasCollision) |
| 177 { | 249 { |
| 178 bool collision = false; | 250 bool canMove = true; |
| 179 for (int j = 0; j < monsterCount; j++) | 251 for (int j = 0; j < monsterCount; j++) |
| 180 { | 252 { |
| 181 if (i == j || !monsters[j].alive || !monsters[j].hasCollision) continue; | 253 if (i == j || !monsters[j].alive || !monsters[j].hasCollision) continue; |
| 182 | 254 |
| 183 float dx = newPos.x - monsters[j].position.x; | 255 float dx = newPos.x - monsters[j].position.x; |
| 184 float dy = newPos.y - monsters[j].position.y; | 256 float dy = newPos.y - monsters[j].position.y; |
| 185 float distance = sqrtf(dx * dx + dy * dy); | 257 float distance = sqrtf(dx * dx + dy * dy); |
| 186 | 258 |
| 187 if (distance < MONSTER_RADIUS * 2) | 259 if (distance < MONSTER_RADIUS * 2) |
| 188 { | 260 { |
| 189 collision = true; | 261 // If this monster is heavier, push the other monster away |
| 190 break; | 262 if (monsters[i].weight > monsters[j].weight) |
| 263 { | |
| 264 // Calculate push direction (away from current monster) | |
| 265 Vector2 pushDir = {dx, dy}; | |
| 266 float pushLength = sqrtf(pushDir.x * pushDir.x + pushDir.y * pushDir.y); | |
| 267 if (pushLength > 0) | |
| 268 { | |
| 269 pushDir.x /= pushLength; | |
| 270 pushDir.y /= pushLength; | |
| 271 } | |
| 272 | |
| 273 // Push the lighter monster away | |
| 274 float pushForce = (monsters[i].weight - monsters[j].weight) * MONSTER_SPEED * deltaTime * 0.5f; | |
| 275 monsters[j].position.x += pushDir.x * pushForce; | |
| 276 monsters[j].position.y += pushDir.y * pushForce; | |
| 277 } | |
| 278 else | |
| 279 { | |
| 280 // This monster is lighter or equal weight, can't move through | |
| 281 canMove = false; | |
| 282 break; | |
| 283 } | |
| 191 } | 284 } |
| 192 } | 285 } |
| 193 | 286 |
| 194 if (!collision) | 287 if (canMove) |
| 195 { | 288 { |
| 196 monsters[i].position = newPos; | 289 monsters[i].position = newPos; |
| 197 } | 290 } |
| 198 } | 291 } |
| 199 else | 292 else |
| 246 bullets[i].active = false; | 339 bullets[i].active = false; |
| 247 } | 340 } |
| 248 } | 341 } |
| 249 } | 342 } |
| 250 | 343 |
| 251 int CheckCollisions(Bullet* bullets, int bulletCount, Monster* monsters, int monsterCount, Player* player) | 344 int CheckCollisions(Bullet* bullets, int bulletCount, Monster* monsters, int monsterCount, Player* player, DamageNumber* damageNumbers) |
| 252 { | 345 { |
| 253 int bossesKilled = 0; | 346 int bossesKilled = 0; |
| 254 | 347 |
| 255 for (int i = 0; i < bulletCount; i++) | 348 for (int i = 0; i < bulletCount; i++) |
| 256 { | 349 { |
| 269 { | 362 { |
| 270 // Calculate damage based on color difference | 363 // Calculate damage based on color difference |
| 271 float damage = CalculateColorDamage(bullets[i].hue, monsters[j].hue, bullets[i].damage); | 364 float damage = CalculateColorDamage(bullets[i].hue, monsters[j].hue, bullets[i].damage); |
| 272 monsters[j].health -= damage; | 365 monsters[j].health -= damage; |
| 273 | 366 |
| 367 // Spawn damage number | |
| 368 Color damageColor = damage > bullets[i].damage * 1.5f ? ORANGE : WHITE; | |
| 369 SpawnDamageNumber(damageNumbers, MAX_DAMAGE_NUMBERS, monsters[j].position, damage, damageColor); | |
| 370 | |
| 274 // Check if monster died | 371 // Check if monster died |
| 275 if (monsters[j].health <= 0) | 372 if (monsters[j].health <= 0) |
| 276 { | 373 { |
| 277 monsters[j].alive = false; | 374 monsters[j].alive = false; |
| 278 | 375 |
| 376 // Award experience | |
| 377 float expGain = monsters[j].isBoss ? EXP_PER_BOSS : EXP_PER_MONSTER; | |
| 378 AddExperience(player, expGain); | |
| 379 | |
| 279 // Award passive point if boss was killed | 380 // Award passive point if boss was killed |
| 280 if (monsters[j].isBoss) | 381 if (monsters[j].isBoss) |
| 281 { | 382 { |
| 282 player->passivePoints++; | 383 player->passivePoints++; |
| 283 bossesKilled++; | 384 bossesKilled++; |
| 311 { | 412 { |
| 312 minDistance = distance; | 413 minDistance = distance; |
| 313 nearestPos = monsters[i].position; | 414 nearestPos = monsters[i].position; |
| 314 found = true; | 415 found = true; |
| 315 } | 416 } |
| 417 | |
| 418 if (found) | |
| 419 break; | |
| 316 } | 420 } |
| 317 | 421 |
| 318 if (!found) | 422 if (!found) |
| 319 { | 423 { |
| 320 // No monsters, return random direction | 424 // No monsters, return random direction |
| 338 Map map = { | 442 Map map = { |
| 339 .width = INIT_SCREEN_WIDTH * 3, | 443 .width = INIT_SCREEN_WIDTH * 3, |
| 340 .height = INIT_SCREEN_HEIGHT * 3 | 444 .height = INIT_SCREEN_HEIGHT * 3 |
| 341 }; | 445 }; |
| 342 | 446 |
| 343 // Initialize player at map center | |
| 344 Player player = { | 447 Player player = { |
| 345 .position = {map.width / 2, map.height / 2}, | 448 .position = {map.width / 2, map.height / 2}, |
| 346 .color = BLUE, | 449 .color = BLUE, |
| 347 .health = PLAYER_MAX_HEALTH, | 450 .health = PLAYER_MAX_HEALTH, |
| 348 .maxHealth = PLAYER_MAX_HEALTH, | 451 .maxHealth = PLAYER_MAX_HEALTH, |
| 349 .unlockedCount = 0, | 452 .unlockedCount = 0, |
| 350 .passivePoints = 0, | 453 .passivePoints = 3, |
| 351 .invulnerabilityTimer = 0.0f | 454 .invulnerabilityTimer = 0.0f, |
| 455 .level = 1, | |
| 456 .experience = 0.0f, | |
| 457 .expToNextLevel = EXP_TO_LEVEL | |
| 352 }; | 458 }; |
| 353 | 459 |
| 354 // Initialize passive tree | |
| 355 PassiveNode passiveTree[MAX_PASSIVE_NODES]; | 460 PassiveNode passiveTree[MAX_PASSIVE_NODES]; |
| 356 InitializePassiveTree(passiveTree); | 461 InitializePassiveTree(passiveTree); |
| 357 | |
| 358 // Unlock first node only (grayscale bullet to start) | |
| 359 passiveTree[0].unlocked = true; | 462 passiveTree[0].unlocked = true; |
| 360 player.unlockedBulletTypes[player.unlockedCount++] = 0; | 463 player.unlockedBulletTypes[player.unlockedCount++] = 0; |
| 361 | 464 |
| 362 // Initialize camera | 465 // Initialize damage numbers array |
| 466 DamageNumber damageNumbers[MAX_DAMAGE_NUMBERS]; | |
| 467 for (int i = 0; i < MAX_DAMAGE_NUMBERS; i++) | |
| 468 { | |
| 469 damageNumbers[i].active = false; | |
| 470 } | |
| 471 | |
| 363 Camera2D camera = {0}; | 472 Camera2D camera = {0}; |
| 364 camera.target = player.position; | 473 camera.target = player.position; |
| 365 camera.offset = (Vector2){INIT_SCREEN_WIDTH / 2.0f, INIT_SCREEN_HEIGHT / 2.0f}; | 474 camera.offset = (Vector2){INIT_SCREEN_WIDTH / 2.0f, INIT_SCREEN_HEIGHT / 2.0f}; |
| 366 camera.rotation = 0.0f; | 475 camera.rotation = 0.0f; |
| 367 camera.zoom = 1.0f; | 476 camera.zoom = 1.0f; |
| 372 Vector2 menuCenter = { | 481 Vector2 menuCenter = { |
| 373 .x = INIT_SCREEN_WIDTH / 2, | 482 .x = INIT_SCREEN_WIDTH / 2, |
| 374 .y = INIT_SCREEN_HEIGHT / 2 | 483 .y = INIT_SCREEN_HEIGHT / 2 |
| 375 }; | 484 }; |
| 376 | 485 |
| 377 // Game progression variables | |
| 378 float gameTime = 0.0f; | 486 float gameTime = 0.0f; |
| 379 float currentMonsterHue = 0.0f; | 487 float currentMonsterHue = 0.0f; |
| 380 float currentMonsterSaturation = 0.0f; // Start grayscale | 488 float currentMonsterSaturation = 0.0f; // Start grayscale |
| 381 int bossesDefeated = 0; | 489 int bossesDefeated = 0; |
| 382 float nextBossTime = BOSS_SPAWN_TIME; | 490 float nextBossTime = BOSS_SPAWN_TIME; |
| 383 bool colorUnlocked = false; | 491 bool colorUnlocked = false; |
| 384 | 492 |
| 385 // Initialize monsters array | 493 // Initialize monsters array |
| 386 #define MAX_MONSTERS 100 | 494 #define MAX_MONSTERS 1000 |
| 387 Monster live_monsters[MAX_MONSTERS]; | 495 Monster live_monsters[MAX_MONSTERS]; |
| 388 int monsterCount = 0; | 496 int monsterCount = 0; |
| 389 | 497 |
| 390 // Spawn initial monsters (grayscale) | 498 // Spawn initial monsters (grayscale) |
| 391 for (int i = 0; i < 10; i++) | 499 for (int i = 0; i < 30; i++) |
| 392 { | 500 { |
| 393 live_monsters[monsterCount++] = (Monster){ | 501 live_monsters[monsterCount++] = (Monster){ |
| 394 .position = {RandomFloat(0, map.width), RandomFloat(0, map.height)}, | 502 .position = {RandomFloat(0, map.width), RandomFloat(0, map.height)}, |
| 395 .hue = currentMonsterHue, | 503 .hue = currentMonsterHue, |
| 396 .saturation = currentMonsterSaturation, | 504 .saturation = currentMonsterSaturation, |
| 505 .weight = MONSTER_WEIGHT, | |
| 397 .health = 50.0f, | 506 .health = 50.0f, |
| 398 .maxHealth = 50.0f, | 507 .maxHealth = 50.0f, |
| 399 .alive = true, | 508 .alive = true, |
| 400 .hasCollision = true, | 509 .hasCollision = true, |
| 401 .isBoss = false | 510 .isBoss = false |
| 486 .position = {RandomFloat(0, map.width), RandomFloat(0, map.height)}, | 595 .position = {RandomFloat(0, map.width), RandomFloat(0, map.height)}, |
| 487 .hue = currentMonsterHue, | 596 .hue = currentMonsterHue, |
| 488 .saturation = currentMonsterSaturation, | 597 .saturation = currentMonsterSaturation, |
| 489 .health = 50.0f * BOSS_HEALTH_MULTIPLIER, | 598 .health = 50.0f * BOSS_HEALTH_MULTIPLIER, |
| 490 .maxHealth = 50.0f * BOSS_HEALTH_MULTIPLIER, | 599 .maxHealth = 50.0f * BOSS_HEALTH_MULTIPLIER, |
| 600 .weight = BOSS_MONSTER_WEIGHT, | |
| 491 .alive = true, | 601 .alive = true, |
| 492 .hasCollision = true, | 602 .hasCollision = true, |
| 493 .isBoss = true | 603 .isBoss = true |
| 494 }; | 604 }; |
| 495 } | 605 } |
| 578 UpdateMonsters(live_monsters, monsterCount, player.position, deltaTime); | 688 UpdateMonsters(live_monsters, monsterCount, player.position, deltaTime); |
| 579 | 689 |
| 580 // Update bullets | 690 // Update bullets |
| 581 UpdateBullets(bullets, MAX_BULLETS, deltaTime); | 691 UpdateBullets(bullets, MAX_BULLETS, deltaTime); |
| 582 | 692 |
| 693 // Update damage numbers | |
| 694 UpdateDamageNumbers(damageNumbers, MAX_DAMAGE_NUMBERS, deltaTime); | |
| 695 | |
| 583 // Check collisions | 696 // Check collisions |
| 584 int bossKills = CheckCollisions(bullets, MAX_BULLETS, live_monsters, monsterCount, &player); | 697 int bossKills = CheckCollisions(bullets, MAX_BULLETS, live_monsters, monsterCount, &player, damageNumbers); |
| 585 bossesDefeated += bossKills; | 698 bossesDefeated += bossKills; |
| 586 | 699 |
| 587 // Update camera to follow player | 700 // Update camera to follow player |
| 588 camera.target = player.position; | 701 camera.target = player.position; |
| 589 | 702 |
| 726 Color bulletColor = ColorFromHSV(bullets[i].hue, 1.0f, 1.0f); | 839 Color bulletColor = ColorFromHSV(bullets[i].hue, 1.0f, 1.0f); |
| 727 DrawCircleV(bullets[i].position, BULLET_RADIUS, bulletColor); | 840 DrawCircleV(bullets[i].position, BULLET_RADIUS, bulletColor); |
| 728 } | 841 } |
| 729 } | 842 } |
| 730 | 843 |
| 844 // Draw damage numbers | |
| 845 for (int i = 0; i < MAX_DAMAGE_NUMBERS; i++) | |
| 846 { | |
| 847 if (damageNumbers[i].active) | |
| 848 { | |
| 849 printf("True\n"); | |
| 850 float alpha = damageNumbers[i].lifetime / DAMAGE_NUMBER_LIFETIME; | |
| 851 Color color = damageNumbers[i].color; | |
| 852 color.a = (unsigned char)(255 * alpha); | |
| 853 DrawText(TextFormat("%.0f", damageNumbers[i].damage), | |
| 854 damageNumbers[i].position.x - 10, | |
| 855 damageNumbers[i].position.y, | |
| 856 20, | |
| 857 color); | |
| 858 } | |
| 859 } | |
| 860 | |
| 731 // Draw player (flash when invulnerable) | 861 // Draw player (flash when invulnerable) |
| 732 if (player.invulnerabilityTimer <= 0 || ((int)(player.invulnerabilityTimer * 10) % 2 == 0)) | 862 if (player.invulnerabilityTimer <= 0 || ((int)(player.invulnerabilityTimer * 10) % 2 == 0)) |
| 733 { | 863 { |
| 734 DrawCircleV(player.position, PLAYER_RADIUS, player.color); | 864 DrawCircleV(player.position, PLAYER_RADIUS, player.color); |
| 735 } | 865 } |
| 746 float healthPercent = player.health / player.maxHealth; | 876 float healthPercent = player.health / player.maxHealth; |
| 747 DrawRectangle(10, 10, 200, 20, DARKGRAY); | 877 DrawRectangle(10, 10, 200, 20, DARKGRAY); |
| 748 DrawRectangle(10, 10, 200 * healthPercent, 20, RED); | 878 DrawRectangle(10, 10, 200 * healthPercent, 20, RED); |
| 749 DrawText(TextFormat("HP: %.0f/%.0f", player.health, player.maxHealth), 15, 12, 16, WHITE); | 879 DrawText(TextFormat("HP: %.0f/%.0f", player.health, player.maxHealth), 15, 12, 16, WHITE); |
| 750 | 880 |
| 881 // Experience bar | |
| 882 float expPercent = player.experience / player.expToNextLevel; | |
| 883 DrawRectangle(10, 35, 200, 15, DARKGRAY); | |
| 884 DrawRectangle(10, 35, 200 * expPercent, 15, SKYBLUE); | |
| 885 DrawText(TextFormat("Lvl %d", player.level), 15, 36, 12, WHITE); | |
| 886 DrawText(TextFormat("%.0f/%.0f XP", player.experience, player.expToNextLevel), 70, 36, 12, WHITE); | |
| 887 | |
| 751 // Passive points | 888 // Passive points |
| 752 DrawText(TextFormat("Passive Points: %d", player.passivePoints), 10, 40, 20, PURPLE); | 889 DrawText(TextFormat("Passive Points: %d", player.passivePoints), 10, 55, 18, PURPLE); |
| 753 | 890 |
| 754 // Controls | 891 // Controls |
| 755 DrawText("WASD: Move | P: Menu | R: Toggle Colors", 10, 70, 16, DARKGRAY); | 892 DrawText("WASD: Move | P: Menu | R: Toggle Colors", 10, 80, 16, DARKGRAY); |
| 756 | 893 |
| 757 // Count alive monsters and bosses | 894 // Count alive monsters and bosses |
| 758 int aliveCount = 0; | 895 int aliveCount = 0; |
| 759 int bossCount = 0; | 896 int bossCount = 0; |
| 760 for (int i = 0; i < monsterCount; i++) | 897 for (int i = 0; i < monsterCount; i++) |
| 763 { | 900 { |
| 764 aliveCount++; | 901 aliveCount++; |
| 765 if (live_monsters[i].isBoss) bossCount++; | 902 if (live_monsters[i].isBoss) bossCount++; |
| 766 } | 903 } |
| 767 } | 904 } |
| 768 DrawText(TextFormat("Monsters: %d | Bosses: %d", aliveCount, bossCount), 10, 95, 18, DARKGRAY); | 905 DrawText(TextFormat("Monsters: %d | Bosses: %d", aliveCount, bossCount), 10, 105, 18, DARKGRAY); |
| 769 DrawText(TextFormat("Unlocked bullets: %d/%d", player.unlockedCount, MAX_PASSIVE_NODES), 10, 120, 16, DARKGRAY); | 906 DrawText(TextFormat("Unlocked bullets: %d/%d", player.unlockedCount, MAX_PASSIVE_NODES), 10, 130, 16, DARKGRAY); |
| 770 DrawText(TextFormat("Bosses defeated: %d", bossesDefeated), 10, 145, 16, DARKGRAY); | 907 DrawText(TextFormat("Bosses defeated: %d", bossesDefeated), 10, 155, 16, DARKGRAY); |
| 771 } | 908 } |
| 772 | 909 |
| 773 EndDrawing(); | 910 EndDrawing(); |
| 774 } | 911 } |
| 775 return 0; | 912 return 0; |