summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2022-12-10 13:43:21 -0800
committerVito Caputo <vcaputo@pengaru.com>2022-12-10 13:47:50 -0800
commit5ec2d49bdca3531f4baebc9a69b30ec4728b02a2 (patch)
tree00d67aa5dde68dc6ebbcd5b09586c6c58a804fca /src
parent90557841c9bc431506ab8f8a36f6572caab42391 (diff)
game: introduce MAGA powerup and MAGA mode for adult
The MAGA powerup appears only when the adult is captivated by the TV. It's technically not guaranteed to occur, but the propability is so high currently it's basically always going to appear when captivated. The current maga.ans is a MAGA hat, it comes up slowly but otherwise identically to the others like mask/tp etc. If you take the MAGA hat, the adult puts it on, discards any mask it's wearing, and the controls become inverted. Any subsequent mask pickups attempted simply discard the mask and continue maskless. Once in MAGA mode, there is no exiting MAGA mode until death.
Diffstat (limited to 'src')
-rw-r--r--src/game.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/game.c b/src/game.c
index b11c4b4..adc8932 100644
--- a/src/game.c
+++ b/src/game.c
@@ -23,6 +23,7 @@
#include <stage.h>
#include "adult-node.h"
+#include "adult-maga-node.h"
#include "adult-masked-node.h"
#include "baby-hatted-node.h"
#include "baby-node.h"
@@ -35,6 +36,7 @@
#include "m4f-3dx.h"
#include "m4f-bbx.h"
#include "macros.h"
+#include "maga-node.h"
#include "mask-node.h"
#include "plasma-node.h"
#include "sars.h"
@@ -50,6 +52,7 @@
#define GAME_VIRUS_SPEED .01f
#define GAME_ADULT_SPEED .05f
#define GAME_ADULT_ACCEL .25f
+#define GAME_MAGA_SPEED .01f
#define GAME_MASK_SPEED .02f
#define GAME_ENTITIES_DELAY_MS 20
@@ -80,6 +83,7 @@
#define GAME_ADULT_SCALE (v3f_t){ .07f, .07f, .07f }
#define GAME_BABY_SCALE (v3f_t){ .05f, .05f, .05f }
+#define GAME_MAGA_SCALE (v3f_t){ .0435f, .05f, .05f }
#define GAME_MASK_SCALE (v3f_t){ .04299f, .03f, .03f }
#define GAME_TEEPEE_SCALE (v3f_t){ .07f, .07f, .07f }
#define GAME_TEEPEE_ICON_SCALE (v3f_t){ .06f, .06f, .06f }
@@ -88,6 +92,7 @@
#define GAME_DIGITS_SCALE (v3f_t){ .05f, .05f, .05f }
#define GAME_TV_CHANCE .05f
+#define GAME_MAGA_CHANCE .75f /* XXX: MAGA only attempted when captivated by tv */
#define GAME_MASK_CHANCE .02f
#define GAME_TEEPEE_CHANCE .55f
@@ -112,6 +117,7 @@ typedef enum entity_type_t {
ENTITY_TYPE_ADULT,
ENTITY_TYPE_VIRUS,
ENTITY_TYPE_TV,
+ ENTITY_TYPE_MAGA,
ENTITY_TYPE_MASK,
ENTITY_TYPE_TEEPEE,
ENTITY_TYPE_TEEPEE_ICON,
@@ -133,6 +139,10 @@ struct entity_any_t {
unsigned flashes_remaining;
};
+typedef struct maga_t {
+ entity_any_t entity;
+} maga_t;
+
typedef struct mask_t {
entity_any_t entity;
} mask_t;
@@ -153,6 +163,7 @@ typedef struct adult_t {
entity_any_t entity;
unsigned rescues;
unsigned captivated:1;
+ unsigned maga:1;
unsigned masked;
entity_t *holding;
} adult_t;
@@ -177,6 +188,7 @@ union entity_t {
entity_any_t any;
adult_t adult;
baby_t baby;
+ maga_t maga;
mask_t mask;
teepee_t teepee;
tv_t tv;
@@ -212,6 +224,7 @@ typedef struct game_t {
adult_t *adult;
tv_t *tv;
+ maga_t *maga;
mask_t *mask;
teepee_t *teepee;
entity_t *new_infections;
@@ -294,6 +307,21 @@ static baby_t * baby_new(game_t *game, stage_t *parent, baby_t *rescue)
}
+static maga_t * maga_new(game_t *game, stage_t *parent)
+{
+ maga_t *maga;
+
+ maga = pad_get(game->pad, sizeof(entity_t));
+ fatal_if(!maga, "unable to allocate maga_t");
+
+ maga->entity.type = ENTITY_TYPE_MAGA;
+ maga->entity.node = maga_node_new(&(stage_conf_t){ .parent = parent, .name = "maga", .layer = 6, .alpha = 1.f }, &game->sars->projection_x, &maga->entity.model_x);
+ maga->entity.scale = GAME_MAGA_SCALE;
+
+ return maga;
+}
+
+
static mask_t * mask_new(game_t *game, stage_t *parent)
{
mask_t *mask;
@@ -394,8 +422,25 @@ static void hat_baby(game_t *game, baby_t *baby, mask_t *mask)
}
+static void maga_adult(game_t *game, adult_t *adult, maga_t *maga)
+{
+ (void) adult_maga_node_new(&(stage_conf_t){ .stage = adult->entity.node, .replace = 1, .name = "adult-maga", .active = 1, .alpha = 1.f }, &game->sars->projection_x, &adult->entity.model_x);
+
+ adult->maga = 1;
+ adult->masked = 0;
+ sfx_play(sfx.adult_maga);
+ stage_set_active(maga->entity.node, 0);
+}
+
+
static void mask_adult(game_t *game, adult_t *adult, mask_t *mask)
{
+ if (adult->maga) { /* MAGA discards masks */
+ stage_set_active(mask->entity.node, 0);
+
+ return sfx_play(sfx.adult_maga);
+ }
+
(void) adult_masked_node_new(&(stage_conf_t){ .stage = adult->entity.node, .replace = 1, .name = "adult-masked", .active = 1, .alpha = 1.f }, &game->sars->projection_x, &adult->entity.model_x);
adult->masked += GAME_MASK_PROTECTION;
@@ -497,6 +542,7 @@ static ix2_search_status_t baby_search(void *cb_context, ix2_object_t *ix2_objec
/* baby gets infected, return positive hit count */
return IX2_SEARCH_STOP_HIT;
+ case ENTITY_TYPE_MAGA:
case ENTITY_TYPE_TEEPEE:
case ENTITY_TYPE_TV:
return IX2_SEARCH_MORE_MISS;
@@ -527,6 +573,7 @@ static ix2_search_status_t teepee_search(void *cb_context, ix2_object_t *ix2_obj
case ENTITY_TYPE_TEEPEE: /* ignore self */
case ENTITY_TYPE_BABY:
+ case ENTITY_TYPE_MAGA:
case ENTITY_TYPE_MASK:
case ENTITY_TYPE_TV:
case ENTITY_TYPE_VIRUS: /* TODO: virus contaminates teepee? */
@@ -587,6 +634,7 @@ static ix2_search_status_t tv_search(void *cb_context, ix2_object_t *ix2_object,
case ENTITY_TYPE_VIRUS:
case ENTITY_TYPE_TV:
case ENTITY_TYPE_TEEPEE:
+ case ENTITY_TYPE_MAGA:
case ENTITY_TYPE_MASK:
return IX2_SEARCH_MORE_MISS;
@@ -596,6 +644,32 @@ static ix2_search_status_t tv_search(void *cb_context, ix2_object_t *ix2_object,
}
+static ix2_search_status_t maga_search(void *cb_context, ix2_object_t *ix2_object, v2f_t *ix2_object_position, bb2f_t *ix2_object_aabb, void *object)
+{
+ game_t *game = cb_context;
+ entity_t *entity = object;
+
+ switch (entity->any.type) {
+ case ENTITY_TYPE_ADULT:
+ if (stage_get_active(game->maga->entity.node))
+ maga_adult(game, &entity->adult, game->maga);
+
+ return IX2_SEARCH_STOP_HIT;
+
+ case ENTITY_TYPE_BABY:
+ case ENTITY_TYPE_MASK: /* ignore self */
+ case ENTITY_TYPE_MAGA:
+ case ENTITY_TYPE_TEEPEE:
+ case ENTITY_TYPE_TV:
+ case ENTITY_TYPE_VIRUS:
+ return IX2_SEARCH_MORE_MISS;
+
+ default:
+ assert(0);
+ }
+}
+
+
static ix2_search_status_t mask_search(void *cb_context, ix2_object_t *ix2_object, v2f_t *ix2_object_position, bb2f_t *ix2_object_aabb, void *object)
{
game_t *game = cb_context;
@@ -619,6 +693,7 @@ static ix2_search_status_t mask_search(void *cb_context, ix2_object_t *ix2_objec
return IX2_SEARCH_STOP_HIT;
case ENTITY_TYPE_MASK: /* ignore self */
+ case ENTITY_TYPE_MAGA:
case ENTITY_TYPE_TEEPEE:
case ENTITY_TYPE_TV:
case ENTITY_TYPE_VIRUS: /* TODO: virus contaminates mask? */
@@ -675,6 +750,7 @@ static ix2_search_status_t virus_search(void *cb_context, ix2_object_t *ix2_obje
return IX2_SEARCH_STOP_HIT;
case ENTITY_TYPE_MASK: /* TODO: virus contaminates mask? */
+ case ENTITY_TYPE_MAGA:
case ENTITY_TYPE_TEEPEE:
case ENTITY_TYPE_TV:
case ENTITY_TYPE_VIRUS:
@@ -708,6 +784,14 @@ static void update_entities(play_t *play, game_t *game)
stage_set_active(game->tv->entity.node, 1);
}
+ if (game->adult->captivated && randf() > (1.f - GAME_MAGA_CHANCE) && !stage_get_active(game->maga->entity.node)) {
+ /* sometimes activate a MAGA trap */
+ game->maga->entity.position.x = randf();
+ game->maga->entity.position.y = -1.2f;
+ entity_update_x(game, &game->maga->entity);
+ stage_set_active(game->maga->entity.node, 1);
+ }
+
if (randf() > (1.f - GAME_MASK_CHANCE) && !stage_get_active(game->mask->entity.node)) {
/* sometimes activate a mask powerup */
game->mask->entity.position.x = randf();
@@ -755,6 +839,18 @@ static void update_entities(play_t *play, game_t *game)
stage_set_active(game->teepee->entity.node, 1);
}
+ if (stage_get_active(game->maga->entity.node)) { /* if the maga is on, move it and possibly retire it */
+ game->maga->entity.position.y += GAME_MASK_SPEED;
+ entity_update_x(game, &game->maga->entity);
+
+ /* did it hit something? */
+ if (!ix2_search_by_aabb(game->ix2, NULL, NULL, &game->maga->entity.aabb_x, maga_search, game)) {
+ /* No?, is it off-screen? */
+ if (game->maga->entity.position.y > 1.2f)
+ stage_set_active(game->maga->entity.node, 0);
+ }
+ }
+
if (stage_get_active(game->mask->entity.node)) { /* if the mask is on, move it and possibly retire it */
game->mask->entity.position.y += GAME_MASK_SPEED;
entity_update_x(game, &game->mask->entity);
@@ -829,6 +925,7 @@ static void update_entities(play_t *play, game_t *game)
}
+/* this search return value is a gross count of hits, not just with viruses */
static ix2_search_status_t adult_search(void *cb_context, ix2_object_t *ix2_object, v2f_t *ix2_object_position, bb2f_t *ix2_object_aabb, void *object)
{
game_t *game = cb_context;
@@ -891,6 +988,15 @@ static ix2_search_status_t adult_search(void *cb_context, ix2_object_t *ix2_obje
return IX2_SEARCH_STOP_HIT;
+ case ENTITY_TYPE_MAGA:
+ if (!stage_get_active(entity->any.node))
+ return IX2_SEARCH_MORE_MISS;
+
+ /* maga the adult */
+ maga_adult(game, game->adult, &entity->maga);
+
+ return IX2_SEARCH_MORE_HIT;
+
case ENTITY_TYPE_MASK:
if (stage_get_active(entity->any.node))
mask_adult(game, game->adult, &entity->mask);
@@ -985,6 +1091,7 @@ static void reset_game(play_t *play, game_t *game)
game->rescues_head = NULL;
game->tv = tv_new(game, game->game_node);
game->teepee = teepee_new(game, game->game_node);
+ game->maga = maga_new(game, game->game_node);
game->mask = mask_new(game, game->game_node);
game->adult = adult_new(game, game->game_node);
for (int i = 0; i < NELEMS(game->viruses); i++)
@@ -1118,6 +1225,10 @@ static void game_update(play_t *play, void *context)
distance = v2f_length(move);
if (distance) {
*move = v2f_normalize(move);
+
+ if (game->adult->maga) /* MAGA goes the opposite direction */
+ *move = v2f_invert(move);
+
*move = v2f_mult_scalar(move, velocity * (distance < GAME_ADULT_SPEED ? distance : GAME_ADULT_SPEED));
}
© All Rights Reserved