#include #include #include #include #include #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" struct BMPImage spritesheetImage; struct VGAColor vgaColors[256]; struct SpriteRender rabbit, mouse, bullet, enemy; 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 RabbitWeaponry rabbitWeaponry; void setupRabbitBullets() { int i; for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { rabbitBulletPosition[i].isActive = 0; rabbitBulletPosition[i].willBeInactive = 0; } rabbitWeaponry.cooldown = 0; } void setupEnemies() { int i; for (i = 0; i < ENEMY_MAX_COUNT; ++i) { enemyPosition[i].isActive = 0; enemyPosition[i].willBeInactive = 0; } } void attemptToFireRabbitBullet() { char okToFire = 0, availableBullet, i; signed char doubleVelocityX, doubleVelocityY; if (rabbitWeaponry.cooldown > 0) return; for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { if (rabbitBulletPosition[i].isActive == 0) { okToFire = 1; availableBullet = i; break; } } if (!okToFire) return; rabbitWeaponry.cooldown = RABBIT_BULLET_COOLDOWN; doubleVelocityX = sin(rabbitPosition.mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2); doubleVelocityY = -cos(rabbitPosition.mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2); rabbitBulletPosition[availableBullet].isActive = 1; rabbitBulletPosition[availableBullet].willBeInactive = 0; rabbitBulletPosition[availableBullet].x = rabbitPosition.rabbitPosition[0]; rabbitBulletPosition[availableBullet].y = rabbitPosition.rabbitPosition[1] - RABBIT_BULLET_HEIGHT_START; rabbitBulletPosition[availableBullet].oldX = rabbitBulletPosition[availableBullet].x; rabbitBulletPosition[availableBullet].oldY = rabbitBulletPosition[availableBullet].y; rabbitBulletPosition[availableBullet].velocityXSteps[0] = doubleVelocityX / RABBIT_BULLET_VELOCITY; rabbitBulletPosition[availableBullet].velocityXSteps[1] = doubleVelocityX % RABBIT_BULLET_VELOCITY; rabbitBulletPosition[availableBullet].velocityYSteps[0] = doubleVelocityY / RABBIT_BULLET_VELOCITY; rabbitBulletPosition[availableBullet].velocityYSteps[1] = doubleVelocityY % RABBIT_BULLET_VELOCITY; rabbitBulletPosition[availableBullet].velocityStep = 0; } void advanceRabbitBullets() { char i; signed char velocityX, velocityY; for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { if (!rabbitBulletPosition[i].isActive) continue; rabbitBulletPosition[i].oldX = rabbitBulletPosition[i].x; rabbitBulletPosition[i].oldY = rabbitBulletPosition[i].y; rabbitBulletPosition[i].x += rabbitBulletPosition[i].velocityXSteps[rabbitBulletPosition[i].velocityStep]; rabbitBulletPosition[i].y += rabbitBulletPosition[i].velocityYSteps[rabbitBulletPosition[i].velocityStep]; if (rabbitBulletPosition[i].x < MOUSE_LIMIT_LEFT) rabbitBulletPosition[i].willBeInactive = 1; if (rabbitBulletPosition[i].x >= MOUSE_LIMIT_RIGHT) rabbitBulletPosition[i].willBeInactive = 1; if (rabbitBulletPosition[i].y < MOUSE_LIMIT_TOP) rabbitBulletPosition[i].willBeInactive = 1; if (rabbitBulletPosition[i].y >= MOUSE_LIMIT_BOTTOM) rabbitBulletPosition[i].willBeInactive = 1; rabbitBulletPosition[i].velocityStep = 1 - rabbitBulletPosition[i].velocityStep; } if (rabbitWeaponry.cooldown > 0) rabbitWeaponry.cooldown--; } void detectPlayerBulletToEnemyCollisions() { int bulletIdx, enemyIdx; for (bulletIdx = 0; bulletIdx < RABBIT_BULLET_LIMIT; ++bulletIdx) { if (!rabbitBulletPosition[bulletIdx].isActive) continue; for (enemyIdx = 0; enemyIdx < ENEMY_MAX_COUNT; ++enemyIdx) { if (!enemyPosition[enemyIdx].isActive) continue; // bullets hit enemies if: // * bulletY - bullet_height_start is within 3px of enemy base // * } } } struct SpawnPointRange { int left, width; int top, height; }; struct SpawnPointRange spawnPointRanges[1] = { { .left = 50, .width = 30, .top = 50, .height = 30 } }; void maybeSpawnEnemy() { char canSpawn; int i, availableEnemy; int spawnX, spawnY; for (i = 0; i < ENEMY_MAX_COUNT; ++i) { if (!enemyPosition[i].isActive) { availableEnemy = i; canSpawn = 1; break; } } if (!canSpawn) return; spawnX = spawnPointRanges[0].left + rand() % spawnPointRanges[0].width; spawnY = spawnPointRanges[0].top + rand() % spawnPointRanges[0].height; enemyPosition[availableEnemy].isActive = 1; enemyPosition[availableEnemy].enemyPosition[0] = spawnX; enemyPosition[availableEnemy].enemyPosition[1] = spawnY; } void setupEnemySprites() { buildSpriteFromSpritesheet( &spritesheetImage, &enemy, 0, 20, 16, 16 ); } void setupRabbitSprites() { buildSpriteFromSpritesheet( &spritesheetImage, &rabbit, 0, 20, 16, 16 ); rabbit.offsetX = 8; rabbit.offsetY = 15; buildSpriteFromSpritesheet( &spritesheetImage, &mouse, 16, 20, 8, 8 ); mouse.offsetX = 4; mouse.offsetY = 4; buildSpriteFromSpritesheet( &spritesheetImage, &bullet, 16, 28, 4, 4 ); bullet.offsetX = 1; bullet.offsetY = 1; } struct MouseStatus mouseStatus; void renderMouse() { mouse.x = rabbitPosition.mousePosition[0]; mouse.y = rabbitPosition.mousePosition[1]; drawSprite(&mouse); drawPixel(rabbitPosition.mouseDotPosition[0], rabbitPosition.mouseDotPosition[1], 2); } void renderRabbit() { rabbit.x = rabbitPosition.rabbitPosition[0]; rabbit.y = rabbitPosition.rabbitPosition[1]; drawSprite(&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]; drawSprite(&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; drawSprite(&bullet); } } struct SpriteBounds bounds; 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].willBeInactive = 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; } } } int setupGame() { FILE *fh; installKeyboardHandler(); initializeDrawBuffer(); fh = fopen("sprtsht.bmp", "rb"); if (readBMPIntoNewMemory(fh, &spritesheetImage)) return 1; fclose(fh); spritesheetImage.transparentColor = 0; setupWallSprites(&spritesheetImage); setupRabbitSprites(); setupRabbitBullets(); setupEnemySprites(); setVideoMode(VIDEO_MODE_VGA_256); bmp256ColorPaletteToVGAColorPalette(&spritesheetImage, vgaColors); setVGAColors(vgaColors, 256); activateMouse(&mouseStatus); buildArena(); clearArenaRedrawRequests(); srand(time(NULL)); return 0; } double speedCalcs[200]; int currentSpeedCalc = 0; double averageSpeedCalc; clock_t startTime; extern int doAThing(int); #pragma aux (__cdecl) doAThing "doAThing_" int main(void) { int keepRunning = 1; fprintf(stderr, "%d\n", doAThing(1000)); return 0; if (setupGame()) return 1; maybeSpawnEnemy(); while (keepRunning) { readMouse(&mouseStatus); populateKeyboardKeydownState(); handleRabbitMovement( &rabbitPosition, &keyboardKeydownState ); captureAndLimitMousePosition( &rabbitPosition, &mouseStatus ); calculateTargetAngle( &rabbitPosition, &mouseStatus ); if (mouseStatus.leftButtonDown) attemptToFireRabbitBullet(); advanceRabbitBullets(); drawOnlyRabbitArena(); drawOnlyEnemiesArena(); drawOnlyMouseArena(); drawOnlyRabbitBulletArena(); redrawArena(); renderRabbit(); renderEnemies(); renderMouse(); renderRabbitBullets(); 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; }