diff --git a/ad_astra/AdAstra/src/driver/display/display.c b/ad_astra/AdAstra/src/driver/display/display.c index f84c611..c48b45b 100644 --- a/ad_astra/AdAstra/src/driver/display/display.c +++ b/ad_astra/AdAstra/src/driver/display/display.c @@ -38,6 +38,13 @@ void setDisplayContrast(uint8_t value) { dataMode(); } +void turnDisplayOnOff(bool shouldBeOn) { + commandMode(); + sendByteOnSPI(0x8D | shouldBeOn); // set charge pump on/off + sendByteOnSPI(0x10 | shouldBeOn << 2); // set charge pump on/off + sendByteOnSPI(0xAE | shouldBeOn); // turn display sleep on/off +} + void initializeDisplay(DrawFunction drawEverything) { setOutputPin(DISPLAY_RESET_OUTPUT_PIN, false); for (volatile uint8_t i = 0; i != 255; i++) diff --git a/ad_astra/AdAstra/src/driver/display/display.h b/ad_astra/AdAstra/src/driver/display/display.h index 2ba3e47..4a27bf5 100644 --- a/ad_astra/AdAstra/src/driver/display/display.h +++ b/ad_astra/AdAstra/src/driver/display/display.h @@ -21,6 +21,8 @@ typedef void (*DrawFunction)(Rectangle); void initializeDisplay(DrawFunction drawEverything); void setDisplayContrast(uint8_t value); +void turnDisplayOnOff(bool shouldBeOn); + void startIntersectionTest(); bool endIntersectionTest(); diff --git a/ad_astra/AdAstra/src/driver/infra/infra.c b/ad_astra/AdAstra/src/driver/infra/infra.c index 7c195ca..641fb10 100644 --- a/ad_astra/AdAstra/src/driver/infra/infra.c +++ b/ad_astra/AdAstra/src/driver/infra/infra.c @@ -28,6 +28,7 @@ static struct { ProtocolState protocolState; CommandState commandState; OnCommandReceived onCommandReceived; + OnReceiveStarted onReceiveStarted; } infra; @@ -81,6 +82,8 @@ static inline uint8_t isIrOn() { } ISR(PCINT0_vect) { + infra.onReceiveStarted(); + switch (infra.protocolState) { case idle: if (isIrOn()) { @@ -136,9 +139,10 @@ ISR(TIM0_COMPB_vect) { } } -void initializeInfra(OnCommandReceived onCommandReceived) { +void initializeInfra(OnCommandReceived onCommandReceived, OnReceiveStarted onReceiveStarted) { setBit(PORTB, IR_PIN); // enable pull-up setBit(PCMSK, IR_PIN); // specific pin change interrupt enable setBit(GIMSK, PCIE); // global on pin change interrupt enable; infra.onCommandReceived = onCommandReceived; + infra.onReceiveStarted = onReceiveStarted; } diff --git a/ad_astra/AdAstra/src/driver/infra/infra.h b/ad_astra/AdAstra/src/driver/infra/infra.h index 8f79d8c..f8050a5 100644 --- a/ad_astra/AdAstra/src/driver/infra/infra.h +++ b/ad_astra/AdAstra/src/driver/infra/infra.h @@ -10,7 +10,8 @@ #define REPEAT_CODE 1 typedef void (*OnCommandReceived)(uint8_t); +typedef void (*OnReceiveStarted)(); -void initializeInfra(OnCommandReceived onCommandReceived); +void initializeInfra(OnCommandReceived onCommandReceived, OnReceiveStarted onReceiveStarted); #endif diff --git a/ad_astra/AdAstra/src/driver/sleep/sleep.c b/ad_astra/AdAstra/src/driver/sleep/sleep.c index 6efd706..27d34e0 100644 --- a/ad_astra/AdAstra/src/driver/sleep/sleep.c +++ b/ad_astra/AdAstra/src/driver/sleep/sleep.c @@ -20,6 +20,7 @@ void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds) { previousFrameTime = milisecondsSinceFrameStart; while (milisecondsSinceFrameStart < frameLengthInMilliseconds) { + clearBit(MCUCR, SM1); // idle mode sleep_cpu(); } @@ -27,6 +28,10 @@ void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds) { } } +void powerOff() { + setBit(MCUCR, SM1); // power-down mode + sleep_cpu(); +} ISR(TIM0_COMPA_vect) { milisecondsSinceFrameStart++; diff --git a/ad_astra/AdAstra/src/driver/sleep/sleep.h b/ad_astra/AdAstra/src/driver/sleep/sleep.h index 71ec3fd..f9deac3 100644 --- a/ad_astra/AdAstra/src/driver/sleep/sleep.h +++ b/ad_astra/AdAstra/src/driver/sleep/sleep.h @@ -10,4 +10,6 @@ typedef bool (*FrameFunction)(uint8_t); // frameFunction gets previousFrameTime (in milliseconds) as argument void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds); +void powerOff(); + #endif diff --git a/ad_astra/AdAstra/src/mediator/mediator.c b/ad_astra/AdAstra/src/mediator/mediator.c index 4733c80..269487c 100644 --- a/ad_astra/AdAstra/src/mediator/mediator.c +++ b/ad_astra/AdAstra/src/mediator/mediator.c @@ -21,6 +21,8 @@ static struct { uint8_t contrast; uint8_t framesSinceLastSave; uint8_t deathDownCounter; + bool isSleeping; + uint8_t receivedWakeUpBitCount; } state = { .contrast = 255 }; @@ -34,24 +36,45 @@ static inline void saveGame() { } } -static bool frameFunction(uint8_t previousFrameTime) { - disableWritingEEPROM(); - - if (spaceshipObject->as.spaceship.healthLoss >= MAX_HEALTH) { +static inline bool handleDeathAnimation() { + if (isSpaceshipDestroyed()) { setDisplayContrast(state.contrast * (state.deathDownCounter / DEATH_SCREEN_LENGTH)); if (state.deathDownCounter-- == 0) { invalidateEEPROM(); return false; }; } - - handleCommands(); - handleAI(); - generateEvents(); - tickObjects(previousFrameTime); - drawFrame(); - enableWritingEEPROM(); - saveGame(); + return true; +} + +void handleOff() { + turnDisplayOnOff(false); + state.isSleeping = true; +} + +void handleOn() { + if (state.isSleeping && ++state.receivedWakeUpBitCount > 50) { + turnDisplayOnOff(true); + state.isSleeping = false; + state.receivedWakeUpBitCount = 0; + } +} + + +static bool frameFunction(uint8_t previousFrameTime) { + if (state.isSleeping) { + powerOff(); + } else { + disableWritingEEPROM(); + tickObjects(previousFrameTime); + handleCommands(); + handleAI(); + generateEvents(); + drawFrame(); + enableWritingEEPROM(); + saveGame(); + return handleDeathAnimation(); + } return true; } @@ -71,7 +94,7 @@ static inline void createObjects() { void setupConnections() { initializeHardwareAccess(); initializeRedundantStorage(); - initializeInfra(addCommand); + initializeInfra(addCommand, handleOn); initializeDisplay(drawObjects); } @@ -85,7 +108,7 @@ void startGame() { void changeDisplayContrast(int8_t by) { if (by < 0) { state.contrast = (state.contrast < -by) ? 0 : (state.contrast + by); - } else { + } else { state.contrast = (state.contrast > 255 - by) ? 255 : (state.contrast + by); } diff --git a/ad_astra/AdAstra/src/mediator/mediator.h b/ad_astra/AdAstra/src/mediator/mediator.h index d5aefa1..6d0052f 100644 --- a/ad_astra/AdAstra/src/mediator/mediator.h +++ b/ad_astra/AdAstra/src/mediator/mediator.h @@ -6,6 +6,7 @@ void setupConnections(); void startGame(); +void handleOff(); void changeDisplayContrast(int8_t by); #endif diff --git a/ad_astra/AdAstra/src/objects/ai/ai.c b/ad_astra/AdAstra/src/objects/ai/ai.c index 189fb7b..478aac4 100644 --- a/ad_astra/AdAstra/src/objects/ai/ai.c +++ b/ad_astra/AdAstra/src/objects/ai/ai.c @@ -10,12 +10,15 @@ #include "../../util/random/random.h" #include "../../driver/display/display.h" + #define AI_ACTION_COUNT 5 - -typedef bool (*Predicate)(Rectangle*, Object*); +typedef bool (*Predicate)(Rectangle*, Object*, uint8_t); typedef void (*Execution)(Object*); +static uint8_t timeSinceLastAction; + + typedef struct { Predicate predicate; Execution execution; @@ -75,24 +78,41 @@ static void carefullyMoveSpaceship(Object* astronaut, Vec2 target) { } } -static bool shouldShootTurret( +static void makeAiAstronautDoAction(Object* astronaut) { + if (timeSinceLastAction > AI_ACTION_INTERVAL) { + makeAstronautDoAction(astronaut); + timeSinceLastAction = 0; + } +} + +static bool shouldControlTurret( __attribute__((unused)) Rectangle* boundingBox, - __attribute__((unused)) Object* astronaut + __attribute__((unused)) Object* astronaut, + __attribute__((unused)) uint8_t astronautId ) { - return getIntersectingObjectOfType( + return getCountOf(&Asteroid) > 0; +} + +static void executeControlTurret(Object* astronaut) { + if (getIntersectingObjectOfType( (Rectangle){ add(TURRET_POSITION, spaceshipObject->position), (Vec2){63, 1} }, &Asteroid - ); + )) { + makeAiAstronautDoAction(astronaut); + }; } static bool shouldControlSpaceship( __attribute__((unused)) Rectangle* boundingBox, - __attribute__((unused)) Object* astronaut + __attribute__((unused)) Object* astronaut, + uint8_t astronautId ) { - return getCountOf(&Asteroid) > 0; + return getCountOf(&Asteroid) > 0 + && astronautId == 1 + && spaceshipObject->as.spaceship.healthLoss < MAX_HEALTH / 4 * 3; } static void executeControlSpaceship(Object* astronaut) { @@ -105,7 +125,7 @@ static void executeControlSpaceship(Object* astronaut) { ); } -static bool shouldRepairSpaceship(Rectangle* boundingBox, Object* astronaut) { +static bool shouldRepairSpaceship(Rectangle* boundingBox, Object* astronaut, __attribute__((unused)) uint8_t astronautId) { return ( ( areIntersecting(*boundingBox, getBoundingBox(astronaut)) && @@ -115,9 +135,9 @@ static bool shouldRepairSpaceship(Rectangle* boundingBox, Object* astronaut) { ); } -static bool shouldCenterSpaceship(Rectangle* boundingBox, Object* astronaut) { +static bool shouldCenterSpaceship(Rectangle* boundingBox, Object* astronaut, __attribute__((unused)) uint8_t astronautId) { return ( - !actions[0].isSomeoneDoingThis && + !actions[1].isSomeoneDoingThis && ( areIntersecting(*boundingBox, getBoundingBox(astronaut)) || getCenter(getBoundingBox(spaceshipObject)).x != getCenter(WINDOW).x || @@ -135,7 +155,8 @@ static void executeCenterSpaceship(Object* astronaut) { static bool shouldSocialize( __attribute__((unused)) Rectangle* boundingBox, - __attribute__((unused)) Object* astronaut + __attribute__((unused)) Object* astronaut, + __attribute__((unused)) uint8_t astronautId ) { return true; } @@ -147,6 +168,13 @@ static void executeSocialize(Object* astronaut) { } static AIAction actions[AI_ACTION_COUNT] = { + (AIAction) { + .predicate = shouldRepairSpaceship, + .execution = makeAiAstronautDoAction, + .spaceshipPart = spaceshipParts + BEDS_INDEX, + .onlyOneAstronautCanDoIt = true, + .deltaCenter = {2, 0} + }, (AIAction) { .predicate = shouldControlSpaceship, .execution = executeControlSpaceship, @@ -155,15 +183,8 @@ static AIAction actions[AI_ACTION_COUNT] = { .deltaCenter = {-3, 0} }, (AIAction) { - .predicate = shouldRepairSpaceship, - .execution = makeAstronautDoAction, - .spaceshipPart = spaceshipParts + BEDS_INDEX, - .onlyOneAstronautCanDoIt = true, - .deltaCenter = {2, 0} - }, - (AIAction) { - .predicate = shouldShootTurret, - .execution = makeAstronautDoAction, + .predicate = shouldControlTurret, + .execution = executeControlTurret, .spaceshipPart = spaceshipParts + TURRET_CONTROLLER_INDEX, .onlyOneAstronautCanDoIt = true, .deltaCenter = {-3, 0} @@ -185,20 +206,24 @@ static AIAction actions[AI_ACTION_COUNT] = { }; void handleAI() { + timeSinceLastAction++; + uint8_t astronautCount = 0; for (uint8_t j = 0; j < ACTION_COUNT; j++) { actions[j].isSomeoneDoingThis = false; } for (uint8_t i = 0; i < OBJECT_COUNT; i++) { if (objects[i].prototype == &Astronaut && objects + i != character) { + astronautCount++; for (uint8_t j = 0; j < ACTION_COUNT; j++) { AIAction* currentAction = actions + j; Rectangle boundingBox = getBoundingBoxOfSpaceshipPart(currentAction->spaceshipPart); + Object* astronautIntersectingBoundingBox = getIntersectingObjectOfType(boundingBox, &Astronaut); if ( isSpaceshipPartActivated(currentAction->spaceshipPart) && (!currentAction->onlyOneAstronautCanDoIt || (!currentAction->isSomeoneDoingThis && astronautIntersectingBoundingBox != character)) && - currentAction->predicate(&boundingBox, objects + i) + currentAction->predicate(&boundingBox, objects + i, astronautCount) ) { if (!areIntersecting(boundingBox, getBoundingBox(objects + i))) { carefullyMoveAstronaut(objects + i, add(getCenter(boundingBox), currentAction->deltaCenter)); diff --git a/ad_astra/AdAstra/src/objects/ai/ai.h b/ad_astra/AdAstra/src/objects/ai/ai.h index 67092ca..756070c 100644 --- a/ad_astra/AdAstra/src/objects/ai/ai.h +++ b/ad_astra/AdAstra/src/objects/ai/ai.h @@ -1,6 +1,10 @@ #ifndef AI_H #define AI_H +// Between AI astronauts do actions +// there has to be at least this many frames +#define AI_ACTION_INTERVAL 30 + // If there are non player controlled astronauts // control them according to some basic rule set void handleAI(); diff --git a/ad_astra/AdAstra/src/objects/commands/commands.c b/ad_astra/AdAstra/src/objects/commands/commands.c index ae353de..c67f7e0 100644 --- a/ad_astra/AdAstra/src/objects/commands/commands.c +++ b/ad_astra/AdAstra/src/objects/commands/commands.c @@ -1,6 +1,7 @@ #include "commands.h" #include "../../objects/object_container/object_container.h" +#include "../../objects/types/spaceship/spaceship.h" #include "../../mediator/mediator.h" @@ -35,7 +36,7 @@ void handleCommands() { } else { commands.previous = next; } - + switch(next) { case increaseContrast: changeDisplayContrast(CONTRAST_STEP); @@ -55,6 +56,14 @@ void handleCommands() { case moveDown: moveAstronaut(character, directions[south]); break; + case reset: + destroySpaceship(); + commands.previous = noAction; + break; + case turnOff: + handleOff(); + commands.previous = noAction; + break; case action: makeAstronautDoAction(character); commands.previous = noAction; diff --git a/ad_astra/AdAstra/src/objects/commands/commands.h b/ad_astra/AdAstra/src/objects/commands/commands.h index d724398..22f57b9 100644 --- a/ad_astra/AdAstra/src/objects/commands/commands.h +++ b/ad_astra/AdAstra/src/objects/commands/commands.h @@ -1,6 +1,9 @@ #ifndef COMMANDS_H #define COMMANDS_H + +#include + // There can be no more than COMMAND_BUFFER_SIZE commands // waiting for processing simultaneously #define COMMAND_BUFFER_SIZE 8 @@ -15,6 +18,8 @@ typedef enum { noCommand = 0, repeat = 1, + turnOff = 61, + reset = 157, increaseContrast = 87, decreaseContrast = 31, moveUp = 231, diff --git a/ad_astra/AdAstra/src/objects/event_generator/event_generator.c b/ad_astra/AdAstra/src/objects/event_generator/event_generator.c index 8d0d886..fe214bf 100644 --- a/ad_astra/AdAstra/src/objects/event_generator/event_generator.c +++ b/ad_astra/AdAstra/src/objects/event_generator/event_generator.c @@ -45,7 +45,7 @@ static void generate(Prototype const* type, Predicate predicate) { bool generateAstronautPredicate(Rectangle* proposedBoundingBox) { return ( ( - (getCountOf(&Astronaut) == 1 && spaceshipObject->as.spaceship.progress >= hasTable) || + (getCountOf(&Astronaut) == 1 && spaceshipObject->as.spaceship.progress >= hasHalfCrew) || (getCountOf(&Astronaut) == 2 && spaceshipObject->as.spaceship.progress >= hasFullCrew) ) && getIntersectingObjectOfType(*proposedBoundingBox, &Astronaut) == NULL && diff --git a/ad_astra/AdAstra/src/objects/types/asteroid/asteroid.c b/ad_astra/AdAstra/src/objects/types/asteroid/asteroid.c index b0d58d0..519be3f 100644 --- a/ad_astra/AdAstra/src/objects/types/asteroid/asteroid.c +++ b/ad_astra/AdAstra/src/objects/types/asteroid/asteroid.c @@ -14,7 +14,7 @@ bool mineAsteroid(Object* asteroid) { return ++asteroid->as.asteroid.animationFrame == IDLE_FRAME_COUNT; } -static void tick(Object* asteroid, uint8_t previousFrameTime) { +static void tick(Object* asteroid, __attribute__((unused)) uint8_t previousFrameTime) { if (asteroid->as.asteroid.animationFrame < IDLE_FRAME_COUNT) { return; } diff --git a/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.c b/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.c index 86ad652..1b23109 100644 --- a/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.c +++ b/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.c @@ -66,7 +66,8 @@ void moveAstronaut(Object* astronaut, Vec2 direction) { setWasDoingAction(astronaut, false); if (getIsControllingSpaceship(astronaut)) { - moveSpaceship(direction); + moveSpaceship((Vec2){direction.x, 0}); + moveSpaceship((Vec2){0, direction.y}); } else { Vec2 proposedPosition = add(astronaut->position, direction); Rectangle proposedBoundingBox = (Rectangle){proposedPosition, getSize(astronaut)}; diff --git a/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.h b/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.h index 97e5df2..ac3ea48 100644 --- a/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.h +++ b/ad_astra/AdAstra/src/objects/types/astronaut/astronaut.h @@ -10,7 +10,7 @@ // Between two consecutive actions (or movements) // there has to be at least this many milliseconds -#define TIME_BETWEEN_ACTION_CHANGE 40 +#define TIME_BETWEEN_ACTION_CHANGE 50 typedef enum { noAction = 0, diff --git a/ad_astra/AdAstra/src/objects/types/background/background.c b/ad_astra/AdAstra/src/objects/types/background/background.c index fb5d46d..70e1c23 100644 --- a/ad_astra/AdAstra/src/objects/types/background/background.c +++ b/ad_astra/AdAstra/src/objects/types/background/background.c @@ -24,7 +24,7 @@ static Star createStarOnTheRight() { }; } -static void tick(Object* background, uint8_t previousFrameTime) { +static void tick(Object* background, __attribute__((unused)) uint8_t previousFrameTime) { background->as.background.movementState++; for (uint8_t i = 0; i < STAR_COUNT; i++) { switch (i % 3) { diff --git a/ad_astra/AdAstra/src/objects/types/bullet/bullet.c b/ad_astra/AdAstra/src/objects/types/bullet/bullet.c index ee5a373..6160cb6 100644 --- a/ad_astra/AdAstra/src/objects/types/bullet/bullet.c +++ b/ad_astra/AdAstra/src/objects/types/bullet/bullet.c @@ -9,7 +9,7 @@ -static void tick(Object* bullet, uint8_t previousFrameTime) { +static void tick(Object* bullet, __attribute__((unused)) uint8_t previousFrameTime) { if (bullet->as.bullet.wereIntersectingInThePreviousFrame) { clearObject(bullet); return; diff --git a/ad_astra/AdAstra/src/objects/types/heart/heart.c b/ad_astra/AdAstra/src/objects/types/heart/heart.c index da35d40..17a2f3e 100644 --- a/ad_astra/AdAstra/src/objects/types/heart/heart.c +++ b/ad_astra/AdAstra/src/objects/types/heart/heart.c @@ -8,7 +8,7 @@ #include "../../object_container/object_container.h" -static void tick(Object* heart, uint8_t previousFrameTime) { +static void tick(Object* heart, __attribute__((unused)) uint8_t previousFrameTime) { if (++heart->as.heart.timeSinceLastChange == HEART_ANIMATION_INTERVAL) { heart->as.heart.animationFrame = (heart->as.heart.animationFrame + 1) % HEART_FRAME_COUNT; heart->as.heart.timeSinceLastChange = 0; diff --git a/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.c b/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.c index c24aaf8..8ec1b8f 100644 --- a/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.c +++ b/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.c @@ -145,6 +145,14 @@ bool isSpaceshipPartActivated(SpaceshipPart* part) { return part->alwaysActiveDoNotDraw || ((spaceshipObject->as.spaceship.activatedParts >> (part - spaceshipParts)) & 1); } +bool isSpaceshipDestroyed() { + return spaceshipObject->as.spaceship.healthLoss >= MAX_HEALTH; +} + +void destroySpaceship() { + spaceshipObject->as.spaceship.healthLoss = MAX_HEALTH; +} + static inline void drawSpaceshipHealthBar() { uint8_t actualBarLength = spaceshipObject->as.spaceship.healthLoss * BAR_LENGTH / MAX_HEALTH; drawFilledRectangle( diff --git a/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.h b/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.h index df0aebe..0c28bba 100644 --- a/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.h +++ b/ad_astra/AdAstra/src/objects/types/spaceship/spaceship.h @@ -43,10 +43,11 @@ SpaceshipPart spaceshipParts[SPACESHIP_PART_COUNT]; const Prototype Spaceship; typedef enum { - hasBeds = 1, - hasTurret = 3, - hasTable = 5, - hasFullCrew = 9 + hasBeds = 2, + hasTurret = 5, + hasHalfCrew = 8, + hasFullCrew = 15, + hasTable = 25, } Progress; struct _spaceship_t { @@ -66,6 +67,9 @@ bool isOnLadder(Rectangle boundingBox); void onAsteroidMined(); bool isSpaceshipPartActivated(SpaceshipPart* part); +bool isSpaceshipDestroyed(); +void destroySpaceship(); + void shootTurretOfSpaceship(); Action getPossibleActionFromSpaceship(Object* astronaut); diff --git a/space_game/SpaceGame/src/driver/infra/infra.c b/space_game/SpaceGame/src/driver/infra/infra.c index e73fc1c..26a7c57 100644 --- a/space_game/SpaceGame/src/driver/infra/infra.c +++ b/space_game/SpaceGame/src/driver/infra/infra.c @@ -6,6 +6,7 @@ #include "bitwise.h" #include "../../hardware_access/hardware_access.h" #include "../uart/receive.h" +#include "../uart/transmit.h" // (0.5625 + (0.5625 + 1.6875) / 2) / 1000 / timer interval @@ -36,7 +37,7 @@ static void saveCurrentByte() { uint8_t byte = infra.current; infra.current = 0; infra.bitPosition = 0; - + if (byte == INFRA_ADDRESS) { infra.commandState = foundStartingByte; return; @@ -48,6 +49,7 @@ static void saveCurrentByte() { break; case significantByte: infra.onCommandReceived(byte); + sendUintOnUartAsync(byte); infra.commandState = waitingForEndOfCommand; break; case waitingForEndOfCommand: diff --git a/space_game/SpaceGame/src/driver/sleep/sleep.c b/space_game/SpaceGame/src/driver/sleep/sleep.c index 6efd706..27d34e0 100644 --- a/space_game/SpaceGame/src/driver/sleep/sleep.c +++ b/space_game/SpaceGame/src/driver/sleep/sleep.c @@ -20,6 +20,7 @@ void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds) { previousFrameTime = milisecondsSinceFrameStart; while (milisecondsSinceFrameStart < frameLengthInMilliseconds) { + clearBit(MCUCR, SM1); // idle mode sleep_cpu(); } @@ -27,6 +28,10 @@ void startFrameLoop(FrameFunction function, uint8_t frameLengthInMilliseconds) { } } +void powerOff() { + setBit(MCUCR, SM1); // power-down mode + sleep_cpu(); +} ISR(TIM0_COMPA_vect) { milisecondsSinceFrameStart++; diff --git a/space_game/SpaceGame/src/mediator/mediator.c b/space_game/SpaceGame/src/mediator/mediator.c index 39e28e1..b1ff516 100644 --- a/space_game/SpaceGame/src/mediator/mediator.c +++ b/space_game/SpaceGame/src/mediator/mediator.c @@ -45,11 +45,11 @@ static bool frameFunction(uint8_t previousFrameTime) { return false; }; } - + + tickObjects(previousFrameTime); handleCommands(); handleAI(); generateEvents(); - tickObjects(previousFrameTime); drawFrame(); return true; diff --git a/space_game/SpaceGame/src/mediator/mediator.h b/space_game/SpaceGame/src/mediator/mediator.h index d5aefa1..9fd7b02 100644 --- a/space_game/SpaceGame/src/mediator/mediator.h +++ b/space_game/SpaceGame/src/mediator/mediator.h @@ -4,8 +4,17 @@ #include +// Setup the drivers, and business layer objects and their relations +// It is kind of a very basic dependency injection. void setupConnections(); + +// Start drawing frames and ticking objects void startGame(); + +// Increase or decrease the contrast (brightness) of the display +// by the given value +// The contrast can be any number between 0 and 255. +// The function automatically clamps the contrast. void changeDisplayContrast(int8_t by); #endif diff --git a/space_game/SpaceGame/src/objects/ai/ai.c b/space_game/SpaceGame/src/objects/ai/ai.c index bafab52..94648ce 100644 --- a/space_game/SpaceGame/src/objects/ai/ai.c +++ b/space_game/SpaceGame/src/objects/ai/ai.c @@ -10,12 +10,15 @@ #include "../../util/random/random.h" #include "../../driver/display/display.h" -#define AI_ACTION_COUNT 5 +#define AI_ACTION_COUNT 5 typedef bool (*Predicate)(Rectangle*, Object*); typedef void (*Execution)(Object*); +static uint8_t timeSinceLastAction; + + typedef struct { Predicate predicate; Execution execution; @@ -70,29 +73,41 @@ static void carefullyMoveSpaceship(Object* astronaut, Vec2 target) { getCenter(getBoundingBox(spaceshipObject)) ) ); - moveAstronaut(astronaut, (Vec2){direction.x, 0}); - moveAstronaut(astronaut, (Vec2){0, direction.y}); + + moveAstronaut(astronaut, direction); } } -static bool shouldShootTurret( - __attribute__((unused)) Rectangle* boundingBox, +static void makeAiAstronautDoAction(Object* astronaut) { + timeSinceLastAction = 0; + makeAstronautDoAction(astronaut); +} + +static bool shouldControlTurret( + __attribute__((unused)) Rectangle* boundingBox, __attribute__((unused)) Object* astronaut ) { - return getIntersectingObjectOfType( + return getCountOf(&Asteroid) > 0; +} + +static void executeControlTurret(Object* astronaut) { + if (getIntersectingObjectOfType( (Rectangle){ add(TURRET_POSITION, spaceshipObject->position), (Vec2){63, 1} }, &Asteroid - ); + )) { + makeAiAstronautDoAction(astronaut); + }; } static bool shouldControlSpaceship( - __attribute__((unused)) Rectangle* boundingBox, + __attribute__((unused)) Rectangle* boundingBox, __attribute__((unused)) Object* astronaut ) { - return getCountOf(&Asteroid) > 0; + return getCountOf(&Asteroid) > 0 + && spaceshipObject->as.spaceship.healthLoss < MAX_HEALTH / 4 * 3; } static void executeControlSpaceship(Object* astronaut) { @@ -134,7 +149,7 @@ static void executeCenterSpaceship(Object* astronaut) { } static bool shouldSocialize( - __attribute__((unused)) Rectangle* boundingBox, + __attribute__((unused)) Rectangle* boundingBox, __attribute__((unused)) Object* astronaut ) { return true; @@ -156,14 +171,14 @@ static AIAction actions[AI_ACTION_COUNT] = { }, (AIAction) { .predicate = shouldRepairSpaceship, - .execution = makeAstronautDoAction, + .execution = makeAiAstronautDoAction, .spaceshipPart = spaceshipParts + BEDS_INDEX, .onlyOneAstronautCanDoIt = true, .deltaCenter = {2, 0} }, (AIAction) { - .predicate = shouldShootTurret, - .execution = makeAstronautDoAction, + .predicate = shouldControlTurret, + .execution = executeControlTurret, .spaceshipPart = spaceshipParts + TURRET_CONTROLLER_INDEX, .onlyOneAstronautCanDoIt = true, .deltaCenter = {-3, 0} @@ -185,6 +200,8 @@ static AIAction actions[AI_ACTION_COUNT] = { }; void handleAI() { + timeSinceLastAction++; + for (uint8_t j = 0; j < ACTION_COUNT; j++) { actions[j].isSomeoneDoingThis = false; } @@ -202,7 +219,7 @@ void handleAI() { ) { if (!areIntersecting(boundingBox, getBoundingBox(objects + i))) { carefullyMoveAstronaut(objects + i, add(getCenter(boundingBox), currentAction->deltaCenter)); - } else { + } else if (timeSinceLastAction > AI_ACTION_INTERVAL) { currentAction->execution(objects + i); } currentAction->isSomeoneDoingThis = true; diff --git a/space_game/SpaceGame/src/objects/ai/ai.h b/space_game/SpaceGame/src/objects/ai/ai.h index 67092ca..fa0a634 100644 --- a/space_game/SpaceGame/src/objects/ai/ai.h +++ b/space_game/SpaceGame/src/objects/ai/ai.h @@ -1,6 +1,10 @@ #ifndef AI_H #define AI_H +// Between AI astronauts do actions +// there has to be at least this many frames +#define AI_ACTION_INTERVAL 15 + // If there are non player controlled astronauts // control them according to some basic rule set void handleAI(); diff --git a/space_game/SpaceGame/src/objects/types/astronaut/astronaut.c b/space_game/SpaceGame/src/objects/types/astronaut/astronaut.c index dffa493..7188e93 100644 --- a/space_game/SpaceGame/src/objects/types/astronaut/astronaut.c +++ b/space_game/SpaceGame/src/objects/types/astronaut/astronaut.c @@ -66,8 +66,9 @@ void moveAstronaut(Object* astronaut, Vec2 direction) { setWasDoingAction(astronaut, false); if (getIsControllingSpaceship(astronaut)) { - moveSpaceship(direction); - } else { + moveSpaceship((Vec2){direction.x, 0}); + moveSpaceship((Vec2){0, direction.y}); + } else { Vec2 proposedPosition = add(astronaut->position, direction); Rectangle proposedBoundingBox = (Rectangle){proposedPosition, getSize(astronaut)}; if (isOnboard(proposedBoundingBox)) {