diff --git a/src/deh_tables.c b/src/deh_tables.c index 6d9c8c7f2..bd908e8b3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3281,6 +3281,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi //"S_ITEMCAPSULE_BOTTOM", //"S_ITEMCAPSULE_INSIDE", + "S_MAGICIANBOX", + "S_MAGICIANBOXTOP", + // Signpost sparkles "S_SIGNSPARK1", "S_SIGNSPARK2", @@ -5278,6 +5281,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_FLOATINGITEM", "MT_ITEMCAPSULE", "MT_ITEMCAPSULE_PART", + "MT_MAGICIANBOX", + "MT_MAGICIANBOX_SIDE", "MT_SIGNSPARKLE", diff --git a/src/info.c b/src/info.c index b1f4bc1be..0d8d3e462 100644 --- a/src/info.c +++ b/src/info.c @@ -542,6 +542,7 @@ char sprnames[NUMSPRITES + 1][5] = "KINF", // Invincibility flash "INVI", // Invincibility speedlines "ICAP", // Item capsules + "MGBX", // Heavy Magician transform box "WIPD", // Wipeout dust trail "DRIF", // Drift Sparks @@ -3888,6 +3889,9 @@ state_t states[NUMSTATES] = //{SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM //{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE + {SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX + {SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP + {SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3 @@ -22390,6 +22394,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_MAGICIANBOX + -1, // doomednum + S_MAGICIANBOX, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 26*FRACUNIT, // radius + 26*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_MAGICIANBOX_SIDE + -1, // doomednum + S_MAGICIANBOX, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 26*FRACUNIT, // radius + 14*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_SIGNSPARKLE -1, // doomednum S_SIGNSPARK1, // spawnstate diff --git a/src/info.h b/src/info.h index 176705a41..05caa8010 100644 --- a/src/info.h +++ b/src/info.h @@ -1088,6 +1088,7 @@ typedef enum sprite SPR_KINF, // Invincibility flash SPR_INVI, // Invincibility speedlines SPR_ICAP, // Item capsules + SPR_MGBX, // Heavy Magician transform box SPR_WIPD, // Wipeout dust trail SPR_DRIF, // Drift Sparks @@ -4292,6 +4293,9 @@ typedef enum state //S_ITEMCAPSULE_BOTTOM, //S_ITEMCAPSULE_INSIDE, + S_MAGICIANBOX, + S_MAGICIANBOX_TOP, + // Signpost sparkles S_SIGNSPARK1, S_SIGNSPARK2, @@ -6325,6 +6329,8 @@ typedef enum mobj_type MT_FLOATINGITEM, MT_ITEMCAPSULE, MT_ITEMCAPSULE_PART, + MT_MAGICIANBOX, + MT_MAGICIANBOX_SIDE, MT_SIGNSPARKLE, diff --git a/src/p_mobj.c b/src/p_mobj.c index bdf0064f0..cf58bf6c9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7609,6 +7609,96 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->renderflags = (mobj->renderflags & ~RF_TRANSMASK)|(trans << RF_TRANSSHIFT); } break; + case MT_MAGICIANBOX: + fixed_t destx, desty, fakeangle; + INT32 j; + + // EV1: rotation rate + // EV2: lifetime + // cusval: should play sounds (limit 1) + + mobj->extravalue2--; + + if (mobj->extravalue2 == 0) + { + P_RemoveMobj(mobj); + break; + } + else if (mobj->extravalue2 < TICRATE/3) + { + mobj->target = NULL; + if (mobj->extravalue2 & 1) + mobj->renderflags |= RF_DONTDRAW; + else + mobj->renderflags &= ~RF_DONTDRAW; + } + else if (mobj->extravalue2 == TICRATE/3 && mobj->target) + { + mobj->target->renderflags &= ~RF_DONTDRAW; + + if (mobj->cusval) // Are we the side selected to play a sound? + { + S_StartSound(mobj, sfx_kc2e); + S_StartSound(mobj, sfx_s3k9f); + } + + for (j = 0; j < 16; j++) + { + fixed_t hmomentum = P_RandomRange(PR_DECORATION, 3, 6) * mobj->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, 1, 3) * mobj->scale; + UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); + + angle_t ang = R_PointToAngle(mobj->target->momx, mobj->target->momy); + SINT8 flip = 1; + + mobj_t *dust; + + if (j & 1) + ang -= ANGLE_90; + else + ang += ANGLE_90; + + dust = P_SpawnMobjFromMobj(mobj, + FixedMul(mobj->radius, FINECOSINE(ang >> ANGLETOFINESHIFT)), + FixedMul(mobj->radius, FINESINE(ang >> ANGLETOFINESHIFT)), + mobj->target->height, (j%3 == 0) ? MT_SIGNSPARKLE : MT_SPINDASHDUST + ); + flip = P_MobjFlip(dust); + + dust->momx = mobj->target->momx + FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); + dust->momy = mobj->target->momy + FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); + dust->momz = vmomentum * flip; + dust->scale = dust->scale*4; + dust->frame |= FF_SUBTRACT|FF_TRANS90; + dust->color = color; + dust->colorized = true; + } + } + else + { + mobj->target->renderflags |= RF_DONTDRAW; + } + + if (!mobj->target || !mobj->target->health || !mobj->target->player) { + mobj->extravalue2 = min(mobj->extravalue2, TICRATE/3); + return true; + } + + mobj->extravalue1 += 1; + + mobj->angle += ANG1*mobj->extravalue1; + mobj->scale = mobj->target->scale; + + destx = mobj->target->x; + desty = mobj->target->y; + + fakeangle = (FixedInt(AngleFixed(mobj->angle)) + 90)%360; // What + + destx += FixedMul(mobj->radius*2, FINECOSINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + desty += FixedMul(mobj->radius*2, FINESINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + + P_MoveOrigin(mobj, destx, desty, mobj->target->z); + break; case MT_LIGHTNINGSHIELD: { fixed_t destx, desty; diff --git a/src/r_skins.c b/src/r_skins.c index 8688d8648..92299a9d2 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -360,15 +360,29 @@ void SetRandomFakePlayerSkin(player_t* player) if (player->mo) { S_StartSound(player->mo, sfx_kc33); + S_StartSound(player->mo, sfx_cdfm44); mobj_t *parent = player->mo; fixed_t rad = FixedDiv(FixedHypot(parent->radius, parent->radius), parent->scale); - INT32 j; + INT32 j, k; + + for (k = 0; k < 4; k++) + { + mobj_t *box = P_SpawnMobjFromMobj(parent, 0, 0, 0, MT_MAGICIANBOX); + box->target = parent; + box->angle = ANGLE_90 * k; + box->extravalue1 = 1; // Rotation rate + box->extravalue2 = 3*TICRATE/2; // Lifetime + if (k == 0) + box->cusval = 1; // Should play sounds when disappearing + else + box->cusval = 0; + } for (j = 0; j < 16; j++) { - fixed_t hmomentum = P_RandomRange(PR_DECORATION, 3, 6) * parent->scale; - fixed_t vmomentum = P_RandomRange(PR_DECORATION, 1, 3) * parent->scale; + fixed_t hmomentum = P_RandomRange(PR_DECORATION, 10, 20) * parent->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, 5, 10) * parent->scale; UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); angle_t ang = R_PointToAngle(parent->momx, parent->momy);