ready for push to public git?

This commit is contained in:
John Bintz 2024-03-04 17:38:03 -05:00
parent a144f4fc47
commit d0ccb689a9
19 changed files with 426 additions and 110 deletions

View File

@ -105,15 +105,15 @@ int attemptToFireRabbitBullet(
);
}
} else if (rabbitWeaponry->currentWeapon == WEAPON_TYPE_BEAM_SHOT_GUN) {
// make sure three bullets are available
// make sure two bullets are available
if (!maybeFireShotCount(
rabbitBulletPosition,
availableBullets,
4
2
)) return 0;
// if so, fire away
for (i = 0; i < 4; ++i) {
for (i = 0; i < 2; ++i) {
beamOffsetX = sin(mouseAngle * DEG2RAD) * i * 2;
beamOffsetY = -cos(mouseAngle * DEG2RAD) * i * 2;
@ -267,8 +267,8 @@ int rabbitBulletGrid[4][RABBIT_BULLET_LIMIT];
int enemyGrid[4][ENEMY_MAX_COUNT];
int enemyBulletGrid[4][ENEMY_BULLET_LIMIT];
int rabbitBulletGridIndex[4],
enemyGridIndex[4],
enemyBulletGridIndex[4];
enemyGridIndex[4],
enemyBulletGridIndex[4];
int gridPosition[4];
#define CALCULATE_GRID_POS(x,y) ((x / COLLISION_GRID_SIZE) + (y / COLLISION_GRID_SIZE) * 2)
@ -424,7 +424,8 @@ void knockbackEnemy(
void handleRabbitBulletToEnemyCollisions(
struct BulletPosition rabbitBulletPosition[],
struct EnemyPosition enemyPosition[]
struct EnemyPosition enemyPosition[],
struct RabbitWeaponry *rabbitWeaponry
) {
int bulletIdx, enemyIdx, grid;
int resolvedBulletIdx, resolvedEnemyIdx;
@ -447,7 +448,7 @@ void handleRabbitBulletToEnemyCollisions(
populateTargetCollision(&enemy);
if (isCollision()) {
enemyPosition[resolvedEnemyIdx].hitPoints--;
enemyPosition[resolvedEnemyIdx].hitPoints -= rabbitWeaponry->damage;
if (enemyPosition[resolvedEnemyIdx].hitPoints < 1) {
enemyPosition[resolvedEnemyIdx].willBeInactive = 1;
enemyPosition[resolvedEnemyIdx].wasKilled = 1;
@ -543,11 +544,18 @@ void handleEnemyKills(
struct RabbitWeaponry *rabbitWeaponry
) {
int i, currentKillCount;
int originalDifficulty;
int healthIncrease;
currentKillCount = processEnemyKillStates(enemyPosition);
globalGameState->health += ENEMY_KILL_HEALTH_GAIN * currentKillCount;
if (globalGameState->health > RABBIT_HEALTH_MAX) globalGameState->health = RABBIT_HEALTH_MAX;
healthIncrease = globalGameState->healthGainPerKill * currentKillCount;
if (healthIncrease > 0) {
healthIncrease = rand() % healthIncrease + 1;
globalGameState->health += healthIncrease;
if (globalGameState->health > globalGameState->maxHealth) globalGameState->health = globalGameState->maxHealth;
}
globalGameState->kills += currentKillCount;
@ -559,11 +567,17 @@ void handleEnemyKills(
currentKillCount
);
originalDifficulty = globalGameState->difficulty;
for (i = 0; i < MAX_DIFFICULTY; ++i) {
if (globalGameState->kills > difficultyBands[i]) {
globalGameState->difficulty = i + 1;
}
}
if (originalDifficulty != globalGameState->difficulty) {
globalGameState->coins += (globalGameState->difficulty - originalDifficulty);
}
}
}

View File

@ -12,7 +12,8 @@ void advanceRabbitBullets(
void handleRabbitBulletToEnemyCollisions(
struct BulletPosition[],
struct EnemyPosition[]
struct EnemyPosition[],
struct RabbitWeaponry*
);
int handleRabbitToEnemyCollisions(

11
const.c
View File

@ -3,6 +3,9 @@
int difficultyBands[MAX_DIFFICULTY];
int hitPointRanges[MAX_DIFFICULTY][4];
int damageUpgradeCosts[3] = { 5, 11, 18 };
int healthUpgradeCosts[3] = { 4, 9, 15 };
int healthGainUpgradeCosts[3] = { 6, 13, 21 };
struct SpriteBounds bounds;
@ -17,11 +20,15 @@ struct CompiledSpriteRender rabbit,
void buildDifficultyBands() {
int i;
float current = BASE_KILLS;
float current = 0;
float increaseBy = BASE_KILLS;
for (i = 0; i < MAX_DIFFICULTY; ++i) {
current += increaseBy;
difficultyBands[i] = (int)current;
current *= KILLS_NEEDED_FOR_NEXT_LEVEL_MULTIPLIER;
increaseBy *= KILLS_NEEDED_FOR_NEXT_LEVEL_MULTIPLIER;
}
}

26
const.h
View File

@ -8,6 +8,11 @@
#define ARENA_HEIGHT_TILES (10)
#define COLLISION_GRID_SIZE (ARENA_WIDTH_TILES / 2 * TILE_SIZE)
#define ARENA_LEFT_EDGE (TILE_SIZE)
#define ARENA_TOP_EDGE (TILE_SIZE)
#define ARENA_RIGHT_EDGE (ARENA_WIDTH_TILES - 1) * TILE_SIZE
#define ARENA_BOTTOM_EDGE (ARENA_WIDTH_TILES - 1) * TILE_SIZE
#define MOUSE_DISTANCE (32)
#define RABBIT_MOTION_DRAG (2)
@ -33,22 +38,21 @@
#define DEG2RAD (3.14159/180)
#define ENEMY_MAX_COUNT (50)
#define ENEMY_BULLET_LIMIT (ENEMY_MAX_COUNT / 4)
#define ENEMY_BULLET_LIMIT (ENEMY_MAX_COUNT / 5)
#define ENEMY_MOVE_SPEED (1)
#define ENEMY_MOVE_DELAY (3)
#define ENEMY_BULLET_VELOCITY (RABBIT_BULLET_VELOCITY - 2)
#define ENEMY_BULLET_VELOCITY (RABBIT_BULLET_VELOCITY - 1)
#define ENEMY_FIRE_MIN_DELAY (45)
#define ENEMY_FIRE_MIN_DELAY (50)
#define ENEMY_FIRE_VARIABLE_DELAY (60)
#define ENEMY_BULLET_DAMAGE (3)
#define ENEMY_COLLISION_DAMAGE (6)
#define ENEMY_KILL_HEALTH_GAIN (1)
#define ENEMY_HIT_POINT_DIFFICULTY_INCREASE_EVERY (4)
#define BASE_ENEMY_SPAWN_COOLDOWN (30)
#define DIFFICULTY_SPAWN_COOLDOWN_REDUCTION (2)
#define DIFFICULTY_SPAWN_COOLDOWN_REDUCTION (1)
#define MINIMUM_ENEMY_SPAWN_COOLDOWN (3)
#define VARIABLE_ENEMY_SPAWN_COOLDOWN (10)
@ -56,8 +60,8 @@
#define SHOTGUN_ROUNDS_PER_LEVEL (25)
#define MAX_DIFFICULTY (40)
#define BASE_KILLS (30)
#define KILLS_NEEDED_FOR_NEXT_LEVEL_MULTIPLIER (1.25)
#define BASE_KILLS (20)
#define KILLS_NEEDED_FOR_NEXT_LEVEL_MULTIPLIER (1.06)
#define HIT_POINT_DIFFICULTY_INCREASE_DELAY (4)
#define WEAPON_TYPE_SINGLE_SHOT_GUN (0)
@ -69,10 +73,16 @@
#define KNOCKBACK_DISTANCE (3)
#define HEALTH_UPGRADE_GAIN (10)
extern int difficultyBands[];
extern int hitPointRanges[MAX_DIFFICULTY][4];
extern struct SpriteBounds bounds;
extern int damageUpgradeCosts[];
extern int healthUpgradeCosts[];
extern int healthGainUpgradeCosts[];
extern struct SpriteBounds bounds;
extern struct CompiledSpriteRender rabbit,
mouse,
bullet,

View File

@ -3,11 +3,12 @@
#include <stdio.h>
void TestBuildDifficultyBands(CuTest *tc) {
buildDifficultyBands();
CuAssertIntEquals(tc, 30, difficultyBands[0]);
CuAssertIntEquals(tc, 37, difficultyBands[1]);
CuAssertIntEquals(tc, 46, difficultyBands[2]);
CuAssertIntEquals(tc, 20, difficultyBands[0]);
CuAssertIntEquals(tc, 41, difficultyBands[1]);
CuAssertIntEquals(tc, 3095, difficultyBands[MAX_DIFFICULTY - 1]);
}
void TestBuildHitPointRanges(CuTest *tc) {

178
game.c
View File

@ -45,7 +45,13 @@ struct GlobalGameState globalGameState = {
.spawnCooldown = 0,
.difficulty = 0,
.kills = 0,
.health = RABBIT_HEALTH_MAX
.coins = 0,
.health = RABBIT_HEALTH_MAX,
.maxHealth = RABBIT_HEALTH_MAX,
.healthGainPerKill = 1,
.damageUpgradeLevel = 0,
.healthUpgradeLevel = 0,
.healthGainUpgradeLevel = 0
};
void setupRabbitBullets() {
@ -59,6 +65,7 @@ void setupRabbitBullets() {
rabbitWeaponry.cooldown = 0;
rabbitWeaponry.currentWeapon = WEAPON_TYPE_SINGLE_SHOT_GUN;
rabbitWeaponry.currentWeaponRemainingRounds = 0;
rabbitWeaponry.damage = 1;
}
void setupPowerup() {
@ -160,7 +167,10 @@ void renderMouse() {
mouse.x = rabbitPosition.mousePosition[0];
mouse.y = rabbitPosition.mousePosition[1];
drawCompiledSprite(&mouse);
drawPixel(rabbitPosition.mouseDotPosition[0], rabbitPosition.mouseDotPosition[1], 2);
mouse.x = rabbitPosition.mouseDotPosition[0];
mouse.y = rabbitPosition.mouseDotPosition[1];
drawCompiledSprite(&mouse);
}
void renderRabbit() {
@ -234,11 +244,9 @@ void drawOnlyMouseArena() {
mouse.y = rabbitPosition.oldMousePosition[1];
drawOnlyArenaForSprite(&mouse);
bounds.top = rabbitPosition.oldMouseDotPosition[1];
bounds.bottom = rabbitPosition.oldMouseDotPosition[1];
bounds.left = rabbitPosition.oldMouseDotPosition[0];
bounds.right = rabbitPosition.oldMouseDotPosition[0];
drawOnlyArena(&bounds);
mouse.x = rabbitPosition.oldMouseDotPosition[0];
mouse.y = rabbitPosition.oldMouseDotPosition[1];
drawOnlyArenaForSprite(&mouse);
}
void drawOnlyRabbitArena() {
@ -425,7 +433,8 @@ void handleCombat() {
handleRabbitBulletToEnemyCollisions(
rabbitBulletPosition,
enemyPosition
enemyPosition,
&rabbitWeaponry
);
if (handleRabbitToPowerupCollision(&rabbitPosition, &playerPowerup)) {
@ -460,6 +469,123 @@ 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;
@ -480,27 +606,37 @@ int main(void) {
enemyPosition,
&rabbitPosition
);
handleMovement();
handleRedraw();
handleCombat();
handleRedraw();
handleEnemyKills(
enemyPosition,
&globalGameState,
&playerPowerup,
&rabbitWeaponry
);
handleMovement();
sprintf(buffer, "Hit: %d", globalGameState.kills);
renderStringToDrawBuffer(buffer, 1, 0, 210, 20);
sprintf(buffer, "Health: %d ", globalGameState.health);
renderStringToDrawBuffer(buffer, 1, 0, 210, 30);
sprintf(buffer, "Rnds: %d ", rabbitWeaponry.currentWeaponRemainingRounds);
renderStringToDrawBuffer(buffer, 1, 0, 210, 40);
sprintf(buffer, "Cool: %d ", playerPowerup.cooldown);
renderStringToDrawBuffer(buffer, 1, 0, 210, 50);
sprintf(buffer, "Lvl: %d ", globalGameState.difficulty);
renderStringToDrawBuffer(buffer, 1, 0, 210, 60);
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();

7
game.h
View File

@ -11,6 +11,13 @@ struct GlobalGameState {
int spawnCooldown;
int kills;
int health;
int maxHealth;
int healthGainPerKill;
int coins;
int damageUpgradeLevel;
int healthUpgradeLevel;
int healthGainUpgradeLevel;
};
#endif

View File

@ -9,6 +9,9 @@
#include "system/mouse_io.h"
#include "system/pc_stuff.h"
#include "system/vga.h"
#define SIGN(x) ((x > 0) - (x < 0))
void captureAndLimitMousePosition(
struct RabbitPosition *pos,
@ -26,43 +29,131 @@ void captureAndLimitMousePosition(
if (pos->mouseDotPosition[1] >= MOUSE_LIMIT_BOTTOM) pos->mouseDotPosition[1] = MOUSE_LIMIT_BOTTOM;
}
// now this is ray casting
struct TargetMousePosition {
int x, y;
};
void constrainMousePosition(
struct RabbitPosition *pos,
struct TargetMousePosition *target
) {
int i, didChange, which;
int currentX, currentY;
float xCrossover, yCrossover;
float maxDeltaX, maxDeltaY, fixHypotenuse, fixDistance;
float currentDeltaX, currentDeltaY;
float adjustedDeltaX, adjustedDeltaY;
int considerX, considerY;
maxDeltaX = sin(pos->mouseAngle * DEG2RAD) * MOUSE_DISTANCE;
maxDeltaY = -cos(pos->mouseAngle * DEG2RAD) * MOUSE_DISTANCE;
currentX = target->x + maxDeltaX;
currentY = target->y + maxDeltaY;
if (maxDeltaX > 0) {
currentDeltaX = ARENA_RIGHT_EDGE - target->x;
} else {
currentDeltaX = target->x - ARENA_LEFT_EDGE;
}
if (maxDeltaY > 0) {
currentDeltaY = ARENA_BOTTOM_EDGE - target->y;
} else {
currentDeltaY = target->y - ARENA_TOP_EDGE;
}
which = -1;
considerY = currentY > ARENA_BOTTOM_EDGE || currentY < ARENA_TOP_EDGE;
considerX = currentX > ARENA_RIGHT_EDGE || currentX < ARENA_LEFT_EDGE;
if (considerX || considerY) {
if (considerX && considerY) {
which = currentDeltaY < currentDeltaX;
} else {
which = considerY;
}
}
switch (which) {
case 0: // x
if (maxDeltaX > 0) {
adjustedDeltaX = ARENA_RIGHT_EDGE - target->x;
} else {
adjustedDeltaX = -(target->x - ARENA_LEFT_EDGE);
}
adjustedDeltaY = (adjustedDeltaX / sin(pos->mouseAngle * DEG2RAD)) * -cos(pos->mouseAngle * DEG2RAD);
if (fabs(adjustedDeltaY) > currentDeltaY) {
adjustedDeltaY = SIGN(adjustedDeltaY) * currentDeltaY;
}
break;
case 1: // y
if (maxDeltaY > 0) {
adjustedDeltaY = ARENA_BOTTOM_EDGE - target->y;
} else {
adjustedDeltaY = -(target->y - ARENA_TOP_EDGE);
}
adjustedDeltaX = (adjustedDeltaY / -cos(pos->mouseAngle * DEG2RAD)) * sin(pos->mouseAngle * DEG2RAD);
if (fabs(adjustedDeltaX) > currentDeltaX) {
adjustedDeltaX = SIGN(adjustedDeltaX) * currentDeltaX;
}
break;
}
if (which != -1) {
currentX = target->x + adjustedDeltaX;
currentY = target->y + adjustedDeltaY;
}
target->x = currentX;
target->y = currentY;
}
void calculateTargetAngle(
struct RabbitPosition *pos
) {
int targetX, targetY;
float distanceX, distanceY;
float angle, fixHypotenuse, fixDistance;
struct TargetMousePosition targetMousePosition;
// Position the cursor
distanceX = pos->mouseDotPosition[0] - pos->rabbitPosition[0];
distanceY = pos->mouseDotPosition[1] - pos->rabbitPosition[1];
angle = atan2(distanceY, distanceX) * RAD2DEG + 90;
if (angle < 0) angle += 360;
// edge case -- top left corner
if (
pos->rabbitPosition[0] == ARENA_LEFT_EDGE &&
pos->rabbitPosition[1] == ARENA_TOP_EDGE &&
distanceX == 0 &&
distanceY == 0
) {
angle = 315;
} else {
angle = atan2(distanceY, distanceX) * RAD2DEG + 90;
if (angle < 0) angle += 360;
}
distanceX = sin(angle * DEG2RAD) * MOUSE_DISTANCE;
distanceY = -cos(angle * DEG2RAD) * MOUSE_DISTANCE;
pos->mouseAngle = angle;
pos->oldMousePosition[0] = pos->mousePosition[0];
pos->oldMousePosition[1] = pos->mousePosition[1];
targetX = pos->rabbitPosition[0] + distanceX;
targetY = pos->rabbitPosition[1] + distanceY;
targetMousePosition.x = pos->rabbitPosition[0];
targetMousePosition.y = pos->rabbitPosition[1];
if (targetX > (ARENA_WIDTH_TILES - 1) * TILE_SIZE) {
fixDistance = targetX - ((ARENA_WIDTH_TILES - 1) * TILE_SIZE);
fixHypotenuse = fixDistance / sin(angle * DEG2RAD);
targetX = (ARENA_WIDTH_TILES - 1) * TILE_SIZE;
targetY = pos->rabbitPosition[1] + -cos(angle * DEG2RAD) * -fixHypotenuse;
}
constrainMousePosition(pos, &targetMousePosition);
pos->mousePosition[0] = targetX;
pos->mousePosition[1] = targetY;
pos->mouseAngle = angle;
pos->mousePosition[0] = targetMousePosition.x;
pos->mousePosition[1] = targetMousePosition.y;
}
#define SIGN(x) ((x > 0) - (x < 0))
void handleEnemyMovement(
struct EnemyPosition enemyPosition[],

View File

@ -22,6 +22,7 @@ struct RabbitWeaponry {
char cooldown;
char currentWeapon;
int currentWeaponRemainingRounds;
char damage;
};
struct PlayerPowerup {
@ -48,20 +49,20 @@ struct BulletPosition {
};
struct EnemyPosition {
char isActive;
char willBeInactive;
char wasKilled;
char hitPoints;
char hasLeftGate;
char gateExitedFrom;
int hitPoints;
int enemyPosition[2];
int oldEnemyPosition[2];
int enemyMoveDelayStep;
int enemyFireDelayStep;
char isActive;
char willBeInactive;
char wasKilled;
char hasLeftGate;
char gateExitedFrom;
};
void calculateTargetAngle(struct RabbitPosition*);

View File

@ -3,28 +3,28 @@
#include "const.h"
void TestCalculateTargetAngle_AgainstRightWall(CuTest *tc) {
void TestCalculateTargetAngle_AgainstTopRight(CuTest *tc) {
struct RabbitPosition rabbitPosition;
// mouse against very edge
rabbitPosition.mouseDotPosition[0] = 199;
rabbitPosition.mouseDotPosition[1] = 30;
rabbitPosition.mouseDotPosition[1] = 0;
// rabbit against wall
rabbitPosition.rabbitPosition[0] = 179;
rabbitPosition.rabbitPosition[1] = 80;
rabbitPosition.rabbitPosition[0] = 177;
rabbitPosition.rabbitPosition[1] = 25;
calculateTargetAngle(&rabbitPosition);
// mouse should not extend (tile width - mouse width) past player
CuAssertIntEquals(tc, 180, rabbitPosition.mousePosition[0]);
CuAssertIntEquals(tc, 105, rabbitPosition.mousePosition[1]);
CuAssertIntEquals(tc, 21, rabbitPosition.mouseAngle);
CuAssertIntEquals(tc, 21, rabbitPosition.mousePosition[1]);
CuAssertIntEquals(tc, 41, rabbitPosition.mouseAngle);
}
CuSuite *MovementGetSuite() {
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, TestCalculateTargetAngle_AgainstRightWall);
SUITE_ADD_TEST(suite, TestCalculateTargetAngle_AgainstTopRight);
return suite;
}

View File

@ -11,7 +11,7 @@
int determinePowerupCooldownTime(int difficulty) {
if (difficulty > MAX_DIFFICULTY) exit(1);
return difficultyBands[difficulty] + rand() % difficultyBands[difficulty];
return difficulty * 10 + rand() % 20;
}
// if every shot lands, you should run out slightly before the next powerup
@ -20,9 +20,8 @@ int determinePowerupCooldownTime(int difficulty) {
int determineWeaponRounds(int difficulty) {
if (difficulty > MAX_DIFFICULTY) exit(1);
return difficultyBands[difficulty] +
difficultyBands[difficulty] / 2 +
rand() % (difficultyBands[difficulty] / 2);
return difficultyBands[difficulty] / 2 +
rand() % (difficultyBands[difficulty] / 8);
}
void processPowerupCooldown(
@ -32,7 +31,7 @@ void processPowerupCooldown(
int killCount
) {
if (playerPowerup->isActive) return;
if (rabbitWeaponry->currentWeapon != WEAPON_TYPE_SINGLE_SHOT_GUN) return;
//if (rabbitWeaponry->currentWeapon != WEAPON_TYPE_SINGLE_SHOT_GUN) return;
playerPowerup->cooldown -= killCount;
if (playerPowerup->cooldown <= 0) {
@ -40,7 +39,7 @@ void processPowerupCooldown(
playerPowerup->y = TILE_SIZE + rand() % ((ARENA_HEIGHT_TILES - 2) * TILE_SIZE);
playerPowerup->isActive = 1;
playerPowerup->willBeInactive = 0;
playerPowerup->type = 2;
playerPowerup->type = rand() % 2 + 1;
playerPowerup->cooldown = determinePowerupCooldownTime(globalGameState->difficulty);
}

View File

@ -10,17 +10,17 @@
void TestDeterminePowerupCooldownTime(CuTest *tc) {
srand(1);
CuAssertIntEquals(tc, 38, determinePowerupCooldownTime(0));
CuAssertIntEquals(tc, 60, determinePowerupCooldownTime(1));
CuAssertIntEquals(tc, 85, determinePowerupCooldownTime(2));
CuAssertIntEquals(tc, 18, determinePowerupCooldownTime(0));
CuAssertIntEquals(tc, 28, determinePowerupCooldownTime(1));
CuAssertIntEquals(tc, 33, determinePowerupCooldownTime(2));
}
void TestDetermineWeaponRounds(CuTest *tc) {
srand(1);
CuAssertIntEquals(tc, 53, determineWeaponRounds(0));
CuAssertIntEquals(tc, 71, determineWeaponRounds(1));
CuAssertIntEquals(tc, 85, determineWeaponRounds(2));
CuAssertIntEquals(tc, 10, determineWeaponRounds(0));
CuAssertIntEquals(tc, 23, determineWeaponRounds(1));
CuAssertIntEquals(tc, 36, determineWeaponRounds(2));
}
@ -60,7 +60,7 @@ void TestProcessPowerupCooldown_WeaponActive(CuTest *tc) {
10
);
CuAssertIntEquals(tc, 100, playerPowerup.cooldown);
CuAssertIntEquals(tc, 90, playerPowerup.cooldown);
CuAssertIntEquals(tc, 0, playerPowerup.isActive);
}
@ -108,7 +108,7 @@ void TestProcessPowerupCooldown_Triggered(CuTest *tc) {
CuAssertIntEquals(tc, 0, playerPowerup.willBeInactive);
// rand
CuAssertIntEquals(tc, 33, playerPowerup.cooldown);
CuAssertIntEquals(tc, 15, playerPowerup.cooldown);
CuAssertIntEquals(tc, 58, playerPowerup.x);
CuAssertIntEquals(tc, 178, playerPowerup.y);
}

View File

@ -52,7 +52,7 @@ void TestSpawnEnemy(CuTest *tc) {
// randomized values
CuAssertIntEquals(tc, 1, enemyPosition.hitPoints);
CuAssertIntEquals(tc, 103, enemyPosition.enemyFireDelayStep);
CuAssertIntEquals(tc, 108, enemyPosition.enemyFireDelayStep);
// from spawndetails
CuAssertIntEquals(tc, 1, enemyPosition.gateExitedFrom);

View File

@ -1391,10 +1391,10 @@ sprite_bullet_:
mov ebp, esp
mov BYTE PTR [eax + -321], 5
mov BYTE PTR [eax + -320], 5
mov BYTE PTR [eax + -1], 5
mov BYTE PTR [eax + 0], 5
mov BYTE PTR [eax + 1], 5
mov BYTE PTR [eax + 320], 5
mov BYTE PTR [eax + 321], 5
pop ebp
ret

View File

@ -66,9 +66,9 @@ extern void sprite_mouse(byte *);
extern void sprite_bullet(byte *);
#define SPRITE_BULLET_WIDTH (4)
#define SPRITE_BULLET_WIDTH (2)
#define SPRITE_BULLET_HEIGHT (4)
#define SPRITE_BULLET_HEIGHT (2)
#define SPRITE_BULLET_OFFSET_X (1)

View File

@ -26,8 +26,8 @@ files:
dimensions: [8, 8]
offset: [4, 4]
bullet:
position: [16, 28]
dimensions: [4, 4]
position: [17, 29]
dimensions: [2, 2]
offset: [1, 1]
enemy:
position: [0, 20]

View File

@ -13,6 +13,9 @@ void populateKeyboardKeydownState() {
keyboardKeydownState.KEY_A = keystateBits[3] & 0x40;
keyboardKeydownState.KEY_S = keystateBits[3] & 0x80;
keyboardKeydownState.KEY_D = keystateBits[4] & 0x01;
keyboardKeydownState.KEY_I = keystateBits[2] & 0x80;
keyboardKeydownState.KEY_O = keystateBits[3] & 0x01;
keyboardKeydownState.KEY_P = keystateBits[3] & 0x02;
keyboardKeydownState.KEY_ESC = keystateBits[0] & 0x02;
}

View File

@ -10,6 +10,9 @@ struct KeyboardKeydownState {
byte KEY_A;
byte KEY_S;
byte KEY_D;
byte KEY_I;
byte KEY_O;
byte KEY_P;
byte KEY_ESC;
};

View File

@ -2,6 +2,7 @@
#include "pc_stuff.h"
#include <malloc.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
@ -128,26 +129,68 @@ void setVGAColors(struct VGAColor colors[], int totalColors) {
#define RENDER_STRING_FAILSAFE (80)
struct CharRowDetails {
char c;
char color;
char backgroundColor;
char writeBackgroundColor;
char* pos;
} charRowDetails;
// Write this in inline assembler for practice!
void plotCharRow();
#pragma aux plotCharRow = \
"mov al, [edi]" \
"mov ah, 8" \
"mov bl, [edi+1]" \
"mov bh, [edi+2]" \
"mov cl, [edi+3]" \
"mov edi, [edi + 4]" \
"nextBit: mov ch, al" \
"and ch,1" \
"cmp ch,1" \
"jne background" \
"mov [edi], bl" \
"jmp maybeKeepGoing" \
"background: cmp cl,0" \
"je maybeKeepGoing" \
"mov [edi], bh" \
"maybeKeepGoing: ror al, 1" \
"inc edi" \
"dec ah" \
"jnz nextBit" \
parm [edi] \
modify [eax ebx ecx edi];
void renderStringToDrawBuffer(char* buffer, int color, int backgroundColor, int x, int y) {
char *bufferPos = buffer, currentCharacter, charRow;
int i, fontX, fontY, currentX = x;
int charX, fontYs[8];
charRowDetails.color = color;
if (backgroundColor == -1) {
charRowDetails.backgroundColor = 0;
}
charRowDetails.writeBackgroundColor = backgroundColor != -1;
for (fontY = 0; fontY < 8; ++fontY) {
fontYs[fontY] = (y + fontY) * VGA_DISPLAY_WIDTH;
}
charX = x;
for (i = 0; i < RENDER_STRING_FAILSAFE; ++i) {
currentCharacter = *(bufferPos++);
if (!currentCharacter) break;
for (fontY = 0; fontY < 8; ++fontY) {
charRow = font8x8_basic[currentCharacter][fontY];
charRowDetails.c = font8x8_basic[currentCharacter][fontY];
charRowDetails.pos = drawBuffer + fontYs[fontY] + charX;
for (fontX = 0; fontX < 8; ++fontX) {
if (charRow & (1 << fontX)) {
drawBuffer[(y + fontY) * VGA_DISPLAY_WIDTH + (i * 8 + x + fontX)] = color;
} else {
if (backgroundColor > -1) {
drawBuffer[(y + fontY) * VGA_DISPLAY_WIDTH + (i * 8 + x + fontX)] = backgroundColor;
}
}
}
plotCharRow(&charRowDetails);
}
charX += 8;
}
}