2024-02-25 17:52:42 +00:00
|
|
|
#include <stddef.h>
|
2024-02-15 13:34:50 +00:00
|
|
|
#include <stdio.h>
|
2024-02-20 11:48:12 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <conio.h>
|
2024-02-21 21:25:00 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
2024-02-15 13:34:50 +00:00
|
|
|
|
2024-02-24 12:36:18 +00:00
|
|
|
#include "sprites.h"
|
2024-02-20 13:00:13 +00:00
|
|
|
#include "system/vga.h"
|
|
|
|
#include "system/keyboard.h"
|
|
|
|
#include "system/mouse_io.h"
|
|
|
|
#include "system/pc_stuff.h"
|
2024-02-21 13:25:55 +00:00
|
|
|
|
2024-02-15 13:34:50 +00:00
|
|
|
#include "bmpload.h"
|
2024-02-20 17:51:59 +00:00
|
|
|
#include "const.h"
|
|
|
|
#include "arena.h"
|
2024-02-21 13:25:55 +00:00
|
|
|
#include "movement.h"
|
2024-02-25 13:43:30 +00:00
|
|
|
#include "combat.h"
|
|
|
|
|
|
|
|
// TODO: centralize these outside of game.c
|
|
|
|
struct CompiledSpriteRender rabbit, mouse, bullet, enemy;
|
|
|
|
struct SpriteBounds bounds;
|
2024-02-15 01:15:55 +00:00
|
|
|
|
2024-02-15 13:34:50 +00:00
|
|
|
struct BMPImage spritesheetImage;
|
|
|
|
struct VGAColor vgaColors[256];
|
|
|
|
|
2024-02-25 13:43:30 +00:00
|
|
|
struct MouseStatus mouseStatus;
|
|
|
|
|
2024-02-21 13:25:55 +00:00
|
|
|
struct RabbitPosition rabbitPosition = {
|
|
|
|
.rabbitPosition = { 60, 60 },
|
|
|
|
.rabbitLimits = { { 20, 20 }, { 180, 180 } },
|
|
|
|
.mousePosition = { 0, 0 },
|
|
|
|
.rabbitVelocity = { 0, 0 },
|
|
|
|
.mouseDotPosition = { 0, 0 }
|
|
|
|
};
|
2024-02-21 21:25:00 +00:00
|
|
|
struct EnemyPosition enemyPosition[ENEMY_MAX_COUNT];
|
2024-02-21 13:25:55 +00:00
|
|
|
struct BulletPosition rabbitBulletPosition[RABBIT_BULLET_LIMIT];
|
|
|
|
struct RabbitWeaponry rabbitWeaponry;
|
|
|
|
|
2024-02-25 13:43:30 +00:00
|
|
|
struct SpawnPointRange {
|
|
|
|
int left, width;
|
|
|
|
int top, height;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SpawnPointRange spawnPointRanges[1] = {
|
2024-02-25 17:52:42 +00:00
|
|
|
{ .left = 130, .width = 50, .top = 50, .height = 100 }
|
2024-02-25 13:43:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2024-02-21 13:25:55 +00:00
|
|
|
void setupRabbitBullets() {
|
2024-02-21 21:25:00 +00:00
|
|
|
int i;
|
2024-02-21 13:25:55 +00:00
|
|
|
|
|
|
|
for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) {
|
|
|
|
rabbitBulletPosition[i].isActive = 0;
|
|
|
|
rabbitBulletPosition[i].willBeInactive = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rabbitWeaponry.cooldown = 0;
|
|
|
|
}
|
|
|
|
|
2024-02-21 21:25:00 +00:00
|
|
|
void setupEnemies() {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ENEMY_MAX_COUNT; ++i) {
|
|
|
|
enemyPosition[i].isActive = 0;
|
|
|
|
enemyPosition[i].willBeInactive = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2024-02-25 13:43:30 +00:00
|
|
|
enemyPosition[availableEnemy].oldEnemyPosition[0] = spawnX;
|
|
|
|
enemyPosition[availableEnemy].oldEnemyPosition[1] = spawnY;
|
2024-02-21 21:25:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setupEnemySprites() {
|
2024-02-24 15:38:46 +00:00
|
|
|
buildCompiledSprite(
|
|
|
|
&sprite_enemy,
|
2024-02-21 21:25:00 +00:00
|
|
|
&enemy,
|
2024-02-24 15:38:46 +00:00
|
|
|
SPRITE_ENEMY_WIDTH,
|
|
|
|
SPRITE_ENEMY_HEIGHT,
|
|
|
|
SPRITE_ENEMY_OFFSET_X,
|
|
|
|
SPRITE_ENEMY_OFFSET_Y
|
2024-02-21 21:25:00 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-02-16 02:18:15 +00:00
|
|
|
void setupRabbitSprites() {
|
2024-02-24 15:38:46 +00:00
|
|
|
buildCompiledSprite(
|
|
|
|
&sprite_rabbit,
|
2024-02-16 02:18:15 +00:00
|
|
|
&rabbit,
|
2024-02-24 15:38:46 +00:00
|
|
|
SPRITE_RABBIT_WIDTH,
|
|
|
|
SPRITE_RABBIT_HEIGHT,
|
|
|
|
SPRITE_RABBIT_OFFSET_X,
|
|
|
|
SPRITE_RABBIT_OFFSET_Y
|
2024-02-16 02:18:15 +00:00
|
|
|
);
|
2024-02-20 11:48:12 +00:00
|
|
|
|
2024-02-24 15:38:46 +00:00
|
|
|
buildCompiledSprite(
|
|
|
|
&sprite_mouse,
|
2024-02-20 11:48:12 +00:00
|
|
|
&mouse,
|
2024-02-24 15:38:46 +00:00
|
|
|
SPRITE_MOUSE_WIDTH,
|
|
|
|
SPRITE_MOUSE_HEIGHT,
|
|
|
|
SPRITE_MOUSE_OFFSET_X,
|
|
|
|
SPRITE_MOUSE_OFFSET_Y
|
2024-02-20 11:48:12 +00:00
|
|
|
);
|
|
|
|
|
2024-02-24 15:38:46 +00:00
|
|
|
buildCompiledSprite(
|
|
|
|
&sprite_bullet,
|
2024-02-21 13:25:55 +00:00
|
|
|
&bullet,
|
2024-02-24 15:38:46 +00:00
|
|
|
SPRITE_BULLET_WIDTH,
|
|
|
|
SPRITE_BULLET_HEIGHT,
|
|
|
|
SPRITE_BULLET_OFFSET_X,
|
|
|
|
SPRITE_BULLET_OFFSET_Y
|
2024-02-21 13:25:55 +00:00
|
|
|
);
|
|
|
|
}
|
2024-02-16 02:18:15 +00:00
|
|
|
|
2024-02-20 17:39:28 +00:00
|
|
|
void renderMouse() {
|
2024-02-21 13:25:55 +00:00
|
|
|
mouse.x = rabbitPosition.mousePosition[0];
|
|
|
|
mouse.y = rabbitPosition.mousePosition[1];
|
2024-02-20 11:48:12 +00:00
|
|
|
|
2024-02-24 15:38:46 +00:00
|
|
|
drawCompiledSprite(&mouse);
|
2024-02-21 13:25:55 +00:00
|
|
|
drawPixel(rabbitPosition.mouseDotPosition[0], rabbitPosition.mouseDotPosition[1], 2);
|
2024-02-20 11:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void renderRabbit() {
|
2024-02-21 13:25:55 +00:00
|
|
|
rabbit.x = rabbitPosition.rabbitPosition[0];
|
|
|
|
rabbit.y = rabbitPosition.rabbitPosition[1];
|
2024-02-20 17:39:28 +00:00
|
|
|
|
2024-02-24 15:38:46 +00:00
|
|
|
drawCompiledSprite(&rabbit);
|
2024-02-16 02:18:15 +00:00
|
|
|
}
|
|
|
|
|
2024-02-21 21:25:00 +00:00
|
|
|
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];
|
|
|
|
|
2024-02-24 15:38:46 +00:00
|
|
|
drawCompiledSprite(&enemy);
|
2024-02-21 21:25:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-21 13:25:55 +00:00
|
|
|
void renderRabbitBullets() {
|
|
|
|
char i;
|
2024-02-16 02:18:15 +00:00
|
|
|
|
2024-02-21 13:25:55 +00:00
|
|
|
for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) {
|
|
|
|
if (!rabbitBulletPosition[i].isActive) continue;
|
2024-02-16 02:18:15 +00:00
|
|
|
|
2024-02-21 13:25:55 +00:00
|
|
|
bullet.x = rabbitBulletPosition[i].x;
|
|
|
|
bullet.y = rabbitBulletPosition[i].y;
|
2024-02-16 02:18:15 +00:00
|
|
|
|
2024-02-24 15:38:46 +00:00
|
|
|
drawCompiledSprite(&bullet);
|
2024-02-16 02:18:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-20 11:48:12 +00:00
|
|
|
void drawOnlyMouseArena() {
|
2024-02-21 13:25:55 +00:00
|
|
|
mouse.x = rabbitPosition.oldMousePosition[0];
|
|
|
|
mouse.y = rabbitPosition.oldMousePosition[1];
|
2024-02-20 11:48:12 +00:00
|
|
|
getSpriteBounds(&mouse, &bounds);
|
2024-02-20 17:51:59 +00:00
|
|
|
drawOnlyArena(&bounds);
|
2024-02-20 17:39:28 +00:00
|
|
|
|
2024-02-21 13:25:55 +00:00
|
|
|
bounds.top = rabbitPosition.oldMouseDotPosition[1];
|
|
|
|
bounds.bottom = rabbitPosition.oldMouseDotPosition[1];
|
|
|
|
bounds.left = rabbitPosition.oldMouseDotPosition[0];
|
|
|
|
bounds.right = rabbitPosition.oldMouseDotPosition[0];
|
2024-02-20 17:51:59 +00:00
|
|
|
drawOnlyArena(&bounds);
|
2024-02-20 11:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void drawOnlyRabbitArena() {
|
2024-02-21 13:25:55 +00:00
|
|
|
rabbit.x = rabbitPosition.oldRabbitPosition[0];
|
|
|
|
rabbit.y = rabbitPosition.oldRabbitPosition[1];
|
2024-02-20 11:48:12 +00:00
|
|
|
getSpriteBounds(&rabbit, &bounds);
|
2024-02-20 17:51:59 +00:00
|
|
|
drawOnlyArena(&bounds);
|
2024-02-20 11:48:12 +00:00
|
|
|
}
|
|
|
|
|
2024-02-21 21:25:00 +00:00
|
|
|
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) {
|
2024-02-25 13:43:30 +00:00
|
|
|
enemyPosition[i].isActive = 0;
|
2024-02-21 21:25:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-21 13:25:55 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-21 21:25:00 +00:00
|
|
|
int setupGame() {
|
2024-02-15 13:34:50 +00:00
|
|
|
FILE *fh;
|
2024-02-15 01:15:55 +00:00
|
|
|
|
|
|
|
installKeyboardHandler();
|
2024-02-15 13:34:50 +00:00
|
|
|
initializeDrawBuffer();
|
|
|
|
|
|
|
|
fh = fopen("sprtsht.bmp", "rb");
|
|
|
|
if (readBMPIntoNewMemory(fh, &spritesheetImage)) return 1;
|
|
|
|
fclose(fh);
|
|
|
|
|
|
|
|
spritesheetImage.transparentColor = 0;
|
|
|
|
|
2024-02-25 17:52:42 +00:00
|
|
|
setupWallSprites();
|
2024-02-16 02:18:15 +00:00
|
|
|
setupRabbitSprites();
|
2024-02-21 13:25:55 +00:00
|
|
|
setupRabbitBullets();
|
2024-02-21 21:25:00 +00:00
|
|
|
setupEnemySprites();
|
2024-02-15 13:34:50 +00:00
|
|
|
|
|
|
|
setVideoMode(VIDEO_MODE_VGA_256);
|
|
|
|
bmp256ColorPaletteToVGAColorPalette(&spritesheetImage, vgaColors);
|
|
|
|
setVGAColors(vgaColors, 256);
|
2024-02-15 01:15:55 +00:00
|
|
|
|
2024-02-20 11:48:12 +00:00
|
|
|
activateMouse(&mouseStatus);
|
|
|
|
|
2024-02-16 02:18:15 +00:00
|
|
|
buildArena();
|
2024-02-21 13:25:55 +00:00
|
|
|
clearArenaRedrawRequests();
|
2024-02-15 13:34:50 +00:00
|
|
|
|
2024-02-21 21:25:00 +00:00
|
|
|
srand(time(NULL));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-02-25 13:43:30 +00:00
|
|
|
void handleMovement() {
|
|
|
|
handleRabbitMovement(
|
|
|
|
&rabbitPosition,
|
|
|
|
&keyboardKeydownState
|
|
|
|
);
|
|
|
|
captureAndLimitMousePosition(
|
|
|
|
&rabbitPosition,
|
|
|
|
&mouseStatus
|
|
|
|
);
|
|
|
|
calculateTargetAngle(
|
|
|
|
&rabbitPosition,
|
|
|
|
&mouseStatus
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleCombat() {
|
|
|
|
if (mouseStatus.leftButtonDown) {
|
|
|
|
attemptToFireRabbitBullet(
|
|
|
|
&rabbitPosition,
|
|
|
|
&rabbitWeaponry,
|
|
|
|
rabbitBulletPosition
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
advanceRabbitBullets(
|
|
|
|
rabbitBulletPosition,
|
|
|
|
&rabbitWeaponry
|
|
|
|
);
|
|
|
|
|
2024-02-25 20:48:19 +00:00
|
|
|
buildCollisionGrids(
|
|
|
|
rabbitBulletPosition,
|
|
|
|
&rabbitPosition,
|
|
|
|
enemyPosition
|
|
|
|
);
|
|
|
|
|
2024-02-25 17:52:42 +00:00
|
|
|
handleRabbitToEnemyCollisions(
|
|
|
|
&rabbitPosition,
|
|
|
|
enemyPosition
|
|
|
|
);
|
|
|
|
|
2024-02-25 13:43:30 +00:00
|
|
|
handleRabbitBulletToEnemyCollisions(
|
|
|
|
rabbitBulletPosition,
|
|
|
|
enemyPosition
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleRedraw() {
|
|
|
|
drawOnlyRabbitArena();
|
|
|
|
drawOnlyEnemiesArena();
|
|
|
|
drawOnlyMouseArena();
|
|
|
|
drawOnlyRabbitBulletArena();
|
|
|
|
|
|
|
|
redrawArena();
|
|
|
|
|
|
|
|
renderRabbit();
|
|
|
|
renderEnemies();
|
|
|
|
renderMouse();
|
|
|
|
renderRabbitBullets();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2024-02-21 21:25:00 +00:00
|
|
|
double speedCalcs[200];
|
|
|
|
int currentSpeedCalc = 0;
|
|
|
|
double averageSpeedCalc;
|
|
|
|
clock_t startTime;
|
2024-02-25 13:43:30 +00:00
|
|
|
*/
|
2024-02-21 21:25:00 +00:00
|
|
|
|
|
|
|
int main(void) {
|
2024-02-24 12:36:18 +00:00
|
|
|
byte *drawBuffer;
|
2024-02-21 21:25:00 +00:00
|
|
|
int keepRunning = 1;
|
2024-02-25 17:52:42 +00:00
|
|
|
int i;
|
2024-02-21 21:25:00 +00:00
|
|
|
|
|
|
|
if (setupGame()) return 1;
|
|
|
|
|
2024-02-24 12:36:18 +00:00
|
|
|
drawBuffer = getDrawBuffer();
|
|
|
|
|
2024-02-25 17:52:42 +00:00
|
|
|
for (i = 0; i < ENEMY_MAX_COUNT; ++i) {
|
|
|
|
maybeSpawnEnemy();
|
|
|
|
}
|
2024-02-21 21:25:00 +00:00
|
|
|
|
2024-02-16 02:18:15 +00:00
|
|
|
while (keepRunning) {
|
|
|
|
readMouse(&mouseStatus);
|
|
|
|
populateKeyboardKeydownState();
|
2024-02-21 13:25:55 +00:00
|
|
|
|
2024-02-25 13:43:30 +00:00
|
|
|
handleMovement();
|
|
|
|
handleRedraw();
|
2024-02-25 20:48:19 +00:00
|
|
|
handleCombat();
|
2024-02-20 13:20:35 +00:00
|
|
|
|
|
|
|
waitStartVbl();
|
2024-02-15 13:34:50 +00:00
|
|
|
copyDrawBufferToDisplay();
|
|
|
|
waitEndVbl();
|
2024-02-16 02:18:15 +00:00
|
|
|
|
2024-02-20 17:39:28 +00:00
|
|
|
if (keyboardKeydownState.KEY_ESC) { keepRunning = 0; }
|
2024-02-15 01:15:55 +00:00
|
|
|
}
|
2024-02-16 02:18:15 +00:00
|
|
|
|
|
|
|
freeBMP(&spritesheetImage);
|
|
|
|
|
|
|
|
setVideoMode(VIDEO_MODE_80x25_TEXT);
|
|
|
|
uninstallKeyboardHandler();
|
|
|
|
|
2024-02-25 13:43:30 +00:00
|
|
|
/*
|
2024-02-21 21:25:00 +00:00
|
|
|
averageSpeedCalc = 0;
|
|
|
|
for (currentSpeedCalc = 0; currentSpeedCalc < 200; ++currentSpeedCalc) {
|
|
|
|
averageSpeedCalc += speedCalcs[currentSpeedCalc];
|
|
|
|
}
|
|
|
|
|
|
|
|
averageSpeedCalc /= 200;
|
|
|
|
|
|
|
|
fprintf(stderr, "average: %f\n", averageSpeedCalc);
|
2024-02-25 13:43:30 +00:00
|
|
|
*/
|
2024-02-21 13:25:55 +00:00
|
|
|
|
2024-02-15 13:34:50 +00:00
|
|
|
return 0;
|
2024-02-15 01:15:55 +00:00
|
|
|
}
|