#include #include #include #include #include #include #include "sprites.h" #include "system/vga.h" #include "system/keyboard.h" #include "system/mouse_io.h" #include "system/pc_stuff.h" #include "bmpload.h" #include "const.h" #include "arena.h" #include "movement.h" #include "combat.h" #include "game.h" #include "spawn.h" #include "powerup.h" struct BMPImage spritesheetImage; struct VGAColor vgaColors[256]; struct MouseStatus mouseStatus; struct RabbitPosition rabbitPosition = { .rabbitPosition = { 60, 60 }, .rabbitLimits = { { 20, 20 }, { (ARENA_WIDTH_TILES - 1) * TILE_SIZE - 2, (ARENA_HEIGHT_TILES - 1) * TILE_SIZE - 2 } }, .mousePosition = { 0, 0 }, .rabbitVelocity = { 0, 0 }, .mouseDotPosition = { 0, 0 } }; struct EnemyPosition enemyPosition[ENEMY_MAX_COUNT]; struct BulletPosition rabbitBulletPosition[RABBIT_BULLET_LIMIT]; struct BulletPosition enemyBulletPosition[ENEMY_BULLET_LIMIT]; struct RabbitWeaponry rabbitWeaponry; struct PlayerPowerup playerPowerup; struct GlobalGameState globalGameState = { .spawnCooldown = 0, .difficulty = 0, .kills = 0, .coins = 0, .health = RABBIT_HEALTH_MAX, .maxHealth = RABBIT_HEALTH_MAX, .healthGainPerKill = 1, .damageUpgradeLevel = 0, .healthUpgradeLevel = 0, .healthGainUpgradeLevel = 0 }; void setupRabbitBullets() { int i; for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { rabbitBulletPosition[i].isActive = 0; rabbitBulletPosition[i].willBeInactive = 0; } rabbitWeaponry.cooldown = 0; rabbitWeaponry.currentWeapon = WEAPON_TYPE_SINGLE_SHOT_GUN; rabbitWeaponry.currentWeaponRemainingRounds = 0; rabbitWeaponry.damage = 1; } void setupPowerup() { playerPowerup.x = 100; playerPowerup.y = 100; playerPowerup.cooldown = determinePowerupCooldownTime(globalGameState.difficulty); playerPowerup.type = POWERUP_TYPE_SHOTGUN; playerPowerup.isActive = 0; } void setupEnemyBullets() { int i; for (i = 0; i < ENEMY_BULLET_LIMIT; ++i) { enemyBulletPosition[i].isActive = 0; enemyBulletPosition[i].willBeInactive = 0; } } void setupEnemies() { int i; for (i = 0; i < ENEMY_MAX_COUNT; ++i) { enemyPosition[i].isActive = 0; enemyPosition[i].willBeInactive = 0; } } void setupEnemySprites() { buildCompiledSprite( &sprite_enemy, &enemy, SPRITE_ENEMY_WIDTH, SPRITE_ENEMY_HEIGHT, SPRITE_ENEMY_OFFSET_X, SPRITE_ENEMY_OFFSET_Y ); buildCompiledSprite( &sprite_bullet, &enemyBullet, SPRITE_BULLET_WIDTH, SPRITE_BULLET_HEIGHT, SPRITE_BULLET_OFFSET_X, SPRITE_BULLET_OFFSET_Y ); } void setupRabbitSprites() { buildCompiledSprite( &sprite_rabbit, &rabbit, SPRITE_RABBIT_WIDTH, SPRITE_RABBIT_HEIGHT, SPRITE_RABBIT_OFFSET_X, SPRITE_RABBIT_OFFSET_Y ); buildCompiledSprite( &sprite_mouse, &mouse, SPRITE_MOUSE_WIDTH, SPRITE_MOUSE_HEIGHT, SPRITE_MOUSE_OFFSET_X, SPRITE_MOUSE_OFFSET_Y ); buildCompiledSprite( &sprite_bullet, &bullet, SPRITE_BULLET_WIDTH, SPRITE_BULLET_HEIGHT, SPRITE_BULLET_OFFSET_X, SPRITE_BULLET_OFFSET_Y ); } void setupPowerupSprites() { buildCompiledSprite( &sprite_shotgun, &shotgun, SPRITE_SHOTGUN_WIDTH, SPRITE_SHOTGUN_HEIGHT, SPRITE_SHOTGUN_OFFSET_X, SPRITE_SHOTGUN_OFFSET_Y ); buildCompiledSprite( &sprite_beam, &beam, SPRITE_BEAM_WIDTH, SPRITE_BEAM_HEIGHT, SPRITE_BEAM_OFFSET_X, SPRITE_BEAM_OFFSET_Y ); } void renderMouse() { mouse.x = rabbitPosition.mousePosition[0]; mouse.y = rabbitPosition.mousePosition[1]; drawCompiledSprite(&mouse); mouse.x = rabbitPosition.mouseDotPosition[0]; mouse.y = rabbitPosition.mouseDotPosition[1]; drawCompiledSprite(&mouse); } void renderRabbit() { rabbit.x = rabbitPosition.rabbitPosition[0]; rabbit.y = rabbitPosition.rabbitPosition[1]; drawCompiledSprite(&rabbit); } void renderEnemies() { int i; for (i = 0; i < ENEMY_MAX_COUNT; ++i) { if (!enemyPosition[i].isActive) continue; enemy.x = enemyPosition[i].enemyPosition[0]; enemy.y = enemyPosition[i].enemyPosition[1]; drawCompiledSprite(&enemy); } } void renderRabbitBullets() { char i; for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { if (!rabbitBulletPosition[i].isActive) continue; bullet.x = rabbitBulletPosition[i].x; bullet.y = rabbitBulletPosition[i].y; drawCompiledSprite(&bullet); } } void renderEnemyBullets() { char i; for (i = 0; i < ENEMY_BULLET_LIMIT; ++i) { if (!enemyBulletPosition[i].isActive) continue; enemyBullet.x = enemyBulletPosition[i].x; enemyBullet.y = enemyBulletPosition[i].y; drawCompiledSprite(&enemyBullet); } } void renderPowerup() { struct CompiledSpriteRender *which; if (!playerPowerup.isActive) return; switch (playerPowerup.type) { case POWERUP_TYPE_SHOTGUN: which = &shotgun; break; case POWERUP_TYPE_BEAM_WEAPON: which = &beam; break; } which->x = playerPowerup.x; which->y = playerPowerup.y; drawCompiledSprite(which); } void drawOnlyArenaForSprite(struct CompiledSpriteRender *sprite) { getSpriteBounds(sprite, &bounds); drawOnlyArena(&bounds); } void drawOnlyMouseArena() { mouse.x = rabbitPosition.oldMousePosition[0]; mouse.y = rabbitPosition.oldMousePosition[1]; drawOnlyArenaForSprite(&mouse); mouse.x = rabbitPosition.oldMouseDotPosition[0]; mouse.y = rabbitPosition.oldMouseDotPosition[1]; drawOnlyArenaForSprite(&mouse); } void drawOnlyRabbitArena() { rabbit.x = rabbitPosition.oldRabbitPosition[0]; rabbit.y = rabbitPosition.oldRabbitPosition[1]; drawOnlyArenaForSprite(&rabbit); } void drawOnlyPowerupArena() { struct CompiledSpriteRender *which; if (!playerPowerup.isActive) return; switch (playerPowerup.type) { case POWERUP_TYPE_SHOTGUN: which = &shotgun; break; case POWERUP_TYPE_BEAM_WEAPON: which = &beam; break; } which->x = playerPowerup.x; which->y = playerPowerup.y; drawOnlyArenaForSprite(which); if (playerPowerup.willBeInactive) { playerPowerup.isActive = 0; } } void drawOnlyEnemiesArena() { int i; for (i = 0; i < ENEMY_MAX_COUNT; ++i) { if (!enemyPosition[i].isActive) continue; enemy.x = enemyPosition[i].oldEnemyPosition[0]; enemy.y = enemyPosition[i].oldEnemyPosition[1]; drawOnlyArenaForSprite(&enemy); if (enemyPosition[i].willBeInactive) { enemyPosition[i].isActive = 0; } } } void drawOnlyRabbitBulletArena() { int i; for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { if (!rabbitBulletPosition[i].isActive) continue; bullet.x = rabbitBulletPosition[i].oldX; bullet.y = rabbitBulletPosition[i].oldY; drawOnlyArenaForSprite(&bullet); if (rabbitBulletPosition[i].willBeInactive) { rabbitBulletPosition[i].isActive = 0; } } } void drawOnlyEnemyBulletArena() { int i; for (i = 0; i < ENEMY_BULLET_LIMIT; ++i) { if (!enemyBulletPosition[i].isActive) continue; enemyBullet.x = enemyBulletPosition[i].oldX; enemyBullet.y = enemyBulletPosition[i].oldY; drawOnlyArenaForSprite(&enemyBullet); if (enemyBulletPosition[i].willBeInactive) { enemyBulletPosition[i].isActive = 0; } } } int setupGame() { FILE *fh; installKeyboardHandler(); initializeDrawBuffer(); buildDifficultyBands(); buildHitPointRages(); setupWallSprites(); setupRabbitSprites(); setupRabbitBullets(); setupEnemies(); setupEnemyBullets(); setupEnemySprites(); setupPowerup(); setupPowerupSprites(); setVideoMode(VIDEO_MODE_VGA_256); setVGAColors(palette, PALETTE_COLOR_COUNT); activateMouse(&mouseStatus); buildArena(); clearArenaRedrawRequests(); srand(time(NULL)); return 0; } void handleMovement() { handleRabbitMovement( &rabbitPosition, &keyboardKeydownState ); handleEnemyMovement( enemyPosition, &rabbitPosition ); captureAndLimitMousePosition( &rabbitPosition, &mouseStatus ); calculateTargetAngle( &rabbitPosition ); } void handleCombat() { int didHitRabbit; if (mouseStatus.leftButtonDown) { if (attemptToFireRabbitBullet( &rabbitPosition, &rabbitWeaponry, rabbitBulletPosition )) { fireCurrentWeaponOnce( &rabbitWeaponry ); } } attemptToFireEnemyBullets( enemyPosition, enemyBulletPosition, &rabbitPosition, globalGameState.difficulty ); advanceRabbitBullets( rabbitBulletPosition, &rabbitWeaponry ); advanceEnemyBullets( enemyBulletPosition ); buildCollisionGrids( rabbitBulletPosition, enemyBulletPosition, &rabbitPosition, enemyPosition, &playerPowerup ); didHitRabbit = handleRabbitToEnemyCollisions( &rabbitPosition, enemyPosition ); if (didHitRabbit) { globalGameState.health -= ENEMY_COLLISION_DAMAGE * didHitRabbit; } didHitRabbit = handleEnemyBulletToRabbitCollisions( enemyBulletPosition, &rabbitPosition ); if (didHitRabbit) { globalGameState.health -= ENEMY_BULLET_DAMAGE * didHitRabbit; } handleRabbitBulletToEnemyCollisions( rabbitBulletPosition, enemyPosition, &rabbitWeaponry ); if (handleRabbitToPowerupCollision(&rabbitPosition, &playerPowerup)) { playerPowerup.willBeInactive = 1; rabbitWeaponry.currentWeapon = playerPowerup.type; rabbitWeaponry.currentWeaponRemainingRounds = determineWeaponRounds(globalGameState.difficulty); } } void handleRedraw() { drawOnlyRabbitArena(); drawOnlyEnemiesArena(); drawOnlyMouseArena(); drawOnlyRabbitBulletArena(); drawOnlyEnemyBulletArena(); drawOnlyPowerupArena(); redrawArena(); renderPowerup(); renderRabbit(); renderEnemies(); renderMouse(); renderRabbitBullets(); renderEnemyBullets(); } /* double speedCalcs[200]; int currentSpeedCalc = 0; double averageSpeedCalc; clock_t startTime; */ struct PriorStats { int kills; int health; int remainingRounds; int coins; int damageUpgradeAvailable; int healthUpgradeAvailable; int healthGainUpgradeAvailable; } priorStats = { .kills = -1, .health = -1, .remainingRounds = -1, .coins = -1, .damageUpgradeAvailable = -1, .healthUpgradeAvailable = -1, .healthGainUpgradeAvailable = -1 }; struct UpgradesAvailable { char damage; char health; char healthGain; } upgradesAvailable = { .damage = 0, .health = 0, .healthGain = 0, }; void calculateUpgradesAvailable() { if (globalGameState.damageUpgradeLevel < 3) { upgradesAvailable.damage = globalGameState.coins >= damageUpgradeCosts[globalGameState.damageUpgradeLevel]; } else { upgradesAvailable.damage = 0; } if (globalGameState.healthUpgradeLevel < 3) { upgradesAvailable.health = globalGameState.coins >= healthUpgradeCosts[globalGameState.healthUpgradeLevel]; } else { upgradesAvailable.health = 0; } if (globalGameState.healthGainUpgradeLevel < 3) { upgradesAvailable.healthGain = globalGameState.coins >= healthGainUpgradeCosts[globalGameState.healthGainUpgradeLevel]; } else { upgradesAvailable.healthGain = 0; } } void redrawGameStats() { char buffer[20]; if (priorStats.kills != globalGameState.kills) { sprintf(buffer, "Hit: %d", globalGameState.kills); renderStringToDrawBuffer(buffer, 1, 0, 210, 20); priorStats.kills = globalGameState.kills; } if (priorStats.health != globalGameState.health) { sprintf(buffer, "Health: %d ", globalGameState.health); renderStringToDrawBuffer(buffer, 1, 0, 210, 30); priorStats.health = globalGameState.health; } if (priorStats.remainingRounds != rabbitWeaponry.currentWeaponRemainingRounds) { sprintf(buffer, "Rnds: %d ", rabbitWeaponry.currentWeaponRemainingRounds); renderStringToDrawBuffer(buffer, 1, 0, 210, 40); priorStats.remainingRounds = rabbitWeaponry.currentWeaponRemainingRounds; } if (priorStats.coins != globalGameState.coins) { sprintf(buffer, "Coins: %d ", globalGameState.coins); renderStringToDrawBuffer(buffer, 1, 0, 210, 50); priorStats.coins = globalGameState.coins; } if (priorStats.damageUpgradeAvailable != upgradesAvailable.damage) { if (upgradesAvailable.damage) { sprintf(buffer, "[P] Dmg up"); } else { sprintf(buffer, " "); } renderStringToDrawBuffer(buffer, 1, 0, 210, 100); priorStats.damageUpgradeAvailable = upgradesAvailable.damage; } if (priorStats.healthUpgradeAvailable != upgradesAvailable.health) { if (upgradesAvailable.health) { sprintf(buffer, "[O] Health up"); } else { sprintf(buffer, " "); } renderStringToDrawBuffer(buffer, 1, 0, 210, 110); priorStats.healthUpgradeAvailable = upgradesAvailable.health; } if (priorStats.healthGainUpgradeAvailable != upgradesAvailable.healthGain) { if (upgradesAvailable.healthGain) { sprintf(buffer, "[I] HGain up"); } else { sprintf(buffer, " "); } renderStringToDrawBuffer(buffer, 1, 0, 210, 120); priorStats.healthGainUpgradeAvailable = upgradesAvailable.healthGain; } } int main(void) { byte *drawBuffer; int keepRunning = 1; int i; char buffer[20]; if (setupGame()) return 1; drawBuffer = getDrawBuffer(); while (keepRunning) { readMouse(&mouseStatus); populateKeyboardKeydownState(); maybeSpawnEnemy( &globalGameState, enemyPosition, &rabbitPosition ); handleCombat(); handleRedraw(); handleEnemyKills( enemyPosition, &globalGameState, &playerPowerup, &rabbitWeaponry ); handleMovement(); calculateUpgradesAvailable(); redrawGameStats(); if (keyboardKeydownState.KEY_P && upgradesAvailable.damage) { globalGameState.coins -= damageUpgradeCosts[globalGameState.damageUpgradeLevel]; globalGameState.damageUpgradeLevel++; rabbitWeaponry.damage++; } if (keyboardKeydownState.KEY_O && upgradesAvailable.health) { globalGameState.coins -= healthUpgradeCosts[globalGameState.healthUpgradeLevel]; globalGameState.healthUpgradeLevel++; globalGameState.maxHealth += HEALTH_UPGRADE_GAIN; globalGameState.health = globalGameState.maxHealth; } if (keyboardKeydownState.KEY_I && upgradesAvailable.healthGain) { globalGameState.coins -= healthGainUpgradeCosts[globalGameState.healthGainUpgradeLevel]; globalGameState.healthGainUpgradeLevel++; globalGameState.healthGainPerKill++; } waitStartVbl(); copyDrawBufferToDisplay(); waitEndVbl(); if (keyboardKeydownState.KEY_ESC) { keepRunning = 0; } } freeBMP(&spritesheetImage); setVideoMode(VIDEO_MODE_80x25_TEXT); uninstallKeyboardHandler(); /* averageSpeedCalc = 0; for (currentSpeedCalc = 0; currentSpeedCalc < 200; ++currentSpeedCalc) { averageSpeedCalc += speedCalcs[currentSpeedCalc]; } averageSpeedCalc /= 200; fprintf(stderr, "average: %f\n", averageSpeedCalc); */ return 0; }