ready for push to public git?
This commit is contained in:
parent
a144f4fc47
commit
d0ccb689a9
32
combat.c
32
combat.c
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
3
combat.h
3
combat.h
@ -12,7 +12,8 @@ void advanceRabbitBullets(
|
||||
|
||||
void handleRabbitBulletToEnemyCollisions(
|
||||
struct BulletPosition[],
|
||||
struct EnemyPosition[]
|
||||
struct EnemyPosition[],
|
||||
struct RabbitWeaponry*
|
||||
);
|
||||
|
||||
int handleRabbitToEnemyCollisions(
|
||||
|
11
const.c
11
const.c
@ -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
26
const.h
@ -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,
|
||||
|
@ -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
178
game.c
@ -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
7
game.h
@ -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
|
||||
|
127
movement.c
127
movement.c
@ -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[],
|
||||
|
19
movement.h
19
movement.h
@ -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*);
|
||||
|
@ -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;
|
||||
}
|
||||
|
11
powerup.c
11
powerup.c
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
63
system/vga.c
63
system/vga.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user