#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" // TODO: centralize these outside of game.c struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet; struct SpriteBounds bounds; struct BMPImage spritesheetImage; struct VGAColor vgaColors[256]; struct MouseStatus mouseStatus; struct RabbitPosition rabbitPosition = { .rabbitPosition = { 60, 60 }, .rabbitLimits = { { 20, 20 }, { 180, 180 } }, .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 SpawnPointRange { int left, width; int top, height; }; struct SpawnPointRange spawnPointRanges[4] = { { .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = TILE_SIZE, .height = TILE_SIZE }, { .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = (ARENA_HEIGHT_TILES - 2) * TILE_SIZE, .height = TILE_SIZE }, { .left = TILE_SIZE, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, { .left = (ARENA_WIDTH_TILES - 2) * TILE_SIZE, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, }; void setupRabbitBullets() { int i; for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { rabbitBulletPosition[i].isActive = 0; rabbitBulletPosition[i].willBeInactive = 0; } rabbitWeaponry.cooldown = 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; } } int spawnCooldown = 0; int difficulty = 0; int kills = 0; int difficultyBands[10] = { 10, 20, 30, 50, 80, 130, 210, 340, 550, 890 }; void handleEnemyKills() { int i, hadKill; for (i = 0; i < ENEMY_MAX_COUNT; ++i) { if (enemyPosition[i].wasKilled) { enemyPosition[i].wasKilled = 0; kills++; hadKill = 1; } } if (hadKill) { for (i = 0; i < 10; ++i) { if (kills > difficultyBands[i]) { difficulty = i + 1; } } } } void maybeSpawnEnemy() { char canSpawn; int i, availableEnemy; int spawnX, spawnY; if (spawnCooldown-- > 0) return; for (i = 0; i < ENEMY_MAX_COUNT; ++i) { if (!enemyPosition[i].isActive) { availableEnemy = i; canSpawn = 1; break; } } if (!canSpawn) return; i = rand() % 4; spawnX = spawnPointRanges[i].left + rand() % spawnPointRanges[i].width; spawnY = spawnPointRanges[i].top + rand() % spawnPointRanges[i].height; enemyPosition[availableEnemy].isActive = 1; enemyPosition[availableEnemy].willBeInactive = 0; enemyPosition[availableEnemy].wasKilled = 0; enemyPosition[availableEnemy].enemyMoveDelayStep = 0; enemyPosition[availableEnemy].enemyFireDelayStep = ENEMY_FIRE_MIN_DELAY + rand() % ENEMY_FIRE_VARIABLE_DELAY; enemyPosition[availableEnemy].enemyPosition[0] = spawnX; enemyPosition[availableEnemy].enemyPosition[1] = spawnY; enemyPosition[availableEnemy].oldEnemyPosition[0] = spawnX; enemyPosition[availableEnemy].oldEnemyPosition[1] = spawnY; spawnCooldown = (BASE_ENEMY_SPAWN_COOLDOWN - difficulty) + MINIMUM_ENEMY_SPAWN_COOLDOWN + rand() % VARIABLE_ENEMY_SPAWN_COOLDOWN; } 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 renderMouse() { mouse.x = rabbitPosition.mousePosition[0]; mouse.y = rabbitPosition.mousePosition[1]; drawCompiledSprite(&mouse); drawPixel(rabbitPosition.mouseDotPosition[0], rabbitPosition.mouseDotPosition[1], 2); } 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 drawOnlyMouseArena() { mouse.x = rabbitPosition.oldMousePosition[0]; mouse.y = rabbitPosition.oldMousePosition[1]; getSpriteBounds(&mouse, &bounds); drawOnlyArena(&bounds); bounds.top = rabbitPosition.oldMouseDotPosition[1]; bounds.bottom = rabbitPosition.oldMouseDotPosition[1]; bounds.left = rabbitPosition.oldMouseDotPosition[0]; bounds.right = rabbitPosition.oldMouseDotPosition[0]; drawOnlyArena(&bounds); } void drawOnlyRabbitArena() { rabbit.x = rabbitPosition.oldRabbitPosition[0]; rabbit.y = rabbitPosition.oldRabbitPosition[1]; getSpriteBounds(&rabbit, &bounds); drawOnlyArena(&bounds); } 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]; getSpriteBounds(&enemy, &bounds); drawOnlyArena(&bounds); 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; getSpriteBounds(&bullet, &bounds); drawOnlyArena(&bounds); 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; getSpriteBounds(&enemyBullet, &bounds); drawOnlyArena(&bounds); if (enemyBulletPosition[i].willBeInactive) { enemyBulletPosition[i].isActive = 0; } } } int setupGame() { FILE *fh; installKeyboardHandler(); initializeDrawBuffer(); fh = fopen("sprtsht.bmp", "rb"); if (readBMPIntoNewMemory(fh, &spritesheetImage)) return 1; fclose(fh); spritesheetImage.transparentColor = 0; setupWallSprites(); setupRabbitSprites(); setupRabbitBullets(); setupEnemySprites(); setVideoMode(VIDEO_MODE_VGA_256); bmp256ColorPaletteToVGAColorPalette(&spritesheetImage, vgaColors); setVGAColors(vgaColors, 256); activateMouse(&mouseStatus); buildArena(); clearArenaRedrawRequests(); srand(time(NULL)); return 0; } void handleMovement() { handleRabbitMovement( &rabbitPosition, &keyboardKeydownState ); handleEnemyMovement( enemyPosition, &rabbitPosition ); captureAndLimitMousePosition( &rabbitPosition, &mouseStatus ); calculateTargetAngle( &rabbitPosition, &mouseStatus ); } void handleCombat() { if (mouseStatus.leftButtonDown) { attemptToFireRabbitBullet( &rabbitPosition, &rabbitWeaponry, rabbitBulletPosition ); } attemptToFireEnemyBullets( enemyPosition, enemyBulletPosition, &rabbitPosition ); advanceRabbitBullets( rabbitBulletPosition, &rabbitWeaponry ); advanceEnemyBullets( enemyBulletPosition ); buildCollisionGrids( rabbitBulletPosition, &rabbitPosition, enemyPosition ); handleRabbitToEnemyCollisions( &rabbitPosition, enemyPosition ); handleRabbitBulletToEnemyCollisions( rabbitBulletPosition, enemyPosition ); } void handleRedraw() { drawOnlyRabbitArena(); drawOnlyEnemiesArena(); drawOnlyMouseArena(); drawOnlyRabbitBulletArena(); drawOnlyEnemyBulletArena(); redrawArena(); renderRabbit(); renderEnemies(); renderMouse(); renderRabbitBullets(); renderEnemyBullets(); } /* double speedCalcs[200]; int currentSpeedCalc = 0; double averageSpeedCalc; clock_t startTime; */ int main(void) { byte *drawBuffer; int keepRunning = 1; int i; if (setupGame()) return 1; drawBuffer = getDrawBuffer(); while (keepRunning) { readMouse(&mouseStatus); populateKeyboardKeydownState(); maybeSpawnEnemy(); handleMovement(); handleRedraw(); handleCombat(); 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; }