From 52bf13367fe28cb171c7bdd391f6f1d3bdbf2346 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 16 Jun 2016 00:59:54 +0100 Subject: [PATCH 001/212] New rotation functionality. * NAMEcL refers to a frame which is seen for the entirety of an object's left side. * NAMEcR refers to a name which is seen for the entirety of an object's right side. * NAMEcLcR does both sides. * Having just a NAMEcL requires you to fill in the opposite side either with NAMEcn where n is 1 and 5 to 8 OR fill in with a NAMEcR * Switches down the centerline of the object instead of at the ANGLE_202h interval for normal sprites. * Characters were selected for 1) ease of use and 2) not getting in the way of adding support for zdoom's totally bananas 16-way sprite system at a later date if we so choose --- src/hardware/hw_main.c | 11 ++++++-- src/r_defs.h | 6 +++++ src/r_things.c | 57 ++++++++++++++++++++++++++++++++++-------- src/r_things.h | 9 +++++++ 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 35a01ffd1..aba89bdcd 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5095,8 +5095,15 @@ static void HWR_ProjectSprite(mobj_t *thing) if (sprframe->rotate) { // choose a different rotation based on player view - ang = R_PointToAngle(thing->x, thing->y); // uses viewx,viewy - rot = (ang-thing->angle+ANGLE_202h)>>29; + ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + + if ((ang < ANGLE_180) && (sprframe->rotate & 4)) // See from right + rot = 6; // F7 slot + else if ((ang >= ANGLE_180) && (sprframe->rotate & 2)) // See from left + rot = 2; // F3 slot + else // Normal behaviour + rot = (ang+ANGLE_202h)>>29; + //Fab: lumpid is the index for spritewidth,spriteoffset... tables lumpoff = sprframe->lumpid[rot]; flip = sprframe->flip & (1<= 64 || rotation > 8) + if (frame >= 64 || !(R_ValidSpriteAngle(rotation))) I_Error("R_InstallSpriteLump: Bad frame characters in lump %s", W_CheckNameForNum(lumppat)); if (maxframe ==(size_t)-1 || frame > maxframe) @@ -111,8 +111,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch // the lump should be used for all rotations if (sprtemp[frame].rotate == 0) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn); - - if (sprtemp[frame].rotate == 1) + else // Let's complain for both 1-8 and L/R rotations. CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); sprtemp[frame].rotate = 0; @@ -121,15 +120,46 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch sprtemp[frame].lumppat[r] = lumppat; sprtemp[frame].lumpid[r] = lumpid; } - sprtemp[frame].flip = flipped ? UINT8_MAX : 0; + sprtemp[frame].flip = flipped ? UINT8_MAX : 0; // 11111111 in binary + return; + } + + if (rotation == ROT_L || rotation == ROT_R) + { + UINT8 rightfactor = ((rotation == ROT_R) ? 4 : 0); + + // the lump should be used for half of all rotations + if (sprtemp[frame].rotate == 0) + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn); + else if (sprtemp[frame].rotate == 1) + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn); + // Let's not complain about multiple L/R rotations. It's not worth the effort. + + sprtemp[frame].rotate |= ((rotation == ROT_R) ? 4 : 2); + for (r = 0; r < 4; r++) + { + if ((r != 0) || (sprtemp[frame].lumppat[rotation] == LUMPERROR)) // Only set front/back angles if they don't exist + { + sprtemp[frame].lumppat[r + rightfactor] = lumppat; + sprtemp[frame].lumpid[r + rightfactor] = lumpid; + } + } + sprtemp[frame].flip |= (flipped ? (0x0F << rightfactor) : 0); // 00001111 or 11110000 in binary, depending on rotation being ROT_L or ROT_R return; } // the lump is only used for one rotation if (sprtemp[frame].rotate == 0) - CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8 rotations and a rot = 0 lump\n", spritename, cn); + else if (sprtemp[frame].rotate != 1) + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn); - sprtemp[frame].rotate = 1; + if (rotation == 0 || rotation == 4) // Front or back... + sprtemp[frame].rotate = 1; // Prevent L and R changeover + else if (rotation > 3) // Right side + sprtemp[frame].rotate = (1 | (sprtemp[frame].rotate & 2)); // Continue allowing L frame changeover + else // if (rotation <= 3) // Left side + sprtemp[frame].rotate = (1 | (sprtemp[frame].rotate & 4)); // Continue allowing R frame changeover // make 0 based rotation--; @@ -195,7 +225,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, frame = R_Char2Frame(lumpinfo[l].name[4]); rotation = (UINT8)(lumpinfo[l].name[5] - '0'); - if (frame >= 64 || rotation > 8) // Give an actual NAME error -_-... + if (frame >= 64 || !(R_ValidSpriteAngle(rotation))) // Give an actual NAME error -_-... { CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l)); continue; @@ -287,7 +317,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, // only the first rotation is needed break; - case 1: + default: // must have all 8 frames for (rotation = 0; rotation < 8; rotation++) // we test the patch lump, or the id lump whatever @@ -1132,8 +1162,15 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate) { // choose a different rotation based on player view - ang = R_PointToAngle (thing->x, thing->y); - rot = (ang-thing->angle+ANGLE_202h)>>29; + ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + + if ((ang < ANGLE_180) && (sprframe->rotate & 4)) // See from right + rot = 6; // F7 slot + else if ((ang >= ANGLE_180) && (sprframe->rotate & 2)) // See from left + rot = 2; // F3 slot + else // Normal behaviour + rot = (ang+ANGLE_202h)>>29; + //Fab: lumpid is the index for spritewidth,spriteoffset... tables lump = sprframe->lumpid[rot]; flip = sprframe->flip & (1< Date: Thu, 16 Jun 2016 01:20:35 +0100 Subject: [PATCH 002/212] Forgot to stage this, woops. Adds special casing to prevent the I_Error and makes the behaviour of the cL/cR more consistent in general such that it matches my description. --- src/r_things.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 4f1faae97..6e4f780b5 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -135,14 +135,14 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn); // Let's not complain about multiple L/R rotations. It's not worth the effort. + if (sprtemp[frame].rotate == 0xff) + sprtemp[frame].rotate = 0; + sprtemp[frame].rotate |= ((rotation == ROT_R) ? 4 : 2); - for (r = 0; r < 4; r++) + for (r = 1; r < 4; r++) // Don't set for front/back frames { - if ((r != 0) || (sprtemp[frame].lumppat[rotation] == LUMPERROR)) // Only set front/back angles if they don't exist - { - sprtemp[frame].lumppat[r + rightfactor] = lumppat; - sprtemp[frame].lumpid[r + rightfactor] = lumpid; - } + sprtemp[frame].lumppat[r + rightfactor] = lumppat; + sprtemp[frame].lumpid[r + rightfactor] = lumpid; } sprtemp[frame].flip |= (flipped ? (0x0F << rightfactor) : 0); // 00001111 or 11110000 in binary, depending on rotation being ROT_L or ROT_R return; @@ -317,6 +317,14 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, // only the first rotation is needed break; + case 6: // (rotate & (2|4)) == (2|4) - both Left and Right rotations + case 7: + // we test to see whether the left and right slots are present + if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR)) + I_Error("R_AddSingleSpriteDef: Sprite %s frame %c is missing rotations", + sprname, R_Frame2Char(frame)); + break; + default: // must have all 8 frames for (rotation = 0; rotation < 8; rotation++) From f08e996e761e169033cefca99bc64febfe3c1469 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 16 Jun 2016 01:37:48 +0100 Subject: [PATCH 003/212] MI corrections --- src/r_things.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 6e4f780b5..650b454ec 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -111,7 +111,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch // the lump should be used for all rotations if (sprtemp[frame].rotate == 0) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn); - else // Let's complain for both 1-8 and L/R rotations. + else if (sprtemp[frame].rotate != 0xff) // Let's complain for both 1-8 and L/R rotations. CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); sprtemp[frame].rotate = 0; @@ -154,6 +154,9 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch else if (sprtemp[frame].rotate != 1) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn); + // make 0 based + rotation--; + if (rotation == 0 || rotation == 4) // Front or back... sprtemp[frame].rotate = 1; // Prevent L and R changeover else if (rotation > 3) // Right side @@ -161,9 +164,6 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch else // if (rotation <= 3) // Left side sprtemp[frame].rotate = (1 | (sprtemp[frame].rotate & 4)); // Continue allowing R frame changeover - // make 0 based - rotation--; - if (sprtemp[frame].lumppat[rotation] != LUMPERROR) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, '1'+rotation); From 41b35a923f64961945c7a429ea67ecc5a3171b38 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 16 Jun 2016 14:20:03 +0100 Subject: [PATCH 004/212] Gave the new flag-based system for sprite angles actual flag names instead of relying on magic numbers. Also, I did a wee smidgen of reorganisation. --- src/hardware/hw_main.c | 20 +++++++-------- src/r_defs.h | 18 ++++++++----- src/r_things.c | 57 ++++++++++++++++++++++-------------------- 3 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index aba89bdcd..5dfb2d124 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5092,14 +5092,21 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif - if (sprframe->rotate) + if (sprframe->rotate == SRF_SINGLE) + { + // use single rotation for all views + rot = 0; //Fab: for vis->patch below + lumpoff = sprframe->lumpid[0]; //Fab: see note above + flip = sprframe->flip; // Will only be 0x00 or 0xFF + } + else { // choose a different rotation based on player view ang = R_PointToAngle (thing->x, thing->y) - thing->angle; - if ((ang < ANGLE_180) && (sprframe->rotate & 4)) // See from right + if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right rot = 6; // F7 slot - else if ((ang >= ANGLE_180) && (sprframe->rotate & 2)) // See from left + else if ((ang >= ANGLE_180) && (sprframe->rotate & SRF_LEFT)) // See from left rot = 2; // F3 slot else // Normal behaviour rot = (ang+ANGLE_202h)>>29; @@ -5108,13 +5115,6 @@ static void HWR_ProjectSprite(mobj_t *thing) lumpoff = sprframe->lumpid[rot]; flip = sprframe->flip & (1<patch below - lumpoff = sprframe->lumpid[0]; //Fab: see note above - flip = sprframe->flip; // Will only be 0x00 or 0xFF - } if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); diff --git a/src/r_defs.h b/src/r_defs.h index 2ff2cacf9..150c3fa58 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -729,11 +729,21 @@ typedef struct #pragma pack() #endif +typedef enum +{ + SRF_SINGLE = 0, // 0-angle for all rotations + SRF_3D = 1, // Angles 1-8 + SRF_LEFT = 2, // Left side has single patch + SRF_RIGHT = 4, // Right side has single patch + SRF_2D = 6, // SRF_LEFT|SRF_RIGHT + SRF_NONE = 0xff // Initial value +} spriterotateflags_t; // SRF's up! + // // Sprites are patches with a special naming convention so they can be // recognized by R_InitSprites. // The base name is NNNNFx or NNNNFxFx, with x indicating the rotation, -// x = 0, 1-7. +// x = 0, 1-8, L/R // The sprite and frame specified by a thing_t is range checked at run time. // A sprite is a patch_t that is assumed to represent a three dimensional // object and may have multiple rotations predrawn. @@ -745,13 +755,9 @@ typedef struct // typedef struct { - // If false use 0 for any position. - // If L is present, (rotate & 2) == 2. - // If R is present, (rotate & 4) == 4. - // Otherwise, use 1. // Note: as eight entries are available, we might as well insert the same // name eight times. - UINT8 rotate; + UINT8 rotate; // see spriterotateflags_t above // Lump to use for view angles 0-7. lumpnum_t lumppat[8]; // lump number 16 : 16 wad : lump diff --git a/src/r_things.c b/src/r_things.c index 650b454ec..1ea932b9a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -109,12 +109,12 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch if (rotation == 0) { // the lump should be used for all rotations - if (sprtemp[frame].rotate == 0) + if (sprtemp[frame].rotate == SRF_SINGLE) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn); - else if (sprtemp[frame].rotate != 0xff) // Let's complain for both 1-8 and L/R rotations. + else if (sprtemp[frame].rotate != SRF_NONE) // Let's complain for both 1-8 and L/R rotations. CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); - sprtemp[frame].rotate = 0; + sprtemp[frame].rotate = SRF_SINGLE; for (r = 0; r < 8; r++) { sprtemp[frame].lumppat[r] = lumppat; @@ -129,16 +129,20 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch UINT8 rightfactor = ((rotation == ROT_R) ? 4 : 0); // the lump should be used for half of all rotations - if (sprtemp[frame].rotate == 0) + if (sprtemp[frame].rotate == SRF_SINGLE) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn); - else if (sprtemp[frame].rotate == 1) + else if (sprtemp[frame].rotate == SRF_3D) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn); // Let's not complain about multiple L/R rotations. It's not worth the effort. - if (sprtemp[frame].rotate == 0xff) - sprtemp[frame].rotate = 0; + if (sprtemp[frame].rotate == SRF_NONE) + sprtemp[frame].rotate = SRF_SINGLE; + + sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT); + + if (sprtemp[frame].rotate == (SRF_3D|SRF_2D)) + sprtemp[frame].rotate = SRF_2D; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen. - sprtemp[frame].rotate |= ((rotation == ROT_R) ? 4 : 2); for (r = 1; r < 4; r++) // Don't set for front/back frames { sprtemp[frame].lumppat[r + rightfactor] = lumppat; @@ -149,20 +153,20 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch } // the lump is only used for one rotation - if (sprtemp[frame].rotate == 0) + if (sprtemp[frame].rotate == SRF_SINGLE) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8 rotations and a rot = 0 lump\n", spritename, cn); - else if (sprtemp[frame].rotate != 1) + else if ((sprtemp[frame].rotate != SRF_3D) && (sprtemp[frame].rotate != SRF_NONE)) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn); // make 0 based rotation--; if (rotation == 0 || rotation == 4) // Front or back... - sprtemp[frame].rotate = 1; // Prevent L and R changeover + sprtemp[frame].rotate = SRF_3D; // Prevent L and R changeover else if (rotation > 3) // Right side - sprtemp[frame].rotate = (1 | (sprtemp[frame].rotate & 2)); // Continue allowing L frame changeover + sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_LEFT)); // Continue allowing L frame changeover else // if (rotation <= 3) // Left side - sprtemp[frame].rotate = (1 | (sprtemp[frame].rotate & 4)); // Continue allowing R frame changeover + sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_RIGHT)); // Continue allowing R frame changeover if (sprtemp[frame].lumppat[rotation] != LUMPERROR) CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, '1'+rotation); @@ -308,17 +312,16 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, { switch (sprtemp[frame].rotate) { - case 0xff: + case SRF_NONE: // no rotations were found for that frame at all I_Error("R_AddSingleSpriteDef: No patches found for %s frame %c", sprname, R_Frame2Char(frame)); break; - case 0: + case SRF_SINGLE: // only the first rotation is needed break; - case 6: // (rotate & (2|4)) == (2|4) - both Left and Right rotations - case 7: + case SRF_2D: // both Left and Right rotations // we test to see whether the left and right slots are present if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR)) I_Error("R_AddSingleSpriteDef: Sprite %s frame %c is missing rotations", @@ -1167,14 +1170,21 @@ static void R_ProjectSprite(mobj_t *thing) I_Error("R_ProjectSprite: sprframes NULL for sprite %d\n", thing->sprite); #endif - if (sprframe->rotate) + if (sprframe->rotate == SRF_SINGLE) + { + // use single rotation for all views + rot = 0; //Fab: for vis->patch below + lump = sprframe->lumpid[0]; //Fab: see note above + flip = sprframe->flip; // Will only be 0x00 or 0xFF + } + else { // choose a different rotation based on player view ang = R_PointToAngle (thing->x, thing->y) - thing->angle; - if ((ang < ANGLE_180) && (sprframe->rotate & 4)) // See from right + if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right rot = 6; // F7 slot - else if ((ang >= ANGLE_180) && (sprframe->rotate & 2)) // See from left + else if ((ang >= ANGLE_180) && (sprframe->rotate & SRF_LEFT)) // See from left rot = 2; // F3 slot else // Normal behaviour rot = (ang+ANGLE_202h)>>29; @@ -1183,13 +1193,6 @@ static void R_ProjectSprite(mobj_t *thing) lump = sprframe->lumpid[rot]; flip = sprframe->flip & (1<patch below - lump = sprframe->lumpid[0]; //Fab: see note above - flip = sprframe->flip; // Will only be 0x00 or 0xFF - } I_Assert(lump < max_spritelumps); From 2a74ea07eeef1dcff6e8bd287756c6f8055d7bdb Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 22 Aug 2016 22:54:30 +0100 Subject: [PATCH 005/212] Chee wanted paper sprites' code, so here it is for the public to see. Note: Won't compile. Need to merge in the NAMEcLcR stuff first, let me do that. --- src/dehacked.c | 4 +- src/m_cheat.c | 2 +- src/p_enemy.c | 18 +++--- src/p_inter.c | 2 +- src/p_mobj.c | 30 ++++------ src/p_mobj.h | 5 +- src/p_pspr.h | 4 +- src/p_user.c | 8 +-- src/r_things.c | 158 +++++++++++++++++++++++++++++++++++++------------ src/r_things.h | 3 +- 10 files changed, 160 insertions(+), 74 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index f03dd73b4..c31c22643 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6642,7 +6642,7 @@ static const char *const MOBJFLAG_LIST[] = { "SHOOTABLE", "NOSECTOR", "NOBLOCKMAP", - "AMBUSH", + "PAPERCOLLISION", "PUSHABLE", "BOSS", "SPAWNCEILING", @@ -6700,6 +6700,7 @@ static const char *const MOBJFLAG2_LIST[] = { "BOSSNOTRAP", // No Egg Trap after boss "BOSSFLEE", // Boss is fleeing! "BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) + "AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH NULL }; @@ -6992,6 +6993,7 @@ struct { // Frame settings {"FF_FRAMEMASK",FF_FRAMEMASK}, + {"FF_PAPERSPRITE",FF_PAPERSPRITE}, {"FF_ANIMATE",FF_ANIMATE}, {"FF_FULLBRIGHT",FF_FULLBRIGHT}, {"FF_TRANSMASK",FF_TRANSMASK}, diff --git a/src/m_cheat.c b/src/m_cheat.c index 89334596e..f49930b2c 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1054,7 +1054,7 @@ void OP_NightsObjectplace(player_t *player) if (!OP_HeightOkay(player, false)) return; - if (player->mo->target->flags & MF_AMBUSH) + if (player->mo->target->flags2 & MF2_AMBUSH) angle = (UINT16)player->anotherflyangle; else { diff --git a/src/p_enemy.c b/src/p_enemy.c index 025a25973..b98412bbf 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2625,7 +2625,7 @@ for (i = cvar.value; i; --i) spawnchance[numchoices++] = type newbox = spawnchance[P_RandomKey(numchoices)]; item = mobjinfo[newbox].damage; - remains->flags &= ~MF_AMBUSH; + remains->flags2 &= ~MF2_AMBUSH; break; } default: @@ -3444,7 +3444,7 @@ void A_BubbleSpawn(mobj_t *actor) } actor->flags2 &= ~MF2_DONTDRAW; - if (!(actor->flags & MF_AMBUSH)) + if (!(actor->flags2 & MF2_AMBUSH)) { // Quick! Look through players! // Don't spawn bubbles unless a player is relatively close by (var2). @@ -3492,7 +3492,7 @@ void A_FanBubbleSpawn(mobj_t *actor) if (!(actor->eflags & MFE_UNDERWATER)) return; - if (!(actor->flags & MF_AMBUSH)) + if (!(actor->flags2 & MF2_AMBUSH)) { // Quick! Look through players! // Don't spawn bubbles unless a player is relatively close by (var2). @@ -4038,7 +4038,7 @@ void A_JetChase(mobj_t *actor) return; #endif - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -4931,7 +4931,7 @@ void A_SlingAppear(mobj_t *actor) if (firsttime) { // This is the outermost link in the chain - spawnee->flags |= MF_AMBUSH; + spawnee->flags2 |= MF2_AMBUSH; firsttime = false; } @@ -5916,7 +5916,7 @@ void A_Boss2Chase(mobj_t *actor) { actor->watertop = -actor->watertop; actor->extravalue1 = 18; - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2; actor->extravalue2 = actor->extravalue1; } @@ -5942,7 +5942,7 @@ void A_Boss2Chase(mobj_t *actor) else { // Only speed up if you have the 'Deaf' flag. - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) speedvar = actor->health; else speedvar = actor->info->spawnhealth; @@ -6533,7 +6533,7 @@ void A_BuzzFly(mobj_t *actor) if (LUA_CallAction("A_BuzzFly", actor)) return; #endif - if (actor->flags & MF_AMBUSH) + if (actor->flags2 & MF2_AMBUSH) return; if (actor->reactiontime) @@ -6673,7 +6673,7 @@ void A_GuardChase(mobj_t *actor) return; // got a new target // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, (actor->flags & MF_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) + if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) { P_NewChaseDir(actor); actor->movecount += 5; // Increase tics before change in direction allowed. diff --git a/src/p_inter.c b/src/p_inter.c index cf5512a18..aa0fce5c0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1327,7 +1327,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_SMALLMACECHAIN: case MT_BIGMACECHAIN: // Is this the last link in the chain? - if (toucher->momz > 0 || !(special->flags & MF_AMBUSH) + if (toucher->momz > 0 || !(special->flags2 & MF2_AMBUSH) || (player->pflags & PF_ITEMHANG) || (player->pflags & PF_MACESPIN)) return; diff --git a/src/p_mobj.c b/src/p_mobj.c index 62dee0a67..eed2f3c02 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2466,7 +2466,7 @@ static boolean P_ZMovement(mobj_t *mo) && abs(mom.y) < FixedMul(STOPSPEED, mo->scale) && abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale)) { - if (mo->flags & MF_AMBUSH) + if (mo->flags2 & MF2_AMBUSH) { // If deafed, give the tumbleweed another random kick if it runs out of steam. mom.z += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale); @@ -6392,7 +6392,7 @@ void P_MobjThinker(mobj_t *mobj) flame->angle = mobj->angle; - if (mobj->flags & MF_AMBUSH) // Wave up and down instead of side-to-side + if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side flame->momz = mobj->fuse << (FRACBITS-2); else flame->angle += FixedAngle(mobj->fuse*FRACUNIT); @@ -6427,7 +6427,7 @@ void P_MobjThinker(mobj_t *mobj) strength -= ((20*FRACUNIT)/16)*mobj->movedir; // If deaf'd, the object spawns on the ceiling. - if (mobj->flags & MF_AMBUSH) + if (mobj->flags2 & MF2_AMBUSH) { mobj->z = mobj->ceilingz-mobj->height; flame->momz = -strength; @@ -7283,7 +7283,7 @@ void P_MobjThinker(mobj_t *mobj) case MT_EGGMANBOX: // Eggman box case MT_GRAVITYBOX: // Gravity box case MT_QUESTIONBOX: - if ((mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) + if ((mobj->flags2 & MF2_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) { mobjtype_t spawnchance[64]; INT32 numchoices = 0, i = 0; @@ -7311,11 +7311,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s i = P_RandomKey(numchoices); // Gotta love those random numbers! newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); - // If the monitor respawns randomly, transfer the flag. - if (mobj->flags & MF_AMBUSH) - newmobj->flags |= MF_AMBUSH; - - // Transfer flags2 (strongbox, objectflip) + // Transfer flags2 (strongbox, objectflip, ambush) newmobj->flags2 = mobj->flags2; } else @@ -9132,7 +9128,7 @@ ML_NOCLIMB : Direction not controllable if (firsttime) { // This is the outermost link in the chain - spawnee->flags |= MF_AMBUSH; + spawnee->flags2 |= MF2_AMBUSH; firsttime = false; } @@ -9204,7 +9200,7 @@ ML_NOCLIMB : Direction not controllable { // Inverted if uppermost bit is set if (mthing->angle & 16384) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; if (mthing->angle > 0) mobj->radius = (mthing->angle & 16383)*FRACUNIT; @@ -9381,7 +9377,7 @@ ML_NOCLIMB : Direction not controllable mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum || mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum || mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; } else if (mthing->type != mobjinfo[MT_AXIS].doomednum && @@ -9389,7 +9385,7 @@ ML_NOCLIMB : Direction not controllable mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum && mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum && mthing->type != mobjinfo[MT_STARPOST].doomednum) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; } if (mthing->options & MTF_OBJECTSPECIAL) @@ -9728,7 +9724,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) P_SetMobjState(mobj, mobj->info->seestate); mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; mthing->mobj = mobj; } // All manners of rings and coins @@ -9802,7 +9798,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) } mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; mthing->mobj = mobj; } // *** @@ -9858,7 +9854,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if (mthing->options & MTF_AMBUSH) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; } } // Diagonal rings (handles both types) @@ -9916,7 +9912,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if (mthing->options & MTF_AMBUSH) - mobj->flags |= MF_AMBUSH; + mobj->flags2 |= MF2_AMBUSH; } } // Rings of items (all six of them) diff --git a/src/p_mobj.h b/src/p_mobj.h index 79cffae89..c8207c564 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -107,8 +107,8 @@ typedef enum MF_NOSECTOR = 1<<3, // Don't use the blocklinks (inert but displayable) MF_NOBLOCKMAP = 1<<4, - // Not to be activated by sound, deaf monster. - MF_AMBUSH = 1<<5, + // Thin, paper-like collision bound (for visual equivalent, see FF_PAPERSPRITE) + MF_PAPERCOLLISION = 1<<5, // You can push this object. It can activate switches and things by pushing it on top. MF_PUSHABLE = 1<<6, // Object is a boss. @@ -193,6 +193,7 @@ typedef enum MF2_BOSSNOTRAP = 1<<25, // No Egg Trap after boss MF2_BOSSFLEE = 1<<26, // Boss is fleeing! MF2_BOSSDEAD = 1<<27, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) + MF2_AMBUSH = 1<<28, // Alternate behaviour typically set by MTF_AMBUSH // free: to and including 1<<31 } mobjflag2_t; diff --git a/src/p_pspr.h b/src/p_pspr.h index 2fb232e73..c0064bc3e 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -36,7 +36,9 @@ #endif /// \brief Frame flags: only the frame number -#define FF_FRAMEMASK 0x3fff +#define FF_FRAMEMASK 0x1ff +/// \brief Frame flags: Thin, paper-like sprite (for collision equivalent, see MF_PAPERCOLLISION) +#define FF_PAPERSPRITE 0x800 /// \brief Frame flags: Simple stateless animation #define FF_ANIMATE 0x4000 /// \brief Frame flags: frame always appears full bright diff --git a/src/p_user.c b/src/p_user.c index 9cd6aa401..6bf8753ba 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -629,7 +629,7 @@ static void P_DeNightserizePlayer(player_t *player) if (!(mo2->type == MT_NIGHTSDRONE)) continue; - if (mo2->flags & MF_AMBUSH) + if (mo2->flags2 & MF2_AMBUSH) P_DamageMobj(player->mo, NULL, NULL, 10000); break; @@ -4931,7 +4931,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad boolean transfer1last = false; boolean transfer2last = false; vertex_t vertices[4]; - fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags & MF_AMBUSH ? -1 : 1); + fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags2 & MF2_AMBUSH ? -1 : 1); // Find next waypoint for (th = thinkercap.next; th != &thinkercap; th = th->next) @@ -5596,7 +5596,7 @@ static void P_NiGHTSMovement(player_t *player) // The 'ambush' flag says you should rotate // the other way around the axis. - if (player->mo->target->flags & MF_AMBUSH) + if (player->mo->target->flags2 & MF2_AMBUSH) backwardaxis = true; player->angle_pos = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); @@ -7931,7 +7931,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else if (player->mo->target) { - if (player->mo->target->flags & MF_AMBUSH) + if (player->mo->target->flags2 & MF2_AMBUSH) angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); else angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y); diff --git a/src/r_things.c b/src/r_things.c index 22551a02d..84dff7182 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -754,11 +754,18 @@ static void R_DrawVisSprite(vissprite_t *vis) if (overflow_test < 0) overflow_test = -overflow_test; if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow + if (vis->scalestep) // handles right edge too + { + overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*(vis->scale + (vis->scalestep*(vis->x2 - vis->x1))))>>FRACBITS); + if (overflow_test < 0) overflow_test = -overflow_test; + if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // ditto + } + colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" { - // translate green skin to another color + // translate certain pixels to white colfunc = transcolfunc; if (vis->mobj->type == MT_CYBRAKDEMON) dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); @@ -814,13 +821,10 @@ static void R_DrawVisSprite(vissprite_t *vis) if (!dc_colormap) dc_colormap = colormaps; - dc_iscale = FixedDiv(FRACUNIT, vis->scale); dc_texturemid = vis->texturemid; dc_texheight = 0; frac = vis->startfrac; - spryscale = vis->scale; - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); windowtop = windowbottom = sprbotscreen = INT32_MAX; if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) @@ -832,28 +836,29 @@ static void R_DrawVisSprite(vissprite_t *vis) if (!vis->isScaled) { vis->scale = FixedMul(vis->scale, this_scale); - spryscale = vis->scale; - dc_iscale = FixedDiv(FRACUNIT, vis->scale); + vis->scalestep = FixedMul(vis->scalestep, this_scale); vis->xiscale = FixedDiv(vis->xiscale,this_scale); vis->isScaled = true; } dc_texturemid = FixedDiv(dc_texturemid,this_scale); + } - //Oh lordy, mercy me. Don't freak out if sprites go offscreen! - /*if (vis->xiscale > 0) - frac = FixedDiv(frac, this_scale); - else if (vis->x1 <= 0) - frac = (vis->x1 - vis->x2) * vis->xiscale;*/ + spryscale = vis->scale; + if (!(vis->scalestep)) + { sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - //dc_hires = 1; + dc_iscale = FixedDiv(FRACUNIT, vis->scale); } x1 = vis->x1; x2 = vis->x2; if (vis->x1 < 0) + { + spryscale += vis->scalestep*(-vis->x1); vis->x1 = 0; + } if (vis->x2 >= vid.width) vis->x2 = vid.width-1; @@ -869,10 +874,16 @@ static void R_DrawVisSprite(vissprite_t *vis) #else column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); #endif + if (vis->scalestep) + { + sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); + dc_iscale = (0xffffffffu / (unsigned)spryscale); + } if (vis->vflip) R_DrawFlippedMaskedColumn(column, patch->height); else R_DrawMaskedColumn(column); + spryscale += vis->scalestep; } colfunc = basecolfunc; @@ -967,7 +978,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) if (testheight <= sprite->gz) return; - cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->scale))>>FRACBITS); + cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->sortscale))>>FRACBITS); if (cutfrac < 0) continue; if (cutfrac > viewheight) @@ -1040,7 +1051,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t tr_x, tr_y; fixed_t gxt, gyt; fixed_t tx, tz; - fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! + fixed_t xscale, yscale, sortscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! INT32 x1, x2; @@ -1057,6 +1068,9 @@ static void R_ProjectSprite(mobj_t *thing) angle_t ang; fixed_t iscale; + fixed_t scalestep; // toast '16 + fixed_t offset, offset2; + boolean papersprite = (thing->frame & FF_PAPERSPRITE); //SoM: 3/17/2000 fixed_t gz, gzt; @@ -1064,6 +1078,8 @@ static void R_ProjectSprite(mobj_t *thing) INT32 light = 0; fixed_t this_scale = thing->scale; + fixed_t ang_scale = FRACUNIT; + // transform the origin point tr_x = thing->x - viewx; tr_y = thing->y - viewy; @@ -1074,7 +1090,7 @@ static void R_ProjectSprite(mobj_t *thing) tz = gxt-gyt; // thing is behind view plane? - if (tz < FixedMul(MINZ, this_scale)) + if (!(papersprite) && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later return; gxt = -FixedMul(tr_x, viewsin); @@ -1087,7 +1103,7 @@ static void R_ProjectSprite(mobj_t *thing) // aspect ratio stuff xscale = FixedDiv(projection, tz); - yscale = FixedDiv(projectiony, tz); + sortscale = FixedDiv(projectiony, tz); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -1129,10 +1145,17 @@ static void R_ProjectSprite(mobj_t *thing) I_Error("R_ProjectSprite: sprframes NULL for sprite %d\n", thing->sprite); #endif + if (sprframe->rotate != SRF_SINGLE || papersprite) + { + ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + if (papersprite) + ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT)); + } + if (sprframe->rotate) { // choose a different rotation based on player view - ang = R_PointToAngle (thing->x, thing->y); + //ang = R_PointToAngle (thing->x, thing->y); rot = (ang-thing->angle+ANGLE_202h)>>29; //Fab: lumpid is the index for spritewidth,spriteoffset... tables lump = sprframe->lumpid[rot]; @@ -1153,22 +1176,77 @@ static void R_ProjectSprite(mobj_t *thing) // calculate edges of the shape if (flip) - tx -= FixedMul(spritecachedinfo[lump].width-spritecachedinfo[lump].offset, this_scale); + offset = spritecachedinfo[lump].offset - spritecachedinfo[lump].width; else - tx -= FixedMul(spritecachedinfo[lump].offset, this_scale); + offset = -spritecachedinfo[lump].offset; + offset = FixedMul(offset, this_scale); + tx += FixedMul(offset, ang_scale); x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS; // off the right side? if (x1 > viewwidth) return; - tx += FixedMul(spritecachedinfo[lump].width, this_scale); + offset2 = FixedMul(spritecachedinfo[lump].width, this_scale); + tx += FixedMul(offset2, ang_scale); x2 = ((centerxfrac + FixedMul (tx,xscale)) >>FRACBITS) - 1; // off the left side if (x2 < 0) return; + if (papersprite) + { + fixed_t yscale2, cosmul, sinmul, tz2; + INT32 range; + + if (ang >= ANGLE_180) + { + offset *= -1; + offset2 *= -1; + } + + cosmul = FINECOSINE(thing->angle>>ANGLETOFINESHIFT); + sinmul = FINESINE(thing->angle>>ANGLETOFINESHIFT); + + tr_x += FixedMul(offset, cosmul); + tr_y += FixedMul(offset, sinmul); + gxt = FixedMul(tr_x, viewcos); + gyt = -FixedMul(tr_y, viewsin); + tz = gxt-gyt; + yscale = FixedDiv(projectiony, tz); + if (yscale < 64) return; // Fix some funky visuals + + tr_x += FixedMul(offset2, cosmul); + tr_y += FixedMul(offset2, sinmul); + gxt = FixedMul(tr_x, viewcos); + gyt = -FixedMul(tr_y, viewsin); + tz2 = gxt-gyt; + yscale2 = FixedDiv(projectiony, tz2); + if (yscale2 < 64) return; // ditto + + if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier + return; + + if (x2 > x1) + range = (x2 - x1); + else + range = 1; + + scalestep = (yscale2 - yscale)/range; + + // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? + // sortscale = max(yscale, yscale2); + // sortscale = min(yscale, yscale2); + } + else + { + scalestep = 0; + yscale = sortscale; + } + + xscale = FixedMul(xscale, ang_scale); + // PORTAL SPRITE CLIPPING if (portalrender) { @@ -1250,6 +1328,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->heightsec = heightsec; //SoM: 3/17/2000 vis->mobjflags = thing->flags; vis->scale = yscale; //<sortscale = sortscale; vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15 vis->gx = thing->x; vis->gy = thing->y; @@ -1259,6 +1338,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->pz = thing->z; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; + vis->scalestep = scalestep; vis->mobj = thing; // Easy access! Tails 06-07-2002 @@ -1276,8 +1356,8 @@ static void R_ProjectSprite(mobj_t *thing) vis->xscale = xscale; //SoM: 4/17/2000 vis->sector = thing->subsector->sector; - vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS); - vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, yscale))>>FRACBITS); + vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); + vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); vis->cut = SC_NONE; if (thing->subsector->sector->numlights) vis->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap; @@ -1298,7 +1378,10 @@ static void R_ProjectSprite(mobj_t *thing) } if (vis->x1 > x1) + { vis->startfrac += FixedDiv(vis->xiscale, this_scale)*(vis->x1-x1); + vis->scale += scalestep*(vis->x1 - x1); + } //Fab: lumppat is the lump number of the patch to use, this is different // than lumpid for sprites-in-pwad : the graphics are patched @@ -1457,7 +1540,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // store information in a vissprite vis = R_NewVisSprite(); - vis->scale = yscale; //<scale = vis->sortscale = yscale; //<dispoffset = 0; // Monster Iestyn: 23/11/15 vis->gx = thing->x; vis->gy = thing->y; @@ -1467,6 +1550,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->pz = thing->z; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; + vis->scalestep = 0; vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; @@ -1645,14 +1729,14 @@ void R_SortVisSprites(void) bestscale = bestdispoffset = INT32_MAX; for (ds = unsorted.next; ds != &unsorted; ds = ds->next) { - if (ds->scale < bestscale) + if (ds->sortscale < bestscale) { - bestscale = ds->scale; + bestscale = ds->sortscale; bestdispoffset = ds->dispoffset; best = ds; } // order visprites of same scale by dispoffset, smallest first - else if (ds->scale == bestscale && ds->dispoffset < bestdispoffset) + else if (ds->sortscale == bestscale && ds->dispoffset < bestdispoffset) { bestdispoffset = ds->dispoffset; best = ds; @@ -1814,7 +1898,7 @@ static void R_CreateDrawNodes(void) for (i = x1; i <= x2; i++) { - if (r2->seg->frontscale[i] > rover->scale) + if (r2->seg->frontscale[i] > rover->sortscale) break; } if (i > x2) @@ -1833,10 +1917,10 @@ static void R_CreateDrawNodes(void) continue; scale = r2->thickseg->scale1 > r2->thickseg->scale2 ? r2->thickseg->scale1 : r2->thickseg->scale2; - if (scale <= rover->scale) + if (scale <= rover->sortscale) continue; scale = r2->thickseg->scale1 + (r2->thickseg->scalestep * (sintersect - r2->thickseg->x1)); - if (scale <= rover->scale) + if (scale <= rover->sortscale) continue; #ifdef ESLOPE @@ -1886,11 +1970,11 @@ static void R_CreateDrawNodes(void) continue; scale = r2->seg->scale1 > r2->seg->scale2 ? r2->seg->scale1 : r2->seg->scale2; - if (scale <= rover->scale) + if (scale <= rover->sortscale) continue; scale = r2->seg->scale1 + (r2->seg->scalestep * (sintersect - r2->seg->x1)); - if (rover->scale < scale) + if (rover->sortscale < scale) { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -1906,8 +1990,8 @@ static void R_CreateDrawNodes(void) if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt) continue; - if (r2->sprite->scale > rover->scale - || (r2->sprite->scale == rover->scale && r2->sprite->dispoffset > rover->dispoffset)) + if (r2->sprite->sortscale > rover->sortscale + || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset)) { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2060,8 +2144,8 @@ void R_ClipSprites(void) scale = ds->scale2; } - if (scale < spr->scale || - (lowscale < spr->scale && + if (scale < spr->sortscale || + (lowscale < spr->sortscale && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) { // masked mid texture? @@ -2112,7 +2196,7 @@ void R_ClipSprites(void) fixed_t mh, h; INT32 phs = viewplayer->mo->subsector->sector->heightsec; if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && - (h = centeryfrac - FixedMul(mh -= viewz, spr->scale)) >= 0 && + (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && (h >>= FRACBITS) < viewheight) { if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) @@ -2130,7 +2214,7 @@ void R_ClipSprites(void) } if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && - (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && + (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && (h >>= FRACBITS) < viewheight) { if (phs != -1 && viewz >= sectors[phs].ceilingheight) diff --git a/src/r_things.h b/src/r_things.h index 483db7e99..9a4ba1999 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -131,7 +131,8 @@ typedef struct vissprite_s fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors fixed_t startfrac; // horizontal position of x1 - fixed_t scale; + fixed_t scale, sortscale; // sortscale only differs from scale for flat sprites + fixed_t scalestep; // only for flat sprites, 0 otherwise fixed_t xiscale; // negative if flipped fixed_t texturemid; From e42885a23c971c4bc8e38b4a87c522fd424e55a3 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 22 Aug 2016 23:01:36 +0100 Subject: [PATCH 006/212] Forgot to do this. --- src/r_things.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_things.c b/src/r_things.c index a7f3fa41d..0d85a4631 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1203,7 +1203,7 @@ static void R_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + //ang = R_PointToAngle (thing->x, thing->y) - thing->angle; if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right rot = 6; // F7 slot From e8d65f0b5481643b77a35551cd24e8c0cb821759 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 22 Aug 2016 23:39:27 +0100 Subject: [PATCH 007/212] GCC 4.6 and lower fix --- src/r_things.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_things.c b/src/r_things.c index 0d85a4631..55866759d 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1107,7 +1107,7 @@ static void R_ProjectSprite(mobj_t *thing) vissprite_t *vis; - angle_t ang; + angle_t ang = 0; // gcc 4.6 and lower fix fixed_t iscale; fixed_t scalestep; // toast '16 fixed_t offset, offset2; From 14ff3906e138aa459e73600e3be916b9d5b167b9 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 23 Aug 2016 00:45:26 +0100 Subject: [PATCH 008/212] Woops, forgot to port collision as well. --- src/p_map.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/p_map.c b/src/p_map.c index 1f2d903e8..a95ed6b8d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -469,6 +469,73 @@ static boolean PIT_CheckThing(mobj_t *thing) if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) return true; // didn't hit it + if (thing->flags & MF_PAPERCOLLISION) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing. + { + fixed_t cosradius, sinradius; + vertex_t v1, v2; // fake vertexes + line_t junk; // fake linedef + cosradius = FixedMul(thing->radius, FINECOSINE(thing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(thing->radius, FINESINE(thing->angle>>ANGLETOFINESHIFT)); + + v1.x = thing->x - cosradius; + v1.y = thing->y - sinradius; + v2.x = thing->x + cosradius; + v2.y = thing->y + sinradius; + + junk.v1 = &v1; + junk.v2 = &v2; + junk.dx = v2.x - v1.x; + junk.dy = v2.y - v1.y; + + if (tmthing->flags & MF_PAPERCOLLISION) // more strenuous checking to prevent clipping issues + { + INT32 check1, check2, check3, check4; + cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); + check1 = P_PointOnLineSide(tmx - cosradius, tmy - sinradius, &junk); + check2 = P_PointOnLineSide(tmx + cosradius, tmy + sinradius, &junk); + check3 = P_PointOnLineSide(tmx + tmthing->momx - cosradius, tmy + tmthing->momy - sinradius, &junk); + check4 = P_PointOnLineSide(tmx + tmthing->momx + cosradius, tmy + tmthing->momy + sinradius, &junk); + if ((check1 == check2) && (check2 == check3) && (check3 == check4)) + return true; // the line doesn't cross between collider's start or end + } + else + { + if ((P_PointOnLineSide(tmx - tmthing->radius, tmy - tmthing->radius, &junk) + == P_PointOnLineSide(tmx + tmthing->radius, tmy + tmthing->radius, &junk)) + && (P_PointOnLineSide(tmx + tmthing->radius, tmy - tmthing->radius, &junk) + == P_PointOnLineSide(tmx - tmthing->radius, tmy + tmthing->radius, &junk))) + return true; // the line doesn't cross between either pair of opposite corners + } + } + else if (tmthing->flags & MF_PAPERCOLLISION) + { + fixed_t cosradius, sinradius; + vertex_t v1, v2; // fake vertexes + line_t junk; // fake linedef + + cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); + + v1.x = tmx - cosradius; + v1.y = tmy - sinradius; + v2.x = tmx + cosradius; + v2.y = tmy + sinradius; + + junk.v1 = &v1; + junk.v2 = &v2; + junk.dx = v2.x - v1.x; + junk.dy = v2.y - v1.y; + + // no need to check whether thing has MF_PAPERCOLLISION, since checked above + + if ((P_PointOnLineSide(thing->x - thing->radius, thing->y - thing->radius, &junk) + == P_PointOnLineSide(thing->x + thing->radius, thing->y + thing->radius, &junk)) + && (P_PointOnLineSide(thing->x + thing->radius, thing->y - thing->radius, &junk) + == P_PointOnLineSide(thing->x - thing->radius, thing->y + thing->radius, &junk))) + return true; // the line doesn't cross between either pair of opposite corners + } + #ifdef HAVE_BLUA { UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type @@ -1123,6 +1190,17 @@ static boolean PIT_CheckLine(line_t *ld) if (P_BoxOnLineSide(tmbbox, ld) != -1) return true; +if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. + { + fixed_t cosradius, sinradius; + cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); + if (P_PointOnLineSide(tmx - cosradius, tmy - sinradius, ld) + == P_PointOnLineSide(tmx + cosradius, tmy + sinradius, ld)) + return true; // the line doesn't cross between collider's start or end + + } + // A line has been hit // The moving thing's destination position will cross From a587231aa4f85dcade73fd5ccdb2dd8c5429c947 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 26 Aug 2016 22:00:53 +0100 Subject: [PATCH 009/212] Crash fix ported from internal. --- src/r_things.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_things.c b/src/r_things.c index 55866759d..8e41fb447 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -143,7 +143,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch if (sprtemp[frame].rotate == (SRF_3D|SRF_2D)) sprtemp[frame].rotate = SRF_2D; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen. - for (r = 1; r < 4; r++) // Don't set for front/back frames + for (r = 0; r < 4; r++) // Thanks to R_PrecacheLevel, we can't leave sprtemp[*].lumppat[*] == LUMPERROR... so we load into the front/back angle too. { sprtemp[frame].lumppat[r + rightfactor] = lumppat; sprtemp[frame].lumpid[r + rightfactor] = lumpid; From 39d4f22660b6957e3e70a483bf7624edcbf90842 Mon Sep 17 00:00:00 2001 From: Sryder Date: Tue, 13 Dec 2016 21:02:23 +0000 Subject: [PATCH 010/212] Flat sprites for OGL --- src/hardware/hw_glob.h | 1 + src/hardware/hw_main.c | 77 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 94eef1d3e..5d1a81d4f 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -78,6 +78,7 @@ typedef struct gr_vissprite_s //Hurdler: 25/04/2000: now support colormap in hardware mode UINT8 *colormap; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing + float z1, z2; } gr_vissprite_t; // -------- diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 70520af8d..98ab6cab2 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4223,6 +4223,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); + //const boolean papersprite = (spr->mobj && (spr->mobj->frame & FF_PAPERSPRITE)); if (spr->mobj) this_scale = FIXED_TO_FLOAT(spr->mobj->scale); if (hires) @@ -4266,7 +4267,28 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // make a wall polygon (with 2 triangles), using the floor/ceiling heights, // and the 2d map coords of start/end vertices - wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz; + wallVerts[0].z = wallVerts[3].z = spr->z1; + wallVerts[2].z = wallVerts[1].z = spr->z2; + + // transform + wv = wallVerts; + + /*if (spr->mobj->frame & FF_PAPERSPRITE) + { + float mobjanglecos, mobjanglesin; + mobjanglesin = FIXED_TO_FLOAT(FINESINE((spr->mobj->angle-dup_viewangle+ANGLE_90)>>ANGLETOFINESHIFT)); + mobjanglecos = FIXED_TO_FLOAT(FINECOSINE((spr->mobj->angle-dup_viewangle+ANGLE_90)>>ANGLETOFINESHIFT)); + for (i = 0; i < 4; i++,wv++) + { + // x = (x * anglecos) + (z * anglesin) + // z = (x * anglesin) - (z * anglecos) + // instead of doing the z part we just add spr->tz afterwards because they are all the same + // value right now + tr_x = wv->x-spr->x2+(spr->x2-spr->x1)/2; + //wv->x = (tr_x * mobjanglecos) + (0) + (spr->x1+(spr->x2-spr->x1)/2); + wv->z = (tr_x * mobjanglesin) - (0) + (spr->tz); + } + }*/ // transform wv = wallVerts; @@ -5042,6 +5064,10 @@ static void HWR_ProjectSprite(mobj_t *thing) UINT8 flip; angle_t ang; INT32 heightsec, phs; + const boolean papersprite = (thing->frame & FF_PAPERSPRITE); + float offset; + float ang_scale = 1.0f, ang_scalez = 0.0f; + float z1, z2; if (!thing) return; @@ -5056,7 +5082,7 @@ static void HWR_ProjectSprite(mobj_t *thing) tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin); // thing is behind view plane? - if (tz < ZCLIP_PLANE && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear + if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear return; tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos); @@ -5094,6 +5120,16 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif + if (sprframe->rotate != SRF_SINGLE || papersprite) + { + ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + if (papersprite) + { + ang_scale = FIXED_TO_FLOAT(FINESINE(ang>>ANGLETOFINESHIFT)); + ang_scalez = FIXED_TO_FLOAT(FINECOSINE(ang>>ANGLETOFINESHIFT)); + } + } + if (sprframe->rotate == SRF_SINGLE) { // use single rotation for all views @@ -5104,8 +5140,6 @@ static void HWR_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; - if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right rot = 6; // F7 slot else if ((ang >= ANGLE_180) && (sprframe->rotate & SRF_LEFT)) // See from left @@ -5123,9 +5157,20 @@ static void HWR_ProjectSprite(mobj_t *thing) // calculate edges of the shape if (flip) - tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale; + offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale; else - tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale; + offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale; + + if (ang_scale < 0) + { + z1 = tz + offset * ang_scalez; + tx += offset * ang_scale; + } + else + { + z1 = tz - offset * ang_scalez; + tx -= offset * ang_scale; + } // project x x1 = gr_windowcenterx + (tx * gr_centerx / tz); @@ -5136,9 +5181,25 @@ static void HWR_ProjectSprite(mobj_t *thing) x1 = tx; - tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale; + offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale; + if (ang_scale < 0) + { + z2 = z1 - offset * ang_scalez; + tx -= offset * ang_scale; + } + else + { + z2 = z1 + offset * ang_scalez; + tx += offset * ang_scale; + } + if (papersprite && max(z1, z1) < ZCLIP_PLANE) + return; + x2 = gr_windowcenterx + (tx * gr_centerx / tz); + + + if (thing->eflags & MFE_VERTICALFLIP) { gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; @@ -5185,6 +5246,8 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->patchlumpnum = sprframe->lumppat[rot]; vis->flip = flip; vis->mobj = thing; + vis->z1 = z1; + vis->z2 = z2; //Hurdler: 25/04/2000: now support colormap in hardware mode if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" From 4fb2a188465bc9ef5fc5450b55b3cdcc8b49215d Mon Sep 17 00:00:00 2001 From: Sryder Date: Tue, 13 Dec 2016 21:18:05 +0000 Subject: [PATCH 011/212] Fix a one character bug with clipping --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 98ab6cab2..d0f67b876 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5192,7 +5192,7 @@ static void HWR_ProjectSprite(mobj_t *thing) z2 = z1 + offset * ang_scalez; tx += offset * ang_scale; } - if (papersprite && max(z1, z1) < ZCLIP_PLANE) + if (papersprite && max(z1, z2) < ZCLIP_PLANE) return; x2 = gr_windowcenterx + (tx * gr_centerx / tz); From 2e72539df24e16bc7e3d0007876c445a91dd1025 Mon Sep 17 00:00:00 2001 From: Sryder Date: Tue, 13 Dec 2016 21:22:40 +0000 Subject: [PATCH 012/212] Remove accidental leftovers Accidentally left a comment and stuff in there from previous attempts --- src/hardware/hw_main.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d0f67b876..d4255ba42 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4273,26 +4273,6 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // transform wv = wallVerts; - /*if (spr->mobj->frame & FF_PAPERSPRITE) - { - float mobjanglecos, mobjanglesin; - mobjanglesin = FIXED_TO_FLOAT(FINESINE((spr->mobj->angle-dup_viewangle+ANGLE_90)>>ANGLETOFINESHIFT)); - mobjanglecos = FIXED_TO_FLOAT(FINECOSINE((spr->mobj->angle-dup_viewangle+ANGLE_90)>>ANGLETOFINESHIFT)); - for (i = 0; i < 4; i++,wv++) - { - // x = (x * anglecos) + (z * anglesin) - // z = (x * anglesin) - (z * anglecos) - // instead of doing the z part we just add spr->tz afterwards because they are all the same - // value right now - tr_x = wv->x-spr->x2+(spr->x2-spr->x1)/2; - //wv->x = (tr_x * mobjanglecos) + (0) + (spr->x1+(spr->x2-spr->x1)/2); - wv->z = (tr_x * mobjanglesin) - (0) + (spr->tz); - } - }*/ - - // transform - wv = wallVerts; - for (i = 0; i < 4; i++,wv++) { //look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -5197,9 +5177,6 @@ static void HWR_ProjectSprite(mobj_t *thing) x2 = gr_windowcenterx + (tx * gr_centerx / tz); - - - if (thing->eflags & MFE_VERTICALFLIP) { gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; From 8290ae9fd4c9d86bee6de503dd5158a34fc389c4 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 13 May 2017 12:49:30 +0100 Subject: [PATCH 013/212] Fix paper sprites apparently "turning" around sometimes when you turn the camera, when they're supposed to be still (sawb.wad for instance) I cleaned up some of Sryder's changes a little too I guess --- src/hardware/hw_main.c | 47 ++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 386e997de..a40a2827d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5122,15 +5122,26 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif - if (sprframe->rotate != SRF_SINGLE || papersprite) + if (papersprite) { - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; - if (papersprite) + // Use the actual view angle, rather than the angle formed + // between the view point and the thing + // this makes sure paper sprites always appear at the right angle! + // Note: DO NOT do this in software mode version, it actually + // makes papersprites look WORSE there (I know, I've tried) + // Monster Iestyn - 13/05/17 + ang = dup_viewangle - thing->angle; + ang_scale = FIXED_TO_FLOAT(FINESINE(ang>>ANGLETOFINESHIFT)); + ang_scalez = FIXED_TO_FLOAT(FINECOSINE(ang>>ANGLETOFINESHIFT)); + + if (ang_scale < 0) { - ang_scale = FIXED_TO_FLOAT(FINESINE(ang>>ANGLETOFINESHIFT)); - ang_scalez = FIXED_TO_FLOAT(FINECOSINE(ang>>ANGLETOFINESHIFT)); + ang_scale = -ang_scale; + ang_scalez = -ang_scalez; } } + else if (sprframe->rotate != SRF_SINGLE) + ang = R_PointToAngle (thing->x, thing->y) - thing->angle; if (sprframe->rotate == SRF_SINGLE) { @@ -5163,16 +5174,8 @@ static void HWR_ProjectSprite(mobj_t *thing) else offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale; - if (ang_scale < 0) - { - z1 = tz + offset * ang_scalez; - tx += offset * ang_scale; - } - else - { - z1 = tz - offset * ang_scalez; - tx -= offset * ang_scale; - } + z1 = tz - (offset * ang_scalez); + tx -= offset * ang_scale; // project x x1 = gr_windowcenterx + (tx * gr_centerx / tz); @@ -5184,16 +5187,10 @@ static void HWR_ProjectSprite(mobj_t *thing) x1 = tx; offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale; - if (ang_scale < 0) - { - z2 = z1 - offset * ang_scalez; - tx -= offset * ang_scale; - } - else - { - z2 = z1 + offset * ang_scalez; - tx += offset * ang_scale; - } + + z2 = z1 + (offset * ang_scalez); + tx += offset * ang_scale; + if (papersprite && max(z1, z2) < ZCLIP_PLANE) return; From 6877930ed9f1b52c76117c64a9215ea0a51d49c9 Mon Sep 17 00:00:00 2001 From: Sryder13 Date: Fri, 8 Sep 2017 00:56:58 +0100 Subject: [PATCH 014/212] Go through and draw MD2s and sprites at the same time so they are sorted from each other (mostly) correctly --- src/hardware/hw_main.c | 67 ++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 05391f4d0..f38e67ce6 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4914,7 +4914,8 @@ static void HWR_CreateDrawNodes(void) // Draw all vissprites // -------------------------------------------------------------------------- #ifdef SORTING -static void HWR_DrawSprites(void) +// added the stransform so they can be switched as drawing happenes so MD2s and sprites are sorted correctly with each other +static void HWR_DrawSprites(FTransform *stransform) { if (gr_visspritecount > 0) { @@ -4933,45 +4934,33 @@ static void HWR_DrawSprites(void) if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { if (!cv_grmd2.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) + { + HWD.pfnSetTransform(stransform); HWR_DrawSprite(spr); - } - else if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) - HWR_DrawSprite(spr); - } - } -} -#endif -// -------------------------------------------------------------------------- -// Draw all MD2 -// -------------------------------------------------------------------------- -static void HWR_DrawMD2S(void) -{ - if (gr_visspritecount > 0) - { - gr_vissprite_t *spr; - - // draw all MD2 back to front - for (spr = gr_vsprsortedhead.next; - spr != &gr_vsprsortedhead; - spr = spr->next) - { -#ifdef HWPRECIP - if (!spr->precip) - { -#endif - if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) - { - if (md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false && md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f) + } + else + { + HWD.pfnSetTransform(&atransform); HWR_DrawMD2(spr); + } + } + else + { + if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) + { + HWD.pfnSetTransform(stransform); + HWR_DrawSprite(spr); + } + else + { + HWD.pfnSetTransform(&atransform); + HWR_DrawMD2(spr); + } } - else if (md2_models[spr->mobj->sprite].notfound == false && md2_models[spr->mobj->sprite].scale > 0.0f) - HWR_DrawMD2(spr); -#ifdef HWPRECIP - } -#endif } } } +#endif // -------------------------------------------------------------------------- // HWR_AddSprites @@ -5644,12 +5633,9 @@ if (0) #ifdef SORTING HWR_SortVisSprites(); #endif - HWR_DrawMD2S(); - // Draw the sprites with trivial transform - HWD.pfnSetTransform(&stransform); #ifdef SORTING - HWR_DrawSprites(); + HWR_DrawSprites(&stransform); #endif #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? @@ -5874,12 +5860,9 @@ if (0) #ifdef SORTING HWR_SortVisSprites(); #endif - HWR_DrawMD2S(); - // Draw the sprites with trivial transform - HWD.pfnSetTransform(&stransform); #ifdef SORTING - HWR_DrawSprites(); + HWR_DrawSprites(&stransform); #endif #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? From db99537a6b67f2942c08680787a7215844770f87 Mon Sep 17 00:00:00 2001 From: Sryder13 Date: Sat, 9 Sep 2017 00:41:11 +0100 Subject: [PATCH 015/212] Various Transparent Texture Fixes Draw Textures and Flats that have holes in them like a solid polygon so they use the depth buffer and don't need to be sorted Disable all linear filtering on textures and flats that have holes in them, the linear filtering introduces translucency into the textures where the edges are. Leaving them with either a black border, or causing pixels behind the slightly translucent areas to not be drawn. Doesn't apply to sprites and the HUD as they are always already sorted properly. Make the Alpha Testing more strict on non-translucent blend modes. This makes it so any transparency below 0.5 is discarded instead. Would make anything that is blended and has holes in it look slightly better, only the HUD and MD2s where the texture has holes are effected currently. Set TF_TRANSPARENT on flat texture flags when there are holes in the texture. Minor fix to make sure MD2s always set the right blend mode --- src/hardware/hw_main.c | 30 +++++------------ src/hardware/r_opengl/r_opengl.c | 57 ++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f38e67ce6..971789122 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1072,7 +1072,6 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, /* SoM: split up and light walls according to the lightlist. This may also include leaving out parts of the wall that can't be seen */ - GLTexture_t * glTex; float realtop, realbot, top, bot; float pegt, pegb, pegmul; @@ -1238,11 +1237,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[0].y = wallVerts[1].y = bot; #endif - glTex = HWR_GetTexture(texnum); + //glTex = HWR_GetTexture(texnum); if (cutflag & FF_TRANSLUCENT) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); - else if (glTex->mipmap.flags & TF_TRANSPARENT) - HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Environment, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap); @@ -1298,11 +1295,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[0].y = wallVerts[1].y = bot; #endif - glTex = HWR_GetTexture(texnum); + //glTex = HWR_GetTexture(texnum); if (cutflag & FF_TRANSLUCENT) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); - else if (glTex->mipmap.flags & TF_TRANSPARENT) - HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Environment, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap); } @@ -2033,15 +2028,14 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } #endif - if (grTex->mipmap.flags & TF_TRANSPARENT) - blendmode = PF_Translucent; - if (gr_frontsector->numlights) { if (!(blendmode & PF_Masked)) HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_TRANSLUCENT); else + { HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS); + } } else if (!(blendmode & PF_Masked)) HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, blendmode, false, lightnum, colormap); @@ -2338,15 +2332,11 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { FBITFIELD blendmode = PF_Masked; - if (rover->flags & FF_TRANSLUCENT) + if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { blendmode = PF_Translucent; Surf.FlatColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; } - else if (grTex->mipmap.flags & TF_TRANSPARENT) - { - blendmode = PF_Environment; - } if (gr_frontsector->numlights) HWR_SplitWall(gr_frontsector, wallVerts, texnum, &Surf, rover->flags); @@ -2461,15 +2451,11 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { FBITFIELD blendmode = PF_Masked; - if (rover->flags & FF_TRANSLUCENT) + if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { blendmode = PF_Translucent; Surf.FlatColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; } - else if (grTex->mipmap.flags & TF_TRANSPARENT) - { - blendmode = PF_Environment; - } if (gr_backsector->numlights) HWR_SplitWall(gr_backsector, wallVerts, texnum, &Surf, rover->flags); @@ -3575,7 +3561,7 @@ static void HWR_Subsector(size_t num) alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } - else if (rover->flags & FF_TRANSLUCENT) // SoM: Flags are more efficient + else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient { light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); #ifndef SORTING @@ -3638,7 +3624,7 @@ static void HWR_Subsector(size_t num) alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } - else if (rover->flags & FF_TRANSLUCENT) + else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); #ifndef SORTING diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index e6ff83e89..80df8afba 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1056,30 +1056,48 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) switch (PolyFlags & PF_Blending) { case PF_Translucent & PF_Blending: pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency +#ifndef KOS_GL_COMPATIBILITY + pglAlphaFunc(GL_NOTEQUAL, 0.0f); +#endif break; case PF_Masked & PF_Blending: // Hurdler: does that mean lighting is only made by alpha src? // it sounds ok, but not for polygonsmooth pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture +#ifndef KOS_GL_COMPATIBILITY + pglAlphaFunc(GL_GREATER, 0.5f); +#endif break; case PF_Additive & PF_Blending: #ifdef ATI_RAGE_PRO_COMPATIBILITY pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency #else pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest +#endif +#ifndef KOS_GL_COMPATIBILITY + pglAlphaFunc(GL_NOTEQUAL, 0.0f); #endif break; case PF_Environment & PF_Blending: pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +#ifndef KOS_GL_COMPATIBILITY + pglAlphaFunc(GL_NOTEQUAL, 0.0f); +#endif break; case PF_Substractive & PF_Blending: // good for shadow // not realy but what else ? pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); +#ifndef KOS_GL_COMPATIBILITY + pglAlphaFunc(GL_NOTEQUAL, 0.0f); +#endif break; default : // must be 0, otherwise it's an error // No blending pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending +#ifndef KOS_GL_COMPATIBILITY + pglAlphaFunc(GL_GREATER, 0.5f); +#endif break; } } @@ -1339,6 +1357,7 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) tex[w*j+i].s.green = 0; tex[w*j+i].s.blue = 0; tex[w*j+i].s.alpha = 0; + pTexInfo->flags |= TF_TRANSPARENT; // there is a hole in it } else { @@ -1409,8 +1428,22 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) tex_downloaded = pTexInfo->downloaded; pglBindTexture(GL_TEXTURE_2D, pTexInfo->downloaded); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); + // disable texture filtering on any texture that has holes so there's no dumb borders or blending issues + if (pTexInfo->flags & TF_TRANSPARENT) + { +#ifdef KOS_GL_COMPATIBILITY + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NONE); +#else + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +#endif + } + else + { + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); + } #ifdef KOS_GL_COMPATIBILITY pglTexImage2D(GL_TEXTURE_2D, 0, GL_ARGB4444, w, h, 0, GL_ARGB4444, GL_UNSIGNED_BYTE, ptex); @@ -1865,12 +1898,6 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration ambient[1] = 0.75f; if (ambient[2] > 0.75f) ambient[2] = 0.75f; - - if (color[3] < 255) - { - pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - pglDepthMask(GL_FALSE); - } } pglEnable(GL_CULL_FACE); @@ -1897,10 +1924,12 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration pglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient); pglMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); #endif + if (color[3] < 255) + SetBlend(PF_Translucent|PF_Modulated|PF_Clip); + else + SetBlend(PF_Masked|PF_Modulated|PF_Occlude|PF_Clip); } - DrawPolygon(NULL, NULL, 0, PF_Masked|PF_Modulated|PF_Occlude|PF_Clip); - pglPushMatrix(); // should be the same as glLoadIdentity //Hurdler: now it seems to work pglTranslatef(pos->x, pos->z, pos->y); @@ -1908,14 +1937,6 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration scaley = -scaley; pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f); - //pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency - - // Remove depth mask when the model is transparent so it doesn't cut thorugh sprites // SRB2CBTODO: For all stuff too?! - if (color && color[3] < 255) - { - pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency - pglDepthMask(GL_FALSE); - } val = *gl_cmd_buffer++; From f3a605de6b12a947a9819561f711ee637107e46d Mon Sep 17 00:00:00 2001 From: Sryder13 Date: Fri, 15 Sep 2017 18:03:06 +0100 Subject: [PATCH 016/212] I need to stop leaving things commented out that are going --- src/hardware/hw_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 971789122..3a2b0f0ed 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1237,7 +1237,6 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[0].y = wallVerts[1].y = bot; #endif - //glTex = HWR_GetTexture(texnum); if (cutflag & FF_TRANSLUCENT) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); else @@ -1295,7 +1294,6 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[0].y = wallVerts[1].y = bot; #endif - //glTex = HWR_GetTexture(texnum); if (cutflag & FF_TRANSLUCENT) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); else From e63c1d15d87bd4fbbb583a88145bd840c9a17972 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 17 Nov 2017 23:02:34 +0000 Subject: [PATCH 017/212] * Show an emerald token box on the tally screen. * Change the horizontal spacing of the emeralds on the special stage tally screen. * (unrelated) Fix a reference to srb2.srb instead of the now-correct srb2.pk3. --- src/d_main.c | 2 +- src/hu_stuff.c | 70 ++++++++++++++++++++++++++++---------------------- src/hu_stuff.h | 3 +-- src/m_menu.c | 2 +- src/st_stuff.c | 14 +++++----- src/y_inter.c | 33 ++++++++++++++++-------- 6 files changed, 71 insertions(+), 53 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 45f9d6763..b3039ee83 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -832,7 +832,7 @@ static void IdentifyVersion(void) else if (srb2wad1 != NULL && FIL_ReadFileOK(srb2wad1)) D_AddFile(srb2wad1); else - I_Error("SRB2.SRB/SRB2.WAD not found! Expected in %s, ss files: %s and %s\n", srb2waddir, srb2wad1, srb2wad2); + I_Error("SRB2.PK3/SRB2.WAD not found! Expected in %s, ss files: %s and %s\n", srb2waddir, srb2wad1, srb2wad2); if (srb2wad1) free(srb2wad1); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 28b20f61e..ff79bd1e3 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -89,8 +89,7 @@ patch_t *tallinfin; // coop hud //------------------------------------------- -patch_t *emeraldpics[7]; -patch_t *tinyemeraldpics[7]; +patch_t *emeraldpics[3][7]; // 0 = normal, 1 = tiny, 2 = coinbox static patch_t *emblemicon; patch_t *tokenicon; static patch_t *exiticon; @@ -250,20 +249,29 @@ void HU_LoadGraphics(void) tokenicon = W_CachePatchName("TOKNICON", PU_HUDGFX); exiticon = W_CachePatchName("EXITICON", PU_HUDGFX); - emeraldpics[0] = W_CachePatchName("CHAOS1", PU_HUDGFX); - emeraldpics[1] = W_CachePatchName("CHAOS2", PU_HUDGFX); - emeraldpics[2] = W_CachePatchName("CHAOS3", PU_HUDGFX); - emeraldpics[3] = W_CachePatchName("CHAOS4", PU_HUDGFX); - emeraldpics[4] = W_CachePatchName("CHAOS5", PU_HUDGFX); - emeraldpics[5] = W_CachePatchName("CHAOS6", PU_HUDGFX); - emeraldpics[6] = W_CachePatchName("CHAOS7", PU_HUDGFX); - tinyemeraldpics[0] = W_CachePatchName("TEMER1", PU_HUDGFX); - tinyemeraldpics[1] = W_CachePatchName("TEMER2", PU_HUDGFX); - tinyemeraldpics[2] = W_CachePatchName("TEMER3", PU_HUDGFX); - tinyemeraldpics[3] = W_CachePatchName("TEMER4", PU_HUDGFX); - tinyemeraldpics[4] = W_CachePatchName("TEMER5", PU_HUDGFX); - tinyemeraldpics[5] = W_CachePatchName("TEMER6", PU_HUDGFX); - tinyemeraldpics[6] = W_CachePatchName("TEMER7", PU_HUDGFX); + emeraldpics[0][0] = W_CachePatchName("CHAOS1", PU_HUDGFX); + emeraldpics[0][1] = W_CachePatchName("CHAOS2", PU_HUDGFX); + emeraldpics[0][2] = W_CachePatchName("CHAOS3", PU_HUDGFX); + emeraldpics[0][3] = W_CachePatchName("CHAOS4", PU_HUDGFX); + emeraldpics[0][4] = W_CachePatchName("CHAOS5", PU_HUDGFX); + emeraldpics[0][5] = W_CachePatchName("CHAOS6", PU_HUDGFX); + emeraldpics[0][6] = W_CachePatchName("CHAOS7", PU_HUDGFX); + + emeraldpics[1][0] = W_CachePatchName("TEMER1", PU_HUDGFX); + emeraldpics[1][1] = W_CachePatchName("TEMER2", PU_HUDGFX); + emeraldpics[1][2] = W_CachePatchName("TEMER3", PU_HUDGFX); + emeraldpics[1][3] = W_CachePatchName("TEMER4", PU_HUDGFX); + emeraldpics[1][4] = W_CachePatchName("TEMER5", PU_HUDGFX); + emeraldpics[1][5] = W_CachePatchName("TEMER6", PU_HUDGFX); + emeraldpics[2][6] = W_CachePatchName("TEMER7", PU_HUDGFX); + + emeraldpics[2][0] = W_CachePatchName("EMBOX1", PU_HUDGFX); + emeraldpics[2][1] = W_CachePatchName("EMBOX2", PU_HUDGFX); + emeraldpics[2][2] = W_CachePatchName("EMBOX3", PU_HUDGFX); + emeraldpics[2][3] = W_CachePatchName("EMBOX4", PU_HUDGFX); + emeraldpics[2][4] = W_CachePatchName("EMBOX5", PU_HUDGFX); + emeraldpics[2][5] = W_CachePatchName("EMBOX6", PU_HUDGFX); + emeraldpics[2][6] = W_CachePatchName("EMBOX7", PU_HUDGFX); } // Initialise Heads up @@ -1466,25 +1474,25 @@ void HU_DrawEmeralds(INT32 x, INT32 y, INT32 pemeralds) { //Draw the emeralds, in the CORRECT order, using tiny emerald sprites. if (pemeralds & EMERALD1) - V_DrawSmallScaledPatch(x , y-6, 0, tinyemeraldpics[0]); + V_DrawSmallScaledPatch(x , y-6, 0, emeraldpics[1][0]); if (pemeralds & EMERALD2) - V_DrawSmallScaledPatch(x+4, y-3, 0, tinyemeraldpics[1]); + V_DrawSmallScaledPatch(x+4, y-3, 0, emeraldpics[1][1]); if (pemeralds & EMERALD3) - V_DrawSmallScaledPatch(x+4, y+3, 0, tinyemeraldpics[2]); + V_DrawSmallScaledPatch(x+4, y+3, 0, emeraldpics[1][2]); if (pemeralds & EMERALD4) - V_DrawSmallScaledPatch(x , y+6, 0, tinyemeraldpics[3]); + V_DrawSmallScaledPatch(x , y+6, 0, emeraldpics[1][3]); if (pemeralds & EMERALD5) - V_DrawSmallScaledPatch(x-4, y+3, 0, tinyemeraldpics[4]); + V_DrawSmallScaledPatch(x-4, y+3, 0, emeraldpics[1][4]); if (pemeralds & EMERALD6) - V_DrawSmallScaledPatch(x-4, y-3, 0, tinyemeraldpics[5]); + V_DrawSmallScaledPatch(x-4, y-3, 0, emeraldpics[1][5]); if (pemeralds & EMERALD7) - V_DrawSmallScaledPatch(x, y, 0, tinyemeraldpics[6]); + V_DrawSmallScaledPatch(x, y, 0, emeraldpics[1][6]); } // @@ -1753,19 +1761,19 @@ static void HU_DrawCoopOverlay(void) #endif if (emeralds & EMERALD1) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)-32, 0, emeraldpics[0]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)-32, 0, emeraldpics[0][0]); if (emeralds & EMERALD2) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)-16, 0, emeraldpics[1]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)-16, 0, emeraldpics[0][1]); if (emeralds & EMERALD3) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)+16, 0, emeraldpics[2]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8+24, (BASEVIDHEIGHT/3)+16, 0, emeraldpics[0][2]); if (emeralds & EMERALD4) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)+32, 0, emeraldpics[3]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3)+32, 0, emeraldpics[0][3]); if (emeralds & EMERALD5) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)+16, 0, emeraldpics[4]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)+16, 0, emeraldpics[0][4]); if (emeralds & EMERALD6) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)-16, 0, emeraldpics[5]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8-24, (BASEVIDHEIGHT/3)-16, 0, emeraldpics[0][5]); if (emeralds & EMERALD7) - V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3) , 0, emeraldpics[6]); + V_DrawScaledPatch((BASEVIDWIDTH/2)-8 , (BASEVIDHEIGHT/3) , 0, emeraldpics[0][6]); } static void HU_DrawNetplayCoopOverlay(void) @@ -1780,7 +1788,7 @@ static void HU_DrawNetplayCoopOverlay(void) for (i = 0; i < 7; ++i) { if (emeralds & (1 << i)) - V_DrawScaledPatch(20 + (i * 20), 6, 0, emeraldpics[i]); + V_DrawScaledPatch(20 + (i * 20), 6, 0, emeraldpics[0][i]); } } diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 2dbeb556d..fb1fa1817 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -63,8 +63,7 @@ extern patch_t *tallnum[10]; extern patch_t *nightsnum[10]; extern patch_t *lt_font[LT_FONTSIZE]; extern patch_t *cred_font[CRED_FONTSIZE]; -extern patch_t *emeraldpics[7]; -extern patch_t *tinyemeraldpics[7]; +extern patch_t *emeraldpics[3][7]; extern patch_t *rflagico; extern patch_t *bflagico; extern patch_t *rmatcico; diff --git a/src/m_menu.c b/src/m_menu.c index dedbd86f0..6979c73b5 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6274,7 +6274,7 @@ static void M_DrawLoadGameData(void) for (j = 0; j < 7; ++j) { if (savegameinfo[savetodraw].numemeralds & (1 << j)) - V_DrawScaledPatch(workx, y, 0, tinyemeraldpics[j]); + V_DrawScaledPatch(workx, y, 0, emeraldpics[1][j]); workx += 10; } } diff --git a/src/st_stuff.c b/src/st_stuff.c index 437b6758a..24f4e590b 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1699,33 +1699,33 @@ static void ST_drawMatchHUD(void) offset = 136; // Used for Y now if (stplyr->powers[pw_emeralds] & EMERALD1) - V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[0]); + V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][0]); offset += 8; if (stplyr->powers[pw_emeralds] & EMERALD2) - V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[1]); + V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][1]); if (stplyr->powers[pw_emeralds] & EMERALD6) - V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[5]); + V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][5]); offset += 16; if (stplyr->powers[pw_emeralds] & EMERALD3) - V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[2]); + V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][2]); if (stplyr->powers[pw_emeralds] & EMERALD5) - V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[4]); + V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][4]); offset += 8; if (stplyr->powers[pw_emeralds] & EMERALD4) - V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[3]); + V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][3]); offset -= 16; if (stplyr->powers[pw_emeralds] & EMERALD7) - V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[6]); + V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][6]); #ifdef HAVE_BLUA } diff --git a/src/y_inter.c b/src/y_inter.c index 8a93b3eab..9c4d684ac 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -176,12 +176,23 @@ static INT32 SCY(INT32 z) static void Y_IntermissionTokenDrawer(void) { - INT32 y; - INT32 offs = 0; + INT32 y, offs, lowy, calc; UINT32 tokencount; - INT32 lowy = BASEVIDHEIGHT - 32; - INT16 temp = SHORT(tokenicon->height)/2; - INT32 calc; + INT16 temp; + UINT8 em; + + offs = 0; + lowy = BASEVIDHEIGHT - 32 - 8; + temp = SHORT(tokenicon->height)/2; + + if (!(emeralds & EMERALD1)) em = 0; + else if (!(emeralds & EMERALD2)) em = 1; + else if (!(emeralds & EMERALD3)) em = 2; + else if (!(emeralds & EMERALD4)) em = 3; + else if (!(emeralds & EMERALD5)) em = 4; + else if (!(emeralds & EMERALD6)) em = 5; + else if (!(emeralds & EMERALD7)) em = 6; + else return; if (tallydonetic != -1) { @@ -190,7 +201,7 @@ static void Y_IntermissionTokenDrawer(void) offs = 8; } - V_DrawFill(32, lowy-1, 16, 1, 31); // slot + V_DrawSmallScaledPatch(32, lowy-1, 0, emeraldpics[2][em]); // coinbox y = (lowy + offs + 1) - (temp + (token + 1)*8); @@ -370,14 +381,14 @@ void Y_IntermissionDrawer(void) } // draw the emeralds - if (intertic & 1) + //if (intertic & 1) { - INT32 emeraldx = 80; + INT32 emeraldx = 152 - 3*28; for (i = 0; i < 7; ++i) { - if (emeralds & (1 << i)) - V_DrawScaledPatch(emeraldx, 74, 0, emeraldpics[i]); - emeraldx += 24; + if ((emeralds & (1 << i)) && ((intertic & 1) || i != (gamemap + 1 - sstage_start))) + V_DrawScaledPatch(emeraldx, 74, 0, emeraldpics[0][i]); + emeraldx += 28; } } From a79d064d15f77a3da35148668dbfd3069aa23e1b Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 8 Dec 2017 18:26:32 +0000 Subject: [PATCH 018/212] The contents of DSZ-f16.wad's LUA_A000 Lua script are in now Thing type numbers may be changed later --- src/dehacked.c | 32 ++++++++++++ src/info.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 35 +++++++++++++ src/p_enemy.c | 31 +++++++++++ src/p_mobj.c | 11 ++++ 5 files changed, 247 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index cb76c663e..20e078af7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1806,6 +1806,7 @@ static actionpointer_t actionpointers[] = {{A_FlameParticle}, "A_FLAMEPARTICLE"}, {{A_FadeOverlay}, "A_FADEOVERLAY"}, {{A_Boss5Jump}, "A_BOSS5JUMP"}, + {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, {{NULL}, "NONE"}, @@ -4748,6 +4749,33 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Blue Crystal "S_BLUECRYSTAL1", + // Kelp, + "S_KELP", + + // DSZ Stalagmites + "S_DSZSTALAGMITE", + "S_DSZ2STALAGMITE", + + // DSZ Light beam + "S_LIGHTBEAM1", + "S_LIGHTBEAM2", + "S_LIGHTBEAM3", + "S_LIGHTBEAM4", + "S_LIGHTBEAM5", + "S_LIGHTBEAM6", + "S_LIGHTBEAM7", + "S_LIGHTBEAM8", + "S_LIGHTBEAM9", + "S_LIGHTBEAM10", + "S_LIGHTBEAM11", + "S_LIGHTBEAM12", + "S_LIGHTBEAM13", + "S_LIGHTBEAM14", + "S_LIGHTBEAM15", + "S_LIGHTBEAM16", + "S_LIGHTBEAM17", + "S_LIGHTBEAM18", + // CEZ Chain "S_CEZCHAIN", @@ -6153,6 +6181,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_CORAL2", // Coral 2 "MT_CORAL3", // Coral 3 "MT_BLUECRYSTAL", // Blue Crystal + "MT_KELP", // Kelp + "MT_DSZSTALAGMITE", // Deep Sea 1 Stalagmite + "MT_DSZ2STALAGMITE", // Deep Sea 2 Stalagmite + "MT_LIGHTBEAM", // DSZ Light beam // Castle Eggman Scenery "MT_CHAIN", // CEZ Chain diff --git a/src/info.c b/src/info.c index acb12379a..c609f34f2 100644 --- a/src/info.c +++ b/src/info.c @@ -202,6 +202,9 @@ char sprnames[NUMSPRITES + 1][5] = "CRL2", // Coral 2 "CRL3", // Coral 3 "BCRY", // Blue Crystal + "KELP", // Kelp + "DSTG", // DSZ Stalagmites + "LIBE", // DSZ Light beam // Castle Eggman Scenery "CHAN", // CEZ Chain @@ -1948,6 +1951,33 @@ state_t states[NUMSTATES] = // Blue Crystal {SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_BLUECRYSTAL1 + // Kelp + {SPR_KELP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KELP + + // DSZ Stalagmites + {SPR_DSTG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DSZSTALAGMITE + {SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DSZ2STALAGMITE + + // DSZ Light beam + {SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2}, // S_LIGHTBEAM1 + {SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM3}, // S_LIGHTBEAM2 + {SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM4}, // S_LIGHTBEAM3 + {SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5}, // S_LIGHTBEAM4 + {SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6}, // S_LIGHTBEAM5 + {SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM7}, // S_LIGHTBEAM6 + {SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8}, // S_LIGHTBEAM7 + {SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9}, // S_LIGHTBEAM8 + {SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM10}, // S_LIGHTBEAM9 + {SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM11}, // S_LIGHTBEAM10 + {SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM12}, // S_LIGHTBEAM11 + {SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM13}, // S_LIGHTBEAM12 + {SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM14}, // S_LIGHTBEAM13 + {SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM15}, // S_LIGHTBEAM14 + {SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM16}, // S_LIGHTBEAM15 + {SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM17}, // S_LIGHTBEAM16 + {SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM18}, // S_LIGHTBEAM17 + {SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1}, // S_LIGHTBEAM18 + // CEZ Chain {SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN @@ -8880,6 +8910,114 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_KELP + 1007, // doomednum + S_KELP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 292*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_DSZSTALAGMITE + 1008, // doomednum + S_DSZSTALAGMITE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8*FRACUNIT, // radius + 116*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_DSZ2STALAGMITE + 999, // doomednum + S_DSZ2STALAGMITE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8*FRACUNIT, // radius + 116*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_LIGHTBEAM + 1010, // doomednum + S_LIGHTBEAM1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_CHAIN 1100, // doomednum S_CEZCHAIN, // spawnstate diff --git a/src/info.h b/src/info.h index 35a3f5f15..65c1c72c1 100644 --- a/src/info.h +++ b/src/info.h @@ -218,6 +218,7 @@ void A_FlickyFlutter(); void A_FlameParticle(); void A_FadeOverlay(); void A_Boss5Jump(); +void A_LightBeamReset(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 256 @@ -401,6 +402,9 @@ typedef enum sprite SPR_CRL2, // Coral 2 SPR_CRL3, // Coral 3 SPR_BCRY, // Blue Crystal + SPR_KELP, // Kelp + SPR_DSTG, // DSZ Stalagmites + SPR_LIBE, // DSZ Light beam // Castle Eggman Scenery SPR_CHAN, // CEZ Chain @@ -2056,6 +2060,33 @@ typedef enum state // Blue Crystal S_BLUECRYSTAL1, + // Kelp, + S_KELP, + + // DSZ Stalagmites + S_DSZSTALAGMITE, + S_DSZ2STALAGMITE, + + // DSZ Light beam + S_LIGHTBEAM1, + S_LIGHTBEAM2, + S_LIGHTBEAM3, + S_LIGHTBEAM4, + S_LIGHTBEAM5, + S_LIGHTBEAM6, + S_LIGHTBEAM7, + S_LIGHTBEAM8, + S_LIGHTBEAM9, + S_LIGHTBEAM10, + S_LIGHTBEAM11, + S_LIGHTBEAM12, + S_LIGHTBEAM13, + S_LIGHTBEAM14, + S_LIGHTBEAM15, + S_LIGHTBEAM16, + S_LIGHTBEAM17, + S_LIGHTBEAM18, + // CEZ Chain S_CEZCHAIN, @@ -3481,6 +3512,10 @@ typedef enum mobj_type MT_CORAL2, // Coral 2 MT_CORAL3, // Coral 3 MT_BLUECRYSTAL, // Blue Crystal + MT_KELP, // Kelp + MT_DSZSTALAGMITE, // Deep Sea 1 Stalagmite + MT_DSZ2STALAGMITE, // Deep Sea 2 Stalagmite + MT_LIGHTBEAM, // DSZ Light beam // Castle Eggman Scenery MT_CHAIN, // CEZ Chain diff --git a/src/p_enemy.c b/src/p_enemy.c index 9acc8430e..de2e1d357 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -246,6 +246,7 @@ void A_FlickyFlutter(mobj_t *actor); void A_FlameParticle(mobj_t *actor); void A_FadeOverlay(mobj_t *actor); void A_Boss5Jump(mobj_t *actor); +void A_LightBeamReset(mobj_t *actor); // // ENEMY THINKING @@ -10624,3 +10625,33 @@ void A_Boss5Jump(mobj_t *actor) actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT)); // I hope that's all that's needed, ugh } + +// Function: A_LightBeamReset +// Description: Resets momentum and position for DSZ's projecting light beams +// +// var1 = unused +// var2 = unused +// +void A_LightBeamReset(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_LightBeamReset", actor)) + return; +#endif + + P_SetScale(actor, FRACUNIT + P_SignedRandom()*FRACUNIT/256); + actor->destscale = actor->scale; + + if (!actor->spawnpoint) + return; // this can't work properly welp + + actor->momx = P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; + actor->momy = P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; + actor->momz = P_SignedRandom()*FRACUNIT/128; + + P_UnsetThingPosition(actor); + actor->x = actor->spawnpoint->x*FRACUNIT + P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; + actor->y = actor->spawnpoint->y*FRACUNIT + P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; + actor->z = actor->spawnpoint->z*FRACUNIT + P_SignedRandom()*FRACUNIT/2; + P_SetThingPosition(actor); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index 6808a6dc6..d45c7ae65 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8359,6 +8359,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_GFZCHERRYTREE: case MT_LAMPPOST1: case MT_LAMPPOST2: + case MT_DSZSTALAGMITE: + case MT_DSZ2STALAGMITE: mobj->flags2 |= MF2_STANDONME; break; case MT_DETON: @@ -10075,6 +10077,15 @@ domaceagain: case MT_TRAPGOYLELONG: if (mthing->angle >= 360) mobj->tics += 7*(mthing->angle / 360) + 1; // starting delay + break; + case MT_DSZSTALAGMITE: + case MT_DSZ2STALAGMITE: + case MT_KELP: + if (mthing->options & MTF_OBJECTSPECIAL) { // make mobj twice as big as normal + P_SetScale(mobj, 2*mobj->scale); // not 2*FRACUNIT in case of something like the old ERZ3 mode + mobj->destscale = mobj->scale; + } + break; default: break; } From 3d4adaac0908e52bc5ad39c92f78c7b1e8e9d922 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 9 Dec 2017 18:48:25 +0000 Subject: [PATCH 019/212] my mistake --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index ff79bd1e3..7af7aa768 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -263,7 +263,7 @@ void HU_LoadGraphics(void) emeraldpics[1][3] = W_CachePatchName("TEMER4", PU_HUDGFX); emeraldpics[1][4] = W_CachePatchName("TEMER5", PU_HUDGFX); emeraldpics[1][5] = W_CachePatchName("TEMER6", PU_HUDGFX); - emeraldpics[2][6] = W_CachePatchName("TEMER7", PU_HUDGFX); + emeraldpics[1][6] = W_CachePatchName("TEMER7", PU_HUDGFX); emeraldpics[2][0] = W_CachePatchName("EMBOX1", PU_HUDGFX); emeraldpics[2][1] = W_CachePatchName("EMBOX2", PU_HUDGFX); From ce724a61385b860f47ca0636f4eeedc1c5d88e52 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 9 Dec 2017 23:08:12 +0000 Subject: [PATCH 020/212] * Make lives pic appear in all gametypes. * Lives position now more consistent between players in splitscreen. * Ringslinger weapon bar is now at the same height as the lives pic, and also more centered horizontally. * Begin tweaking emerald icon locations for ringslinger gametypes. * Remove in-game team names from team gametypes, since this information is (mostly) conveyed by the lives pic. --- src/st_stuff.c | 129 +++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 24f4e590b..98a4b7d95 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -688,29 +688,34 @@ static inline void ST_drawRings(void) ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum, ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); } -static void ST_drawLives(void) +static void ST_drawLivesPic(void) { - const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayer] ? V_SPLITSCREEN : 0); - INT32 livescount; - boolean notgreyedout; + const INT32 y = STRINGY(hudinfo[HUD_LIVESPIC].y+16)-16; if (!stplyr->skincolor) return; // Just joined a server, skin isn't loaded yet! // face background - V_DrawSmallScaledPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, livesback); + V_DrawSmallScaledPatch(hudinfo[HUD_LIVESPIC].x, y, + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, livesback); // face - if (stplyr->mo && stplyr->mo->color) + if (stplyr->spectator) + { + // spectator face + UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, SKINCOLOR_CLOUDY, GTC_CACHE); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANSHALF, faceprefix[stplyr->skin], colormap); + } + else if (stplyr->mo && stplyr->mo->color) { // skincolor face/super UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE); patch_t *face = faceprefix[stplyr->skin]; if (stplyr->powers[pw_super]) face = superprefix[stplyr->skin]; - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,face, colormap); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, face, colormap); if (cv_translucenthud.value == 10 && stplyr->powers[pw_super] == 1 && stplyr->mo->tracer) { INT32 v_supertrans = (stplyr->mo->tracer->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; @@ -718,8 +723,8 @@ static void ST_drawLives(void) { v_supertrans <<= V_ALPHASHIFT; colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->tracer->color, GTC_CACHE); - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|v_supertrans|v_splitflag,face, colormap); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, + V_SNAPTOLEFT|V_SNAPTOBOTTOM|v_supertrans, face, colormap); } } } @@ -727,20 +732,30 @@ static void ST_drawLives(void) { // skincolor face UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,faceprefix[stplyr->skin], colormap); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, faceprefix[stplyr->skin], colormap); } +} + +static void ST_drawLives(void) +{ + const INT32 y = STRINGY(hudinfo[HUD_LIVESNAME].y+16)-16; + INT32 livescount; + boolean notgreyedout; + + if (!stplyr->skincolor) + return; // Just joined a server, skin isn't loaded yet! // name if (strlen(skins[stplyr->skin].hudname) > 8) - V_DrawThinString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), - V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); + V_DrawThinString(hudinfo[HUD_LIVESNAME].x, y, + V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP, skins[stplyr->skin].hudname); else - V_DrawString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), - V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); + V_DrawString(hudinfo[HUD_LIVESNAME].x, y, + V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP, skins[stplyr->skin].hudname); // x - V_DrawScaledPatch(hudinfo[HUD_LIVESX].x, hudinfo[HUD_LIVESX].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, stlivex); + V_DrawScaledPatch(hudinfo[HUD_LIVESX].x, y+8, + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, stlivex); // lives number if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) @@ -775,20 +790,20 @@ static void ST_drawLives(void) } if (livescount == 0x7f) - V_DrawCharacter(hudinfo[HUD_LIVESNUM].x - 8, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), '\x16' | 0x80 | V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, false); + V_DrawCharacter(hudinfo[HUD_LIVESNUM].x - 8, y+8, + '\x16' | 0x80 | V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, false); else { if (livescount > 99) livescount = 99; - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF)|v_splitflag, + V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, y+8, + V_SNAPTOLEFT|V_SNAPTOBOTTOM|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), ((livescount > 99) ? "!!" : va("%d",livescount))); } } static void ST_drawInput(void) { - //const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayer] ? V_SPLITSCREEN : 0); -- no splitscreen support - record attack only for base game const UINT8 accent = (stplyr->skincolor ? Color_Index[stplyr->skincolor-1][4] : 0); UINT8 col, offs; @@ -1620,7 +1635,7 @@ static void ST_drawNiGHTSHUD(void) splitscreen = true; } -static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, INT32 xoffs, patch_t *pat) +static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, INT32 xoffs, INT32 y, patch_t *pat) { INT32 txtflags = 0, patflags = 0; @@ -1638,23 +1653,24 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I patflags = V_80TRANS; } - V_DrawScaledPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|patflags, pat); + V_DrawScaledPatch(8 + xoffs, y, V_SNAPTOLEFT|patflags, pat); if (stplyr->powers[weapon] > 99) - V_DrawThinString(8 + xoffs + 1, STRINGY(162), V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); + V_DrawThinString(8 + xoffs + 1, y, V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); else - V_DrawString(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); + V_DrawString(8 + xoffs, y, V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); if (stplyr->currentweapon == wepflag) - V_DrawScaledPatch(6 + xoffs, STRINGY(162 - (splitscreen ? 4 : 2)), V_SNAPTOLEFT, curweapon); + V_DrawScaledPatch(6 + xoffs, y-2, V_SNAPTOLEFT, curweapon); } else if (stplyr->ringweapons & rwflag) - V_DrawScaledPatch(8 + xoffs, STRINGY(162), V_SNAPTOLEFT|V_TRANSLUCENT, pat); + V_DrawScaledPatch(8 + xoffs, y, V_SNAPTOLEFT|V_TRANSLUCENT, pat); } static void ST_drawMatchHUD(void) { - INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10); + const INT32 y = STRINGY(176+16)-16; // HUD_LIVESPIC + INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; if (!G_RingSlingerGametype()) return; @@ -1667,27 +1683,27 @@ static void ST_drawMatchHUD(void) #endif if (stplyr->powers[pw_infinityring]) - ST_drawWeaponRing(pw_infinityring, 0, 0, offset, infinityring); + ST_drawWeaponRing(pw_infinityring, 0, 0, offset, y, infinityring); else if (stplyr->rings > 0) - V_DrawScaledPatch(8 + offset, STRINGY(162), V_SNAPTOLEFT, normring); + V_DrawScaledPatch(8 + offset, y, V_SNAPTOLEFT, normring); else - V_DrawTranslucentPatch(8 + offset, STRINGY(162), V_SNAPTOLEFT|V_80TRANS, normring); + V_DrawTranslucentPatch(8 + offset, y, V_SNAPTOLEFT|V_80TRANS, normring); if (!stplyr->currentweapon) - V_DrawScaledPatch(6 + offset, STRINGY(162 - (splitscreen ? 4 : 2)), V_SNAPTOLEFT, curweapon); + V_DrawScaledPatch(6 + offset, y-2, V_SNAPTOLEFT, curweapon); offset += 20; - ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, autoring); + ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, y, autoring); offset += 20; - ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, bouncering); + ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, y, bouncering); offset += 20; - ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, scatterring); + ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, y, scatterring); offset += 20; - ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, grenadering); + ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, y, grenadering); offset += 20; - ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, explosionring); + ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, y, explosionring); offset += 20; - ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, railring); + ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, y, railring); #ifdef HAVE_BLUA } @@ -1696,36 +1712,36 @@ static void ST_drawMatchHUD(void) #endif // Power Stones collected - offset = 136; // Used for Y now + offset = STRINGY(128); // Used for Y now if (stplyr->powers[pw_emeralds] & EMERALD1) - V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][0]); + V_DrawScaledPatch(28, offset, V_SNAPTOLEFT, emeraldpics[1][0]); offset += 8; if (stplyr->powers[pw_emeralds] & EMERALD2) - V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][1]); + V_DrawScaledPatch(40, offset, V_SNAPTOLEFT, emeraldpics[1][1]); if (stplyr->powers[pw_emeralds] & EMERALD6) - V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][5]); + V_DrawScaledPatch(16, offset, V_SNAPTOLEFT, emeraldpics[1][5]); offset += 16; if (stplyr->powers[pw_emeralds] & EMERALD3) - V_DrawScaledPatch(40, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][2]); + V_DrawScaledPatch(40, offset, V_SNAPTOLEFT, emeraldpics[1][2]); if (stplyr->powers[pw_emeralds] & EMERALD5) - V_DrawScaledPatch(16, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][4]); + V_DrawScaledPatch(16, offset, V_SNAPTOLEFT, emeraldpics[1][4]); offset += 8; if (stplyr->powers[pw_emeralds] & EMERALD4) - V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][3]); + V_DrawScaledPatch(28, offset, V_SNAPTOLEFT, emeraldpics[1][3]); offset -= 16; if (stplyr->powers[pw_emeralds] & EMERALD7) - V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, emeraldpics[1][6]); + V_DrawScaledPatch(28, offset, V_SNAPTOLEFT, emeraldpics[1][6]); #ifdef HAVE_BLUA } @@ -1880,17 +1896,6 @@ static void ST_drawCTFHUD(void) } } -// Draws "Red Team", "Blue Team", or "Spectator" for team gametypes. -static inline void ST_drawTeamName(void) -{ - if (stplyr->ctfteam == 1) - V_DrawString(256, (splitscreen) ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "RED TEAM"); - else if (stplyr->ctfteam == 2) - V_DrawString(248, (splitscreen) ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "BLUE TEAM"); - else - V_DrawString(244, (splitscreen) ? STRINGY(184) : STRINGY(192), V_HUDTRANSHALF, "SPECTATOR"); -} - static void ST_drawSpecialStageHUD(void) { if (totalrings > 0) @@ -2061,6 +2066,8 @@ static void ST_overlayDrawer(void) if (LUA_HudEnabled(hud_rings)) #endif ST_drawRings(); + + ST_drawLivesPic(); // always do on mystic's request - allows us to kill "RED/BLUE TEAM" text if (G_GametypeUsesLives() #ifdef HAVE_BLUA && LUA_HudEnabled(hud_lives) @@ -2142,10 +2149,6 @@ static void ST_overlayDrawer(void) else if (gametype == GT_CTF) ST_drawCTFHUD(); - // Team names for team gametypes - if (G_GametypeHasTeams()) - ST_drawTeamName(); - // Special Stage HUD if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayer]) ST_drawSpecialStageHUD(); From 336a26602d0d783ff5acf9a13bf6e8dd057eabf2 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 10 Dec 2017 14:35:55 +0000 Subject: [PATCH 021/212] Not strictly pretty, but fixes a bug I discovered whilst working on this. --- src/m_menu.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 6979c73b5..25039c596 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2045,35 +2045,7 @@ static void Newgametype_OnChange(void) P_AllocMapHeader((INT16)(cv_nextmap.value-1)); if (!M_CanShowLevelOnPlatter(cv_nextmap.value-1, cv_newgametype.value)) - { - INT32 value = 0; - - switch (cv_newgametype.value) - { - case GT_COOP: - value = TOL_COOP; - break; - case GT_COMPETITION: - value = TOL_COMPETITION; - break; - case GT_RACE: - value = TOL_RACE; - break; - case GT_MATCH: - case GT_TEAMMATCH: - value = TOL_MATCH; - break; - case GT_TAG: - case GT_HIDEANDSEEK: - value = TOL_TAG; - break; - case GT_CTF: - value = TOL_CTF; - break; - } - - CV_SetValue(&cv_nextmap, M_GetFirstLevelInList(value)); - } + CV_SetValue(&cv_nextmap, M_GetFirstLevelInList(cv_newgametype.value)); } } From 82ac8b6a1c132973873fb8ed924d3590f7b4ccf5 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 19 Jan 2018 17:56:18 +0000 Subject: [PATCH 022/212] Hardcoded SOC_FWR6 from THZ1.wad, also tweaked MT_THZFLOWERB's hitbox --- src/dehacked.c | 8 +++++--- src/info.c | 40 +++++++++++++++++++++++++++++++++++----- src/info.h | 13 ++++++++----- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 20e078af7..067cea460 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4709,9 +4709,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BUSHTREE", "S_BUSHREDTREE", - // THZ Plant - "S_THZFLOWERA", - "S_THZFLOWERB", + // THZ flowers + "S_THZFLOWERA", // THZ1 Steam flower + "S_THZFLOWERB", // THZ1 Spin flower (red) + "S_THZFLOWERC", // THZ1 Spin flower (yellow) // THZ Alarm "S_ALARM1", @@ -6169,6 +6170,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Techno Hill Scenery "MT_THZFLOWER1", "MT_THZFLOWER2", + "MT_THZFLOWER3", "MT_ALARM", // Deep Sea Scenery diff --git a/src/info.c b/src/info.c index c609f34f2..c2eccd421 100644 --- a/src/info.c +++ b/src/info.c @@ -190,8 +190,9 @@ char sprnames[NUMSPRITES + 1][5] = "TRE5", // Bush tree // Techno Hill Scenery - "THZP", // Techno Hill Zone Plant - "FWR5", // Another one + "THZP", // THZ1 Steam Flower + "FWR5", // THZ1 Spin flower (red) + "FWR6", // THZ1 Spin flower (yellow) "ALRM", // THZ2 Alarm // Deep Sea Scenery @@ -1892,7 +1893,7 @@ state_t states[NUMSTATES] = {SPR_CFIR, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_DEMONFIRE6}, // S_DEMONFIRE5 {SPR_CFIR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_DEMONFIRE1}, // S_DEMONFIRE6 - // GFZ Flower + // GFZ flowers {SPR_FWR1, FF_ANIMATE, -1, {NULL}, 7, 3, S_NULL}, // S_GFZFLOWERA {SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL}, // S_GFZFLOWERB {SPR_FWR3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_GFZFLOWERC @@ -1912,8 +1913,10 @@ state_t states[NUMSTATES] = {SPR_TRE5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHTREE {SPR_TRE5, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHREDTREE + // THZ flowers {SPR_THZP, FF_ANIMATE, -1, {NULL}, 7, 4, S_NULL}, // S_THZFLOWERA {SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERB + {SPR_FWR6, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERC // THZ Alarm {SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1 @@ -8630,8 +8633,35 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 8, // speed - 8*FRACUNIT, // radius - 32*FRACUNIT, // height + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_THZFLOWER3 + 903, // doomednum + S_THZFLOWERC, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage diff --git a/src/info.h b/src/info.h index 65c1c72c1..92786e376 100644 --- a/src/info.h +++ b/src/info.h @@ -390,8 +390,9 @@ typedef enum sprite SPR_TRE5, // Bush tree // Techno Hill Scenery - SPR_THZP, // THZ1 Flower - SPR_FWR5, // Another flower + SPR_THZP, // THZ1 Steam Flower + SPR_FWR5, // THZ1 Spin flower (red) + SPR_FWR6, // THZ1 Spin flower (yellow) SPR_ALRM, // THZ2 Alarm // Deep Sea Scenery @@ -2020,9 +2021,10 @@ typedef enum state S_BUSHTREE, S_BUSHREDTREE, - // THZ Plant - S_THZFLOWERA, - S_THZFLOWERB, + // THZ flowers + S_THZFLOWERA, // THZ1 Steam flower + S_THZFLOWERB, // THZ1 Spin flower (red) + S_THZFLOWERC, // THZ1 Spin flower (yellow) // THZ Alarm S_ALARM1, @@ -3500,6 +3502,7 @@ typedef enum mobj_type // Techno Hill Scenery MT_THZFLOWER1, MT_THZFLOWER2, + MT_THZFLOWER3, MT_ALARM, // Deep Sea Scenery From 2141754e5468fc4366c3ea8870f69920254ace6d Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 20 Jan 2018 22:14:24 +0000 Subject: [PATCH 023/212] V_PERPLAYER. (Hooh boy.) * Completely redid how splitscreen works, with eventual support for quads. Squish per-player stuff automatically into the right places! Works in GL, associated flag kills V_SPLITSCREEN. * Seriously update the lives-drawing function for all gametypes, with strings that replace the lives number whenever it's missing (deprecates SKINNAMEPADDING). * Improved how the nosshack works, alongside many other refactorings. --- src/dehacked.c | 16 +- src/doomdef.h | 3 - src/hardware/hw_draw.c | 47 ++- src/r_things.c | 8 - src/st_stuff.c | 782 ++++++++++++++++++----------------------- src/st_stuff.h | 12 +- src/v_video.c | 54 ++- src/v_video.h | 2 +- src/y_inter.c | 62 ++-- 9 files changed, 463 insertions(+), 523 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index cb76c663e..bd4530e00 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6799,32 +6799,22 @@ static const char *const POWERS_LIST[] = { }; static const char *const HUDITEMS_LIST[] = { - "LIVESNAME", - "LIVESPIC", - "LIVESNUM", - "LIVESX", + "LIVES", "RINGS", - "RINGSSPLIT", "RINGSNUM", - "RINGSNUMSPLIT", "SCORE", "SCORENUM", "TIME", - "TIMESPLIT", "MINUTES", - "MINUTESSPLIT", "TIMECOLON", - "TIMECOLONSPLIT", "SECONDS", - "SECONDSSPLIT", "TIMETICCOLON", "TICS", "SS_TOTALRINGS", - "SS_TOTALRINGS_SPLIT", "GETRINGS", "GETRINGSNUM", @@ -7353,7 +7343,7 @@ struct { {"V_WRAPX",V_WRAPX}, {"V_WRAPY",V_WRAPY}, {"V_NOSCALESTART",V_NOSCALESTART}, - {"V_SPLITSCREEN",V_SPLITSCREEN}, + {"V_PERPLAYER",V_PERPLAYER}, {"V_PARAMMASK",V_PARAMMASK}, {"V_SCALEPATCHMASK",V_SCALEPATCHMASK}, @@ -7503,7 +7493,7 @@ static hudnum_t get_huditem(const char *word) if (fastcmp(word, HUDITEMS_LIST[i])) return i; deh_warning("Couldn't find huditem named 'HUD_%s'",word); - return HUD_LIVESNAME; + return HUD_LIVES; } #ifndef HAVE_BLUA diff --git a/src/doomdef.h b/src/doomdef.h index a49fb0207..ee21cf308 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -560,9 +560,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls. //#define PAPER_COLLISIONCORRECTION -/// Hudname padding. -#define SKINNAMEPADDING - /// FINALLY some real clipping that doesn't make walls dissappear AND speeds the game up /// (that was the original comment from SRB2CB, sadly it is a lie and actually slows game down) /// on the bright side it fixes some weird issues with translucent walls diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index dc97f7014..f902b4802 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -33,6 +33,8 @@ #include "../z_zone.h" #include "../v_video.h" #include "../st_stuff.h" +#include "../p_local.h" // stplyr +#include "../g_game.h" // players #include #include "../i_video.h" // for rendermode != render_glide @@ -181,8 +183,49 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, if (option & V_NOSCALESTART) sdupx = sdupy = 2.0f; - if (option & V_SPLITSCREEN) - sdupy /= 2.0f; + if (splitscreen && (option & V_PERPLAYER)) + { + float adjusty = ((option & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + pdupy /= 2; + cy /= 2; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + float adjustx = ((option & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f; + pdupx /= 2; + cx /= 2; + if (stplyr == &players[displayplayer]) + option &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + else if (stplyr == &players[secondarydisplayplayer]) + { + cx += adjustx; + option &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + cy += adjusty; + option &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + cx += adjustx; + cy += adjusty; + option &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + option &= ~V_SNAPTOBOTTOM; + else //if (stplyr == &players[secondarydisplayplayer]) + { + cy += adjusty; + option &= ~V_SNAPTOTOP; + } + } + } if (option & V_FLIP) // Need to flip both this and sow { diff --git a/src/r_things.c b/src/r_things.c index d201786a5..fad47d26b 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2497,11 +2497,7 @@ static void Sk_SetDefaultValue(skin_t *skin) skin->flags = 0; strcpy(skin->realname, "Someone"); -#ifdef SKINNAMEPADDING - strcpy(skin->hudname, " ???"); -#else strcpy(skin->hudname, "???"); -#endif strncpy(skin->charsel, "CHRSONIC", 8); strncpy(skin->face, "MISSING", 8); strncpy(skin->superface, "MISSING", 8); @@ -2733,11 +2729,7 @@ static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump) return INT16_MAX; // not found } -#ifdef SKINNAMEPADDING -#define HUDNAMEWRITE(value) snprintf(skin->hudname, sizeof(skin->hudname), "%5s", value) -#else #define HUDNAMEWRITE(value) STRBUFCPY(skin->hudname, value) -#endif // turn _ into spaces and . into katana dot #define SYMBOLCONVERT(name) for (value = name; *value; value++)\ diff --git a/src/st_stuff.c b/src/st_stuff.c index 98a4b7d95..1426ae405 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -125,33 +125,23 @@ static boolean facefreed[MAXPLAYERS]; hudinfo_t hudinfo[NUMHUDITEMS] = { - { 34, 176}, // HUD_LIVESNAME - { 16, 176}, // HUD_LIVESPIC - { 74, 184}, // HUD_LIVESNUM - { 38, 186}, // HUD_LIVESX + { 16, 176}, // HUD_LIVES { 16, 42}, // HUD_RINGS - { 220, 10}, // HUD_RINGSSPLIT { 96, 42}, // HUD_RINGSNUM - { 296, 10}, // HUD_RINGSNUMSPLIT { 120, 42}, // HUD_RINGSNUMTICS { 16, 10}, // HUD_SCORE { 120, 10}, // HUD_SCORENUM { 16, 26}, // HUD_TIME - { 128, 10}, // HUD_TIMESPLIT { 72, 26}, // HUD_MINUTES - { 188, 10}, // HUD_MINUTESSPLIT { 72, 26}, // HUD_TIMECOLON - { 188, 10}, // HUD_TIMECOLONSPLIT { 96, 26}, // HUD_SECONDS - { 212, 10}, // HUD_SECONDSSPLIT { 96, 26}, // HUD_TIMETICCOLON { 120, 26}, // HUD_TICS { 120, 56}, // HUD_SS_TOTALRINGS - { 296, 40}, // HUD_SS_TOTALRINGS_SPLIT { 110, 93}, // HUD_GETRINGS { 160, 93}, // HUD_GETRINGSNUM @@ -423,84 +413,26 @@ static INT32 SCZ(INT32 z) return FixedInt(FixedMul(z<>= 1; - if (stplyr != &players[displayplayer]) - y += vid.height / 2; - } - return y; -} - -static INT32 STRINGY(INT32 y) -{ - //31/10/99: fixed by Hurdler so it _works_ also in hardware mode - // do not scale to resolution for hardware accelerated - // because these modes always scale by default - if (splitscreen) - { - y >>= 1; - if (stplyr != &players[displayplayer]) - y += BASEVIDHEIGHT / 2; - } - return y; -} - -static INT32 SPLITFLAGS(INT32 f) -{ - // Pass this V_SNAPTO(TOP|BOTTOM) and it'll trim them to account for splitscreen! -Red - if (splitscreen) - { - if (stplyr != &players[displayplayer]) - f &= ~V_SNAPTOTOP; - else - f &= ~V_SNAPTOBOTTOM; - } - return f; -} - static INT32 SCX(INT32 x) { return FixedInt(FixedMul(x<>= 1; - if (stplyr != &players[displayplayer]) - y += vid.height / 2; - } - return FixedInt(FixedDiv(y, vid.fdupy)); -} -#endif - // ========================================================================= // INTERNAL DRAWING // ========================================================================= -#define ST_DrawOverlayNum(x,y,n) V_DrawTallNum(x, y, V_NOSCALESTART|V_HUDTRANS, n) -#define ST_DrawPaddedOverlayNum(x,y,n,d) V_DrawPaddedTallNum(x, y, V_NOSCALESTART|V_HUDTRANS, n, d) -#define ST_DrawOverlayPatch(x,y,p) V_DrawScaledPatch(x, y, V_NOSCALESTART|V_HUDTRANS, p) -#define ST_DrawMappedOverlayPatch(x,y,p,c) V_DrawMappedScaledPatch(x, y, V_NOSCALESTART|V_HUDTRANS, p, c) -#define ST_DrawNumFromHud(h,n,f) V_DrawTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|f, n) -#define ST_DrawPadNumFromHud(h,n,q,f) V_DrawPaddedTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|f, n, q) -#define ST_DrawPatchFromHud(h,p,f) V_DrawScaledPatch(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|f, p) -#define ST_DrawNumFromHudWS(h,n,f) V_DrawTallNum(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|f, n) -#define ST_DrawPadNumFromHudWS(h,n,q,f) V_DrawPaddedTallNum(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|f, n, q) -#define ST_DrawPatchFromHudWS(h,p,f) V_DrawScaledPatch(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|f, p) +#define ST_DrawUnscaledOverlayNum(x,y,n) V_DrawTallNum(x, y, V_NOSCALESTART|V_PERPLAYER|V_HUDTRANS, n) +#define ST_DrawUnscaledPaddedOverlayNum(x,y,n,d) V_DrawPaddedTallNum(x, y, V_NOSCALESTART|V_PERPLAYER|V_HUDTRANS, n, d) +#define ST_DrawUnscaledOverlayPatch(x,y,p) V_DrawScaledPatch(x, y, V_NOSCALESTART|V_PERPLAYER|V_HUDTRANS, p) +#define ST_DrawTopLeftOverlayNum(x,y,n) V_DrawTallNum(x, y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, n) +#define ST_DrawTopLeftOverlayPatch(x,y,p) V_DrawScaledPatch(x, y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, p) +#define ST_DrawMappedOverlayPatch(x,y,p,c) V_DrawMappedScaledPatch(x, y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, p, c) +#define ST_DrawNumFromHud(h,n,f) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n) +#define ST_DrawPadNumFromHud(h,n,q,f) V_DrawPaddedTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n, q) +#define ST_DrawPatchFromHud(h,p,f) V_DrawScaledPatch(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, p) +#define ST_DrawNumFromHudWS(h,n,f) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n) +#define ST_DrawPadNumFromHudWS(h,n,q,f) V_DrawPaddedTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n, q) +#define ST_DrawPatchFromHudWS(h,p,f) V_DrawScaledPatch(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, p) // Draw a number, scaled, over the view, maybe with set translucency // Always draw the number completely since it's overlay @@ -617,7 +549,7 @@ static void ST_drawScore(void) if (objectplacing) { if (op_displayflags > UINT16_MAX) - ST_DrawOverlayPatch(SCX(hudinfo[HUD_SCORENUM].x-tallminus->width), SCY(hudinfo[HUD_SCORENUM].y), tallminus); + ST_DrawTopLeftOverlayPatch((hudinfo[HUD_SCORENUM].x-tallminus->width), hudinfo[HUD_SCORENUM].y, tallminus); else ST_DrawNumFromHud(HUD_SCORENUM, op_displayflags, V_HUDTRANS); } @@ -655,7 +587,7 @@ static void ST_drawTime(void) ST_DrawPatchFromHudWS(HUD_TIMECOLON, sbocolon, V_HUDTRANS); // Colon ST_DrawPadNumFromHudWS(HUD_SECONDS, seconds, 2, V_HUDTRANS); // Seconds - if (!splitscreen && (cv_timetic.value == 2 || cv_timetic.value == 3 || modeattacking)) // there's not enough room for tics in splitscreen, don't even bother trying! + if (cv_timetic.value == 2 || cv_timetic.value == 3 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! { ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod, V_HUDTRANS); // Period ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2, V_HUDTRANS); // Tics @@ -682,30 +614,31 @@ static inline void ST_drawRings(void) else ringnum = max(stplyr->rings, 0); - if (!splitscreen && cv_timetic.value == 3) // Yes, even in modeattacking - ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); + if (cv_timetic.value == 3) // Yes, even in modeattacking + ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); else - ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum, ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); + ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); } -static void ST_drawLivesPic(void) +static void ST_drawLivesArea(void) { - const INT32 y = STRINGY(hudinfo[HUD_LIVESPIC].y+16)-16; + INT32 v_colmap = V_YELLOWMAP, livescount; + boolean notgreyedout; if (!stplyr->skincolor) return; // Just joined a server, skin isn't loaded yet! // face background - V_DrawSmallScaledPatch(hudinfo[HUD_LIVESPIC].x, y, - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, livesback); + V_DrawSmallScaledPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, + V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, livesback); // face if (stplyr->spectator) { // spectator face UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, SKINCOLOR_CLOUDY, GTC_CACHE); - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANSHALF, faceprefix[stplyr->skin], colormap); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, + V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANSHALF, faceprefix[stplyr->skin], colormap); } else if (stplyr->mo && stplyr->mo->color) { @@ -714,8 +647,8 @@ static void ST_drawLivesPic(void) patch_t *face = faceprefix[stplyr->skin]; if (stplyr->powers[pw_super]) face = superprefix[stplyr->skin]; - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, face, colormap); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, + V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, face, colormap); if (cv_translucenthud.value == 10 && stplyr->powers[pw_super] == 1 && stplyr->mo->tracer) { INT32 v_supertrans = (stplyr->mo->tracer->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; @@ -723,8 +656,8 @@ static void ST_drawLivesPic(void) { v_supertrans <<= V_ALPHASHIFT; colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->tracer->color, GTC_CACHE); - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, - V_SNAPTOLEFT|V_SNAPTOBOTTOM|v_supertrans, face, colormap); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, + V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|v_supertrans, face, colormap); } } } @@ -732,104 +665,172 @@ static void ST_drawLivesPic(void) { // skincolor face UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, y, - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, faceprefix[stplyr->skin], colormap); + V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, + V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, faceprefix[stplyr->skin], colormap); } -} -static void ST_drawLives(void) -{ - const INT32 y = STRINGY(hudinfo[HUD_LIVESNAME].y+16)-16; - INT32 livescount; - boolean notgreyedout; - - if (!stplyr->skincolor) - return; // Just joined a server, skin isn't loaded yet! - - // name - if (strlen(skins[stplyr->skin].hudname) > 8) - V_DrawThinString(hudinfo[HUD_LIVESNAME].x, y, - V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP, skins[stplyr->skin].hudname); - else - V_DrawString(hudinfo[HUD_LIVESNAME].x, y, - V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP, skins[stplyr->skin].hudname); - // x - V_DrawScaledPatch(hudinfo[HUD_LIVESX].x, y+8, - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, stlivex); - - // lives number - if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) + // Lives number + if (G_GametypeUsesLives()) { - INT32 i; - livescount = 0; - notgreyedout = (stplyr->lives > 0); - for (i = 0; i < MAXPLAYERS; i++) + // x + V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10, + V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, stlivex); + + // lives number + if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) { - if (!playeringame[i]) - continue; - - if (players[i].lives < 1) - continue; - - if (players[i].lives > 1) - notgreyedout = true; - - if (players[i].lives == 0x7f) + INT32 i; + livescount = 0; + notgreyedout = (stplyr->lives > 0); + for (i = 0; i < MAXPLAYERS; i++) { - livescount = 0x7f; - break; + if (!playeringame[i]) + continue; + + if (players[i].lives < 1) + continue; + + if (players[i].lives > 1) + notgreyedout = true; + + if (players[i].lives == 0x7f) + { + livescount = 0x7f; + break; + } + else if (livescount < 99) + livescount += (players[i].lives); } - else if (livescount < 99) - livescount += (players[i].lives); + } + else + { + livescount = ((cv_cooplives.value == 0) ? 0x7f : stplyr->lives); + notgreyedout = true; + } + + if (livescount == 0x7f) + V_DrawCharacter(hudinfo[HUD_LIVES].x+50, hudinfo[HUD_LIVES].y+8, + '\x16' | 0x80 | V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, false); + else + { + if (livescount > 99) + livescount = 99; + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, + V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), va("%d",livescount)); } } + // Spectator + else if (stplyr->spectator) + { + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "SPECTATE"); + v_colmap = V_GRAYMAP; + } + // Tag + else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + { + if (stplyr->pflags & PF_TAGIT) + { + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, (gametype == GT_HIDEANDSEEK) ? "SEEKER" : "IT!"); + v_colmap = V_ORANGEMAP; + } + else if (stplyr->pflags & PF_GAMETYPEOVER) + { + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANSHALF|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "FAILED"); + v_colmap = V_GRAYMAP; + } + else + { + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, (gametype == GT_HIDEANDSEEK) ? "HIDER" : "RUNNER"); + v_colmap = V_GREENMAP; + } + } + // Team name + else if (G_GametypeHasTeams()) + { + if (stplyr->ctfteam == 1) + { + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "RED"); + v_colmap = V_REDMAP; + } + else if (stplyr->ctfteam == 2) + { + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "BLUE"); + v_colmap = V_BLUEMAP; + } + else + v_colmap = V_GRAYMAP; + } else { - livescount = stplyr->lives; - notgreyedout = true; + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "PLAYING"); } - if (livescount == 0x7f) - V_DrawCharacter(hudinfo[HUD_LIVESNUM].x - 8, y+8, - '\x16' | 0x80 | V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, false); + // name + v_colmap |= (V_HUDTRANS|V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOBOTTOM); + if (strlen(skins[stplyr->skin].hudname) <= 5) + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); + else if (V_ThinStringWidth(skins[stplyr->skin].hudname, v_colmap) <= 40) + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); else + V_DrawThinString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); + + // Power Stones collected + if (G_RingSlingerGametype() +#ifdef HAVE_BLUA + && LUA_HudEnabled(hud_powerstones) +#endif + ) { - if (livescount > 99) - livescount = 99; - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, y+8, - V_SNAPTOLEFT|V_SNAPTOBOTTOM|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), - ((livescount > 99) ? "!!" : va("%d",livescount))); + INT32 workx = hudinfo[HUD_LIVES].x+1, j; + if ((leveltime & 1) && stplyr->powers[pw_invulnerability] && (stplyr->powers[pw_sneakers] == stplyr->powers[pw_invulnerability])) // hack; extremely unlikely to be activated unintentionally + { + for (j = 0; j < 7; ++j) // "super" indicator + { + V_DrawScaledPatch(workx, hudinfo[HUD_LIVES].y-9, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, emeraldpics[1][j]); + workx += 8; + } + } + else + { + for (j = 0; j < 7; ++j) // powerstones + { + if (stplyr->powers[pw_emeralds] & (1 << j)) + V_DrawScaledPatch(workx, hudinfo[HUD_LIVES].y-9, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, emeraldpics[1][j]); + workx += 8; + } + } } } static void ST_drawInput(void) { - const UINT8 accent = (stplyr->skincolor ? Color_Index[stplyr->skincolor-1][4] : 0); - UINT8 col, offs; + const INT32 accent = V_SNAPTOLEFT|V_SNAPTOBOTTOM|(stplyr->skincolor ? Color_Index[stplyr->skincolor-1][4] : 0); + INT32 col; + UINT8 offs; - INT32 x = hudinfo[HUD_LIVESPIC].x, y = hudinfo[HUD_LIVESPIC].y; + INT32 x = hudinfo[HUD_LIVES].x, y = hudinfo[HUD_LIVES].y; if (stplyr->powers[pw_carry] == CR_NIGHTSMODE) y -= 16; // O backing - V_DrawFill(x, y-1, 16, 16, 20); - V_DrawFill(x, y+15, 16, 1, 29); + V_DrawFill(x, y-1, 16, 16, V_SNAPTOLEFT|V_SNAPTOBOTTOM|20); + V_DrawFill(x, y+15, 16, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); if (cv_showinputjoy.value) // joystick render! { - /*V_DrawFill(x , y , 16, 1, 16); - V_DrawFill(x , y+15, 16, 1, 16); - V_DrawFill(x , y+ 1, 1, 14, 16); - V_DrawFill(x+15, y+ 1, 1, 14, 16); -- red's outline*/ + /*V_DrawFill(x , y , 16, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); + V_DrawFill(x , y+15, 16, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); + V_DrawFill(x , y+ 1, 1, 14, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); + V_DrawFill(x+15, y+ 1, 1, 14, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); -- red's outline*/ if (stplyr->cmd.sidemove || stplyr->cmd.forwardmove) { // joystick hole - V_DrawFill(x+5, y+4, 6, 6, 29); + V_DrawFill(x+5, y+4, 6, 6, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); // joystick top V_DrawFill(x+3+stplyr->cmd.sidemove/12, y+2-stplyr->cmd.forwardmove/12, - 10, 10, 29); + 10, 10, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); V_DrawFill(x+3+stplyr->cmd.sidemove/9, y+1-stplyr->cmd.forwardmove/9, 10, 10, accent); @@ -837,10 +838,10 @@ static void ST_drawInput(void) else { // just a limited, greyed out joystick top - V_DrawFill(x+3, y+11, 10, 1, 29); + V_DrawFill(x+3, y+11, 10, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); V_DrawFill(x+3, y+1, - 10, 10, 16); + 10, 10, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); } } else // arrows! @@ -854,10 +855,10 @@ static void ST_drawInput(void) else { offs = 1; - col = 16; - V_DrawFill(x- 2, y+10, 6, 1, 29); - V_DrawFill(x+ 4, y+ 9, 1, 1, 29); - V_DrawFill(x+ 5, y+ 8, 1, 1, 29); + col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; + V_DrawFill(x- 2, y+10, 6, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+ 4, y+ 9, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+ 5, y+ 8, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); } V_DrawFill(x- 2, y+ 5-offs, 6, 6, col); V_DrawFill(x+ 4, y+ 6-offs, 1, 4, col); @@ -872,12 +873,12 @@ static void ST_drawInput(void) else { offs = 1; - col = 16; - V_DrawFill(x+ 5, y+ 3, 1, 1, 29); - V_DrawFill(x+ 6, y+ 4, 1, 1, 29); - V_DrawFill(x+ 7, y+ 5, 2, 1, 29); - V_DrawFill(x+ 9, y+ 4, 1, 1, 29); - V_DrawFill(x+10, y+ 3, 1, 1, 29); + col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; + V_DrawFill(x+ 5, y+ 3, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+ 6, y+ 4, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+ 7, y+ 5, 2, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+ 9, y+ 4, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+10, y+ 3, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); } V_DrawFill(x+ 5, y- 2-offs, 6, 6, col); V_DrawFill(x+ 6, y+ 4-offs, 4, 1, col); @@ -892,10 +893,10 @@ static void ST_drawInput(void) else { offs = 1; - col = 16; - V_DrawFill(x+12, y+10, 6, 1, 29); - V_DrawFill(x+11, y+ 9, 1, 1, 29); - V_DrawFill(x+10, y+ 8, 1, 1, 29); + col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; + V_DrawFill(x+12, y+10, 6, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+11, y+ 9, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+10, y+ 8, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); } V_DrawFill(x+12, y+ 5-offs, 6, 6, col); V_DrawFill(x+11, y+ 6-offs, 1, 4, col); @@ -910,8 +911,8 @@ static void ST_drawInput(void) else { offs = 1; - col = 16; - V_DrawFill(x+ 5, y+17, 6, 1, 29); + col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; + V_DrawFill(x+ 5, y+17, 6, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); } V_DrawFill(x+ 5, y+12-offs, 6, 6, col); V_DrawFill(x+ 6, y+11-offs, 4, 1, col); @@ -927,16 +928,16 @@ static void ST_drawInput(void) else\ {\ offs = 1;\ - col = 16;\ - V_DrawFill(x+16+(xoffs), y+9+(yoffs), 10, 1, 29);\ + col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16;\ + V_DrawFill(x+16+(xoffs), y+9+(yoffs), 10, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29);\ }\ V_DrawFill(x+16+(xoffs), y+(yoffs)-offs, 10, 10, col);\ - V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, symb, false) + V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, V_SNAPTOLEFT|V_SNAPTOBOTTOM|symb, false) drawbutt( 4,-3, BT_JUMP, 'J'); drawbutt(15,-3, BT_USE, 'S'); - V_DrawFill(x+16+4, y+8, 21, 10, 20); // sundial backing + V_DrawFill(x+16+4, y+8, 21, 10, V_SNAPTOLEFT|V_SNAPTOBOTTOM|20); // sundial backing if (stplyr->mo) { UINT8 i, precision; @@ -956,7 +957,7 @@ static void ST_drawInput(void) { V_DrawFill(x+16+14-(i*xcomp)/precision, y+12-(i*ycomp)/precision, - 1, 1, 16); + 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); } if (ycomp <= 0) @@ -973,6 +974,7 @@ static void ST_drawInput(void) if (stplyr->pflags & PF_AUTOBRAKE) { V_DrawThinString(x, y, + V_SNAPTOLEFT|V_SNAPTOBOTTOM| ((!stplyr->powers[pw_carry] && (stplyr->pflags & PF_APPLYAUTOBRAKE) && !(stplyr->cmd.sidemove || stplyr->cmd.forwardmove) @@ -983,12 +985,12 @@ static void ST_drawInput(void) } if (stplyr->pflags & PF_ANALOGMODE) { - V_DrawThinString(x, y, 0, "ANALOG"); + V_DrawThinString(x, y, V_SNAPTOLEFT|V_SNAPTOBOTTOM, "ANALOG"); y -= 8; } } if (!demosynced) // should always be last, so it doesn't push anything else around - V_DrawThinString(x, y, ((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!"); + V_DrawThinString(x, y, V_SNAPTOLEFT|V_SNAPTOBOTTOM|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!"); } static void ST_drawLevelTitle(void) @@ -1067,11 +1069,7 @@ static void ST_drawFirstPersonHUD(void) UINT8 i, max = (player->powers[pw_shield] & SH_FORCEHP); for (i = 0; i <= max; i++) { - INT32 flags = (V_SNAPTORIGHT|V_SNAPTOTOP)|((i == max) ? V_HUDTRANS : V_HUDTRANSHALF); - if (splitscreen) - V_DrawSmallScaledPatch(312-(3*i), STRINGY(24)+(3*i), flags, forceshield); - else - V_DrawScaledPatch(304-(3*i), 24+(3*i), flags, forceshield); + V_DrawScaledPatch(304-(3*i), 24+(3*i), (V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP)|((i == max) ? V_HUDTRANS : V_HUDTRANSHALF), forceshield); } } else switch (player->powers[pw_shield] & SH_NOSTACK) @@ -1088,29 +1086,16 @@ static void ST_drawFirstPersonHUD(void) } if (p) - { - if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24), V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); - else - V_DrawScaledPatch(304, 24, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); - } + V_DrawScaledPatch(304, 24, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); // pw_flashing just sets the icon to flash no matter what. invulntime = player->powers[pw_flashing] ? 1 : player->powers[pw_invulnerability]; if (invulntime > 3*TICRATE || (invulntime && leveltime & 1)) - { - if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24) + 14, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility); - else - V_DrawScaledPatch(304, 24 + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility); - } + V_DrawScaledPatch(304, 24 + 28, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility); if (player->powers[pw_sneakers] > 3*TICRATE || (player->powers[pw_sneakers] && leveltime & 1)) { - if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24) + 28, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers); - else - V_DrawScaledPatch(304, 24 + 56, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers); + V_DrawScaledPatch(304, 24 + 56, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers); } p = NULL; @@ -1158,32 +1143,32 @@ static void ST_drawFirstPersonHUD(void) // Display the countdown drown numbers! if (p) - V_DrawScaledPatch(SCX((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset)), SCY(60 - SHORT(p->topoffset)), - V_NOSCALESTART|V_OFFSET|V_TRANSLUCENT, p); + V_DrawScaledPatch(SCX((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset)), SCZ(60 - SHORT(p->topoffset)), + V_PERPLAYER|V_NOSCALESTART|V_PERPLAYER|V_OFFSET|V_TRANSLUCENT, p); } static void ST_drawNightsRecords(void) { - INT32 aflag = 0; + INT32 aflag = V_PERPLAYER; if (!stplyr->texttimer) return; if (stplyr->texttimer < TICRATE/2) - aflag = (9 - 9*stplyr->texttimer/(TICRATE/2)) << V_ALPHASHIFT; + aflag |= (9 - 9*stplyr->texttimer/(TICRATE/2)) << V_ALPHASHIFT; // A "Bonus Time Start" by any other name... if (stplyr->textvar == 1) { - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(52), V_GREENMAP|aflag, M_GetText("GET TO THE GOAL!")); - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), aflag, M_GetText("SCORE MULTIPLIER START!")); + V_DrawCenteredString(BASEVIDWIDTH/2, 52, V_GREENMAP|aflag, M_GetText("GET TO THE GOAL!")); + V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag, M_GetText("SCORE MULTIPLIER START!")); if (stplyr->finishedtime) { - V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(140), aflag, "TIME:"); - V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(148), aflag, "BONUS:"); - V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(140), V_ORANGEMAP|aflag, va("%d", (stplyr->startedtime - stplyr->finishedtime)/TICRATE)); - V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(148), V_ORANGEMAP|aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100)); + V_DrawString(BASEVIDWIDTH/2 - 48, 140, aflag, "TIME:"); + V_DrawString(BASEVIDWIDTH/2 - 48, 148, aflag, "BONUS:"); + V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 140, V_ORANGEMAP|aflag, va("%d", (stplyr->startedtime - stplyr->finishedtime)/TICRATE)); + V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, 148, V_ORANGEMAP|aflag, va("%d", (stplyr->finishedtime/TICRATE) * 100)); } } @@ -1194,7 +1179,7 @@ static void ST_drawNightsRecords(void) return; // Yes, this string is an abomination. - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), aflag, + V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag, va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health, (stplyr->textvar == 3) ? M_GetText("MORE ") : "", (G_IsSpecialStage(gamemap)) ? "SPHERE" : "RING", @@ -1204,26 +1189,26 @@ static void ST_drawNightsRecords(void) // End Bonus else if (stplyr->textvar == 4) { - V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(140), aflag, (G_IsSpecialStage(gamemap)) ? "ORBS:" : "RINGS:"); - V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(148), aflag, "BONUS:"); - V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(140), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings)); - V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(148), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings * 50)); - ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 48)<lastmarescore, nightsnum, SKINCOLOR_AZURE); + V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "RINGS:"); + V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:"); + V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings)); + V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings * 50)); + ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<lastmarescore, nightsnum, SKINCOLOR_AZURE); // If new record, say so! if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore) { if (stplyr->texttimer & 16) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), V_YELLOWMAP|aflag, "* NEW RECORD *"); + V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_YELLOWMAP|aflag, "* NEW RECORD *"); } if (P_HasGrades(gamemap, stplyr->lastmare + 1)) { if (aflag) - V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, STRINGY(160), aflag, + V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag, ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]); else - V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, STRINGY(160), 0, + V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, 160, 0, ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]); } } @@ -1276,15 +1261,6 @@ static void ST_drawNiGHTSHUD(void) if (stplyr->texttimer && stplyr->textvar == 4) minlink = INT32_MAX; - if (G_IsSpecialStage(gamemap)) - { // Since special stages share score, time, rings, etc. - // disable splitscreen mode for its HUD. - if (stplyr != &players[displayplayer]) - return; - nosshack = splitscreen; - splitscreen = false; - } - // Drill meter if ( #ifdef HAVE_BLUA @@ -1296,7 +1272,7 @@ static void ST_drawNiGHTSHUD(void) INT32 dfill; UINT8 fillpatch; - if (splitscreen || nosshack) + if (splitscreen) { locx = 110; locy = 188; @@ -1313,46 +1289,29 @@ static void ST_drawNiGHTSHUD(void) else fillpatch = 0; - if (splitscreen) - { // 11-5-14 Replaced the old hack with a slightly better hack. -Red - V_DrawScaledPatch(locx, STRINGY(locy)-3, SPLITFLAGS(V_SNAPTOBOTTOM)|V_HUDTRANS, drillbar); - for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), SPLITFLAGS(V_SNAPTOBOTTOM)|V_HUDTRANS, drillfill[fillpatch]); - } - else if (nosshack) - { // Even dirtier hack-of-a-hack to draw seperate drill meters in splitscreen special stages but nothing else. - splitscreen = true; - V_DrawScaledPatch(locx, STRINGY(locy)-3, V_HUDTRANS, drillbar); - for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_HUDTRANS, drillfill[fillpatch]); - stplyr = &players[secondarydisplayplayer]; - if (stplyr->pflags & PF_DRILLING) - fillpatch = (stplyr->drillmeter & 1) + 1; - else - fillpatch = 0; - V_DrawScaledPatch(locx, STRINGY(locy-3), V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); - for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); - stplyr = &players[displayplayer]; - splitscreen = false; - } - else - { // Draw normally. <:3 - V_DrawScaledPatch(locx, locy, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); - for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); - } + V_DrawScaledPatch(locx, locy, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); + for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) + V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); // Display actual drill amount and bumper time - if (cv_debug & DBG_NIGHTSBASIC) + if (!splitscreen && (cv_debug & DBG_NIGHTSBASIC)) { if (stplyr->bumpertime) - V_DrawString(SCX(locx), SCY(locy - 8), V_NOSCALESTART|V_REDMAP|V_MONOSPACE, va("BUMPER: 0.%02d", G_TicsToCentiseconds(stplyr->bumpertime))); + V_DrawString(SCX(locx), SCZ(locy - 8), V_NOSCALESTART|V_REDMAP|V_MONOSPACE, va("BUMPER: 0.%02d", G_TicsToCentiseconds(stplyr->bumpertime))); else - V_DrawString(SCX(locx), SCY(locy - 8), V_NOSCALESTART|V_MONOSPACE, va("Drill: %3d%%", (stplyr->drillmeter*100)/(96*20))); + V_DrawString(SCX(locx), SCZ(locy - 8), V_NOSCALESTART|V_MONOSPACE, va("Drill: %3d%%", (stplyr->drillmeter*100)/(96*20))); } } + if (G_IsSpecialStage(gamemap)) + { // Since special stages share score, time, rings, etc. + // disable splitscreen mode for its HUD. + if (stplyr != &players[displayplayer]) + return; + nosshack = splitscreen; + splitscreen = false; + } + // Link drawing if ( #ifdef HAVE_BLUA @@ -1361,7 +1320,7 @@ static void ST_drawNiGHTSHUD(void) stplyr->linkcount > minlink) { skincolors_t colornum; - INT32 aflag; + INT32 aflag = V_PERPLAYER; fixed_t x, y, scale; if (stplyr->powers[pw_nights_linkfreeze] && (!(stplyr->powers[pw_nights_linkfreeze] & 2) || (stplyr->powers[pw_nights_linkfreeze] > flashingtics))) @@ -1369,22 +1328,20 @@ static void ST_drawNiGHTSHUD(void) else colornum = linkColor[((stplyr->linkcount-1 >= 300) ? 1 : 0)][((stplyr->linkcount-1) / 5) % NUMLINKCOLORS]; - aflag = ((stplyr->linktimer < 2*TICRATE/3) + aflag |= ((stplyr->linktimer < 2*TICRATE/3) ? (9 - 9*stplyr->linktimer/(2*TICRATE/3)) << V_ALPHASHIFT : 0); - if (splitscreen) + y = (nosshack ? 16+11+(BASEVIDHEIGHT/2) : 160+11)<linktimer) { @@ -1422,11 +1379,11 @@ static void ST_drawNiGHTSHUD(void) if (LUA_HudEnabled(hud_nightsrings)) { #endif - ST_DrawOverlayPatch(SCX(16), SCY(8), nbracket); + ST_DrawTopLeftOverlayPatch(16, 8, nbracket); if (G_IsSpecialStage(gamemap)) - ST_DrawOverlayPatch(SCX(24), SCY(8) + SCZ(8), nsshud); + ST_DrawTopLeftOverlayPatch(24, 16, nsshud); else - ST_DrawOverlayPatch(SCX(24), SCY(8) + SCZ(8), nhud[(leveltime/2)%12]); + ST_DrawTopLeftOverlayPatch(24, 16, nhud[(leveltime/2)%12]); if (G_IsSpecialStage(gamemap)) { @@ -1447,8 +1404,8 @@ static void ST_drawNiGHTSHUD(void) origamount = stplyr->capsule->spawnpoint->angle; I_Assert(origamount > 0); // should not happen now - ST_DrawOverlayPatch(SCX(72), SCY(8), nbracket); - ST_DrawOverlayPatch(SCX(74), SCY(8) + SCZ(4), minicaps); + ST_DrawTopLeftOverlayPatch(72, 8, nbracket); + ST_DrawTopLeftOverlayPatch(74, 8 + 4, minicaps); if (stplyr->capsule->reactiontime != 0) { @@ -1457,10 +1414,10 @@ static void ST_drawNiGHTSHUD(void) for (r = 0; r < 5; r++) { - ST_DrawOverlayPatch(SCX(230 - (7*r)), SCY(144), redstat); - ST_DrawOverlayPatch(SCX(188 - (7*r)), SCY(144), orngstat); - ST_DrawOverlayPatch(SCX(146 - (7*r)), SCY(144), yelstat); - ST_DrawOverlayPatch(SCX(104 - (7*r)), SCY(144), byelstat); + ST_DrawUnscaledOverlayPatch(SCX(230 - (7*r)), SCZ(144), redstat); + ST_DrawUnscaledOverlayPatch(SCX(188 - (7*r)), SCZ(144), orngstat); + ST_DrawUnscaledOverlayPatch(SCX(146 - (7*r)), SCZ(144), yelstat); + ST_DrawUnscaledOverlayPatch(SCX(104 - (7*r)), SCZ(144), byelstat); } amount = (origamount - stplyr->capsule->health); @@ -1479,7 +1436,7 @@ static void ST_drawNiGHTSHUD(void) if (r > 10) ++t; if (r > 5) ++t; - ST_DrawOverlayPatch(SCX(69 + (7*t)), SCY(144), bluestat); + ST_DrawUnscaledOverlayPatch(SCX(69 + (7*t)), SCZ(144), bluestat); } } } @@ -1488,27 +1445,27 @@ static void ST_drawNiGHTSHUD(void) INT32 cfill; // Lil' white box! - V_DrawScaledPatch(15, STRINGY(8) + 34, V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulebar); + V_DrawScaledPatch(15, 8 + 34, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulebar); amount = (origamount - stplyr->capsule->health); amount = (amount * length)/origamount; for (cfill = 0; cfill < amount && cfill < 88; ++cfill) - V_DrawScaledPatch(15 + cfill + 1, STRINGY(8) + 35, V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill); + V_DrawScaledPatch(15 + cfill + 1, 8 + 35, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill); } if (total_ringcount >= stplyr->capsule->health) - ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), nredar[leveltime%8]); + ST_DrawTopLeftOverlayPatch(40, 8 + 5, nredar[leveltime%8]); else - ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), narrow[(leveltime/2)%8]); + ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)%8]); } else - ST_DrawOverlayPatch(SCX(40), SCY(8) + SCZ(5), narrow[8]); + ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]); if (total_ringcount >= 100) - ST_DrawOverlayNum((total_ringcount >= 1000) ? SCX(76) : SCX(72), SCY(8) + SCZ(11), total_ringcount); + ST_DrawTopLeftOverlayNum((total_ringcount >= 1000) ? 76 : 72, 8 + 11, total_ringcount); else - ST_DrawOverlayNum(SCX(68), SCY(8) + SCZ(11), total_ringcount); + ST_DrawTopLeftOverlayNum(68, 8 + 11, total_ringcount); #ifdef HAVE_BLUA } #endif @@ -1519,9 +1476,7 @@ static void ST_drawNiGHTSHUD(void) && LUA_HudEnabled(hud_nightsscore) #endif ) - { - ST_DrawNightsOverlayNum(304<marescore, nightsnum, SKINCOLOR_AZURE); - } + ST_DrawNightsOverlayNum(304<marescore, nightsnum, SKINCOLOR_AZURE); if (!stplyr->exiting #ifdef HAVE_BLUA @@ -1536,16 +1491,16 @@ static void ST_drawNiGHTSHUD(void) fixed_t cornerx = vid.width, cornery = vid.height-SCZ(20); #define ASSISHHUDFIX(n) (n*vid.dupx) - ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(22), cornery, W_CachePatchName("NGRTIMER", PU_HUDGFX)); - ST_DrawPaddedOverlayNum(cornerx-ASSISHHUDFIX(22), cornery, G_TicsToCentiseconds(maretime), 2); - ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(46), cornery, sboperiod); + ST_DrawUnscaledOverlayPatch(cornerx-ASSISHHUDFIX(22), cornery, W_CachePatchName("NGRTIMER", PU_HUDGFX)); + ST_DrawUnscaledPaddedOverlayNum(cornerx-ASSISHHUDFIX(22), cornery, G_TicsToCentiseconds(maretime), 2); + ST_DrawUnscaledOverlayPatch(cornerx-ASSISHHUDFIX(46), cornery, sboperiod); if (maretime < 60*TICRATE) - ST_DrawOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime)); + ST_DrawUnscaledOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime)); else { - ST_DrawPaddedOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime), 2); - ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(70), cornery, sbocolon); - ST_DrawOverlayNum(cornerx-ASSISHHUDFIX(70), cornery, G_TicsToMinutes(maretime, true)); + ST_DrawUnscaledPaddedOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime), 2); + ST_DrawUnscaledOverlayPatch(cornerx-ASSISHHUDFIX(70), cornery, sbocolon); + ST_DrawUnscaledOverlayNum(cornerx-ASSISHHUDFIX(70), cornery, G_TicsToMinutes(maretime, true)); } } #undef ASSISHHUDFIX @@ -1577,10 +1532,10 @@ static void ST_drawNiGHTSHUD(void) if (flashingLeft < TICRATE/2) // Start fading out { UINT32 fadingFlag = (9 - 9*flashingLeft/(TICRATE/2)) << V_ALPHASHIFT; - V_DrawTranslucentPatch(SCX(160 - (minus5sec->width/2)), SCY(28), V_NOSCALESTART|fadingFlag, minus5sec); + V_DrawTranslucentPatch(SCX(160 - (minus5sec->width/2)), SCZ(28), V_NOSCALESTART|V_PERPLAYER|fadingFlag, minus5sec); } else - V_DrawScaledPatch(SCX(160 - (minus5sec->width/2)), SCY(28), V_NOSCALESTART, minus5sec); + V_DrawScaledPatch(SCX(160 - (minus5sec->width/2)), SCZ(28), V_NOSCALESTART|V_PERPLAYER, minus5sec); } if (realnightstime < 10) @@ -1590,7 +1545,7 @@ static void ST_drawNiGHTSHUD(void) else numbersize = 48/2; - ST_DrawNightsOverlayNum((160 + numbersize)<powers[pw_nights_superloop]) { pwr = stplyr->powers[pw_nights_superloop]; - V_DrawSmallScaledPatch(SCX(110), SCY(44), V_NOSCALESTART, W_CachePatchName("NPRUA0",PU_CACHE)); - V_DrawThinString(SCX(106), SCY(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + V_DrawSmallScaledPatch(SCX(110), SCZ(44), V_NOSCALESTART, W_CachePatchName("NPRUA0",PU_CACHE)); + V_DrawThinString(SCX(106), SCZ(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_helper]) { pwr = stplyr->powers[pw_nights_helper]; - V_DrawSmallScaledPatch(SCX(150), SCY(44), V_NOSCALESTART, W_CachePatchName("NPRUC0",PU_CACHE)); - V_DrawThinString(SCX(146), SCY(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + V_DrawSmallScaledPatch(SCX(150), SCZ(44), V_NOSCALESTART, W_CachePatchName("NPRUC0",PU_CACHE)); + V_DrawThinString(SCX(146), SCZ(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_linkfreeze]) { pwr = stplyr->powers[pw_nights_linkfreeze]; - V_DrawSmallScaledPatch(SCX(190), SCY(44), V_NOSCALESTART, W_CachePatchName("NPRUE0",PU_CACHE)); - V_DrawThinString(SCX(186), SCY(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + V_DrawSmallScaledPatch(SCX(190), SCZ(44), V_NOSCALESTART, W_CachePatchName("NPRUE0",PU_CACHE)); + V_DrawThinString(SCX(186), SCZ(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } } @@ -1653,23 +1608,23 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I patflags = V_80TRANS; } - V_DrawScaledPatch(8 + xoffs, y, V_SNAPTOLEFT|patflags, pat); + V_DrawScaledPatch(8 + xoffs, y, V_PERPLAYER|V_SNAPTOBOTTOM|patflags, pat); if (stplyr->powers[weapon] > 99) - V_DrawThinString(8 + xoffs + 1, y, V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); + V_DrawThinString(8 + xoffs + 1, y, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon])); else - V_DrawString(8 + xoffs, y, V_SNAPTOLEFT|txtflags, va("%d", stplyr->powers[weapon])); + V_DrawString(8 + xoffs, y, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon])); if (stplyr->currentweapon == wepflag) - V_DrawScaledPatch(6 + xoffs, y-2, V_SNAPTOLEFT, curweapon); + V_DrawScaledPatch(6 + xoffs, y-2, V_PERPLAYER|V_SNAPTOBOTTOM, curweapon); } else if (stplyr->ringweapons & rwflag) - V_DrawScaledPatch(8 + xoffs, y, V_SNAPTOLEFT|V_TRANSLUCENT, pat); + V_DrawScaledPatch(8 + xoffs, y, V_PERPLAYER|V_SNAPTOBOTTOM|V_TRANSLUCENT, pat); } static void ST_drawMatchHUD(void) { - const INT32 y = STRINGY(176+16)-16; // HUD_LIVESPIC + const INT32 y = 176; // HUD_LIVES INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; if (!G_RingSlingerGametype()) @@ -1678,74 +1633,30 @@ static void ST_drawMatchHUD(void) if (G_TagGametype() && !(stplyr->pflags & PF_TAGIT)) return; -#ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_weaponrings)) { -#endif + { + if (stplyr->powers[pw_infinityring]) + ST_drawWeaponRing(pw_infinityring, 0, 0, offset, y, infinityring); + else if (stplyr->rings > 0) + V_DrawScaledPatch(8 + offset, y, V_PERPLAYER|V_SNAPTOBOTTOM, normring); + else + V_DrawTranslucentPatch(8 + offset, y, V_PERPLAYER|V_SNAPTOBOTTOM|V_80TRANS, normring); - if (stplyr->powers[pw_infinityring]) - ST_drawWeaponRing(pw_infinityring, 0, 0, offset, y, infinityring); - else if (stplyr->rings > 0) - V_DrawScaledPatch(8 + offset, y, V_SNAPTOLEFT, normring); - else - V_DrawTranslucentPatch(8 + offset, y, V_SNAPTOLEFT|V_80TRANS, normring); + if (!stplyr->currentweapon) + V_DrawScaledPatch(6 + offset, y-2, V_PERPLAYER|V_SNAPTOBOTTOM, curweapon); - if (!stplyr->currentweapon) - V_DrawScaledPatch(6 + offset, y-2, V_SNAPTOLEFT, curweapon); - - offset += 20; - ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, y, autoring); - offset += 20; - ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, y, bouncering); - offset += 20; - ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, y, scatterring); - offset += 20; - ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, y, grenadering); - offset += 20; - ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, y, explosionring); - offset += 20; - ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, y, railring); - -#ifdef HAVE_BLUA + offset += 20; + ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, y, autoring); + offset += 20; + ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, y, bouncering); + offset += 20; + ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, y, scatterring); + offset += 20; + ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, y, grenadering); + offset += 20; + ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, y, explosionring); + offset += 20; + ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, y, railring); } - - if (LUA_HudEnabled(hud_powerstones)) { -#endif - - // Power Stones collected - offset = STRINGY(128); // Used for Y now - - if (stplyr->powers[pw_emeralds] & EMERALD1) - V_DrawScaledPatch(28, offset, V_SNAPTOLEFT, emeraldpics[1][0]); - - offset += 8; - - if (stplyr->powers[pw_emeralds] & EMERALD2) - V_DrawScaledPatch(40, offset, V_SNAPTOLEFT, emeraldpics[1][1]); - - if (stplyr->powers[pw_emeralds] & EMERALD6) - V_DrawScaledPatch(16, offset, V_SNAPTOLEFT, emeraldpics[1][5]); - - offset += 16; - - if (stplyr->powers[pw_emeralds] & EMERALD3) - V_DrawScaledPatch(40, offset, V_SNAPTOLEFT, emeraldpics[1][2]); - - if (stplyr->powers[pw_emeralds] & EMERALD5) - V_DrawScaledPatch(16, offset, V_SNAPTOLEFT, emeraldpics[1][4]); - - offset += 8; - - if (stplyr->powers[pw_emeralds] & EMERALD4) - V_DrawScaledPatch(28, offset, V_SNAPTOLEFT, emeraldpics[1][3]); - - offset -= 16; - - if (stplyr->powers[pw_emeralds] & EMERALD7) - V_DrawScaledPatch(28, offset, V_SNAPTOLEFT, emeraldpics[1][6]); - -#ifdef HAVE_BLUA - } -#endif } static inline void ST_drawRaceHUD(void) @@ -1776,15 +1687,15 @@ static inline void ST_drawRaceHUD(void) if (!bounce) S_StartSound(0, ((racenum == racego) ? sfx_s3kad : sfx_s3ka7)); } - V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(racenum->width))/2), (INT32)(SCY(height)), V_NOSCALESTART, racenum); + V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(racenum->width))/2), (INT32)(SCZ(height)), V_NOSCALESTART|V_PERPLAYER, racenum); } if (circuitmap) { if (stplyr->exiting) - V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), V_YELLOWMAP, "FINISHED!"); + V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, V_YELLOWMAP, "FINISHED!"); else - V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), 0, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); + V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, 0, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); } } @@ -1832,36 +1743,27 @@ static void ST_drawTagHUD(void) // Print the stuff. if (pstext[0]) - { - if (splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(168), 0, pstext); - else - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), 0, pstext); - } + V_DrawCenteredString(BASEVIDWIDTH/2, 168, V_PERPLAYER|V_SNAPTOBOTTOM, pstext); + if (pstime[0]) - { - if (splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), 0, pstime); - else - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(192), 0, pstime); - } + V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_PERPLAYER|V_SNAPTOBOTTOM, pstime); } static void ST_drawCTFHUD(void) { - INT32 i; + INT32 i, y = 176; UINT16 whichflag = 0; // Draw the flags - V_DrawSmallScaledPatch(256, (splitscreen) ? STRINGY(160) : STRINGY(176), V_HUDTRANS, rflagico); - V_DrawSmallScaledPatch(288, (splitscreen) ? STRINGY(160) : STRINGY(176), V_HUDTRANS, bflagico); + V_DrawSmallScaledPatch(256, y, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, rflagico); + V_DrawSmallScaledPatch(280, y, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, bflagico); for (i = 0; i < MAXPLAYERS; i++) { if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base - V_DrawScaledPatch(256, (splitscreen) ? STRINGY(156) : STRINGY(174), V_HUDTRANS, nonicon); + V_DrawScaledPatch(256, y-4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, nonicon); else if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base - V_DrawScaledPatch(288, (splitscreen) ? STRINGY(156) : STRINGY(174), V_HUDTRANS, nonicon); + V_DrawScaledPatch(280, y-4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, nonicon); whichflag |= players[i].gotflag; if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG)) @@ -1872,11 +1774,7 @@ static void ST_drawCTFHUD(void) if (stplyr->gotflag) { patch_t *p = (stplyr->gotflag & GF_REDFLAG) ? gotrflag : gotbflag; - - if (splitscreen) - V_DrawSmallScaledPatch(312, STRINGY(24) + 42, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); - else - V_DrawScaledPatch(304, 24 + 84, V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); + V_DrawScaledPatch(304, 24 + 84, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); } // Display a countdown timer showing how much time left until the flag your team dropped returns to base. @@ -1885,13 +1783,13 @@ static void ST_drawCTFHUD(void) if (redflag && redflag->fuse > 1) { sprintf(timeleft, "%u", (redflag->fuse / TICRATE)); - V_DrawCenteredString(268, STRINGY(184), V_YELLOWMAP|V_HUDTRANS, timeleft); + V_DrawCenteredString(268, y+8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, timeleft); } if (blueflag && blueflag->fuse > 1) { sprintf(timeleft, "%u", (blueflag->fuse / TICRATE)); - V_DrawCenteredString(300, STRINGY(184), V_YELLOWMAP|V_HUDTRANS, timeleft); + V_DrawCenteredString(300, y+8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, timeleft); } } } @@ -1909,7 +1807,7 @@ static void ST_drawSpecialStageHUD(void) if (sstimer) { - V_DrawString(hudinfo[HUD_TIMELEFT].x, STRINGY(hudinfo[HUD_TIMELEFT].y), V_HUDTRANS, M_GetText("TIME LEFT")); + V_DrawString(hudinfo[HUD_TIMELEFT].x, hudinfo[HUD_TIMELEFT].y, V_PERPLAYER|V_HUDTRANS, M_GetText("TIME LEFT")); ST_DrawNumFromHud(HUD_TIMELEFTNUM, sstimer/TICRATE, V_HUDTRANS); } else @@ -1952,7 +1850,7 @@ static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offse interval = 0; } - V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, STRINGY(hudinfo[HUD_HUNTPICS].y), V_HUDTRANS, patches[i]); + V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, V_PERPLAYER|V_HUDTRANS, patches[i]); return interval; } @@ -2067,13 +1965,12 @@ static void ST_overlayDrawer(void) #endif ST_drawRings(); - ST_drawLivesPic(); // always do on mystic's request - allows us to kill "RED/BLUE TEAM" text - if (G_GametypeUsesLives() + if (!modeattacking #ifdef HAVE_BLUA && LUA_HudEnabled(hud_lives) #endif ) - ST_drawLives(); + ST_drawLivesArea(); } } @@ -2113,7 +2010,7 @@ static void ST_overlayDrawer(void) } if (p) - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, STRINGY(BASEVIDHEIGHT/2 - (SHORT(p->height)/2)) - (splitscreen ? 4 : 0), (stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS), p); + V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, BASEVIDHEIGHT/2 - (SHORT(p->height)/2), V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS), p); } @@ -2121,22 +2018,21 @@ static void ST_overlayDrawer(void) { // Countdown timer for Race Mode if (countdown) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(176), 0, va("%d", countdown/TICRATE)); + V_DrawCenteredString(BASEVIDWIDTH/2, 176, V_PERPLAYER, va("%d", countdown/TICRATE)); // If you are in overtime, put a big honkin' flashin' message on the screen. if (G_RingSlingerGametype() && cv_overtime.value - && (leveltime > (timelimitintics + TICRATE/2)) && cv_timelimit.value && (leveltime/TICRATE % 2 == 0)) - { - if (splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(168), 0, M_GetText("OVERTIME!")); - else - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(184), 0, M_GetText("OVERTIME!")); - } + && (leveltime > (timelimitintics + TICRATE/2)) && cv_timelimit.value && (leveltime/TICRATE % 2 == 0)) + V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_PERPLAYER, M_GetText("OVERTIME!")); // Draw Match-related stuff //\note Match HUD is drawn no matter what gametype. // ... just not if you're a spectator. - if (!stplyr->spectator) + if (!stplyr->spectator +#ifdef HAVE_BLUA + && (LUA_HudEnabled(hud_weaponrings)) +#endif + ) ST_drawMatchHUD(); // Race HUD Stuff @@ -2160,7 +2056,7 @@ static void ST_overlayDrawer(void) ST_doHuntIconsAndSound(); if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1)) - V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, STRINGY(hudinfo[HUD_GRAVBOOTSICO].y), V_SNAPTORIGHT, gravboots); + V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, hudinfo[HUD_GRAVBOOTSICO].y, V_PERPLAYER|V_SNAPTORIGHT, gravboots); if(!P_IsLocalPlayer(stplyr)) { @@ -2219,12 +2115,10 @@ static void ST_overlayDrawer(void) total /= 4; } - if (exiting >= total) - ; - else + if (exiting < total) { total -= exiting; - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(124), 0, va(M_GetText("%d more player%s required to exit."), total, ((total == 1) ? "" : "s"))); + V_DrawCenteredString(BASEVIDWIDTH/2, 124, V_PERPLAYER, va(M_GetText("%d more player%s required to exit."), total, ((total == 1) ? "" : "s"))); if (!splitscreen) V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); } @@ -2234,7 +2128,7 @@ static void ST_overlayDrawer(void) else if (gametype == GT_HIDEANDSEEK && (!stplyr->spectator && !(stplyr->pflags & PF_TAGIT)) && (leveltime > hidetime * TICRATE)) { - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(116), 0, M_GetText("You cannot move while hiding.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 116, V_PERPLAYER, M_GetText("You cannot move while hiding.")); if (!splitscreen) V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); } @@ -2242,9 +2136,9 @@ static void ST_overlayDrawer(void) { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; if (respawntime > 0 && !stplyr->spectator) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, va(M_GetText("Respawn in: %d second%s."), respawntime, respawntime == 1 ? "" : "s")); + V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, va(M_GetText("Respawn in: %d second%s."), respawntime, respawntime == 1 ? "" : "s")); else - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Jump to respawn.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Jump to respawn.")); } else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE) #ifdef HAVE_BLUA @@ -2252,14 +2146,14 @@ static void ST_overlayDrawer(void) #endif ) { - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), V_HUDTRANSHALF, M_GetText("You are a spectator.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 60, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You are a spectator.")); if (G_GametypeHasTeams()) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to be assigned to a team.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to be assigned to a team.")); else if (G_IsSpecialStage(gamemap) && useNightsSS) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("You cannot play until the stage has ended.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You cannot play until the stage has ended.")); else if (gametype == GT_COOP && stplyr->lives <= 0) { - if (cv_cooplives.value == 1 + if (cv_cooplives.value == 2 && (netgame || multiplayer)) { INT32 i; @@ -2276,18 +2170,14 @@ static void ST_overlayDrawer(void) } if (i != MAXPLAYERS) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132)-(splitscreen ? 12 : 0), V_HUDTRANSHALF, M_GetText("You'll steal a life on respawn.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You'll steal a life on respawn.")); } } else if (gametype != GT_COOP) - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to enter the game.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to enter the game.")); if (!splitscreen) - { - V_DrawCenteredString(BASEVIDWIDTH/2, 148, V_HUDTRANSHALF, M_GetText("Press F12 to watch another player.")); - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_HUDTRANSHALF, M_GetText("Press Jump to float and Spin to sink.")); - } - else - V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(136), V_HUDTRANSHALF, M_GetText("Press Jump to float and Spin to sink.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_HUDTRANSHALF, M_GetText("Press F12 to watch another player.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 148, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Jump to float and Spin to sink.")); } } diff --git a/src/st_stuff.h b/src/st_stuff.h index 9be37b502..2294c35e4 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -77,33 +77,23 @@ typedef struct typedef enum { - HUD_LIVESNAME, - HUD_LIVESPIC, - HUD_LIVESNUM, - HUD_LIVESX, + HUD_LIVES, HUD_RINGS, - HUD_RINGSSPLIT, HUD_RINGSNUM, - HUD_RINGSNUMSPLIT, HUD_RINGSNUMTICS, HUD_SCORE, HUD_SCORENUM, HUD_TIME, - HUD_TIMESPLIT, HUD_MINUTES, - HUD_MINUTESSPLIT, HUD_TIMECOLON, - HUD_TIMECOLONSPLIT, HUD_SECONDS, - HUD_SECONDSSPLIT, HUD_TIMETICCOLON, HUD_TICS, HUD_SS_TOTALRINGS, - HUD_SS_TOTALRINGS_SPLIT, HUD_GETRINGS, HUD_GETRINGSNUM, diff --git a/src/v_video.c b/src/v_video.c index 20fe9229e..c9ab2933d 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -15,6 +15,8 @@ #include "doomdef.h" #include "r_local.h" +#include "p_local.h" // stplyr +#include "g_game.h" // players #include "v_video.h" #include "hu_stuff.h" #include "r_draw.h" @@ -624,8 +626,50 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t x -= FixedMul(SHORT(patch->leftoffset)<>=1; + if (splitscreen && (scrn & V_PERPLAYER)) + { + fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1); + fdup >>= 1; + rowfrac <<= 1; + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1)); + colfrac <<= 1; + x >>= 1; + if (stplyr == &players[displayplayer]) + scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + else if (stplyr == &players[secondarydisplayplayer]) + { + x += adjustx; + scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + y += adjusty; + scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + x += adjustx; + y += adjusty; + scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + scrn &= ~V_SNAPTOBOTTOM; + else //if (stplyr == &players[secondarydisplayplayer]) + { + y += adjusty; + scrn &= ~V_SNAPTOTOP; + } + } + } desttop = screens[scrn&V_PARAMMASK]; @@ -670,9 +714,9 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t if (vid.height != BASEVIDHEIGHT * dupy) { // same thing here - if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + /*if ((scrn & (V_PERPLAYER|V_SNAPTOBOTTOM)) == (V_PERPLAYER|V_SNAPTOBOTTOM)) y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); - else if (scrn & V_SNAPTOBOTTOM) + else */if (scrn & V_SNAPTOBOTTOM) y += (vid.height - (BASEVIDHEIGHT * dupy)); else if (!(scrn & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; @@ -835,7 +879,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (vid.height != BASEVIDHEIGHT * dupy) { // same thing here - if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + if ((scrn & (V_PERPLAYER|V_SNAPTOBOTTOM)) == (V_PERPLAYER|V_SNAPTOBOTTOM)) y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); else if (scrn & V_SNAPTOBOTTOM) y += (vid.height - (BASEVIDHEIGHT * dupy)); diff --git a/src/v_video.h b/src/v_video.h index f9fd475f4..66fd2f430 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -113,7 +113,7 @@ extern RGBA_t *pMasterPalette; #define V_WRAPY 0x20000000 // Don't clamp texture on Y (for HW mode) #define V_NOSCALESTART 0x40000000 // don't scale x, y, start coords -#define V_SPLITSCREEN 0x80000000 +#define V_PERPLAYER 0x80000000 // defines for old functions #define V_DrawPatch(x,y,s,p) V_DrawFixedPatch((x)< Date: Sun, 21 Jan 2018 12:56:38 +0000 Subject: [PATCH 024/212] * Update V_DrawCroppedPatch and V_DrawFill to support V_PERPLAYER. * Fix some mistakes in the comments for v_video.h. --- src/hardware/hw_draw.c | 81 ++++++++++++++++++++++++------- src/v_video.c | 106 ++++++++++++++++++++++++++++++++++++++--- src/v_video.h | 4 +- 3 files changed, 166 insertions(+), 25 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index f902b4802..0a09a2b41 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -194,36 +194,22 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, float adjustx = ((option & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f; pdupx /= 2; cx /= 2; - if (stplyr == &players[displayplayer]) - option &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; - else if (stplyr == &players[secondarydisplayplayer]) - { + if (stplyr == &players[secondarydisplayplayer]) cx += adjustx; - option &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; - } else if (stplyr == &players[thirddisplayplayer]) - { cy += adjusty; - option &= ~V_SNAPTOTOP|V_SNAPTORIGHT; - } - else //if (stplyr == &players[fourthdisplayplayer]) + else if (stplyr == &players[fourthdisplayplayer]) { cx += adjustx; cy += adjusty; - option &= ~V_SNAPTOTOP|V_SNAPTOLEFT; } } else #endif // 2 players { - if (stplyr == &players[displayplayer]) - option &= ~V_SNAPTOBOTTOM; - else //if (stplyr == &players[secondarydisplayplayer]) - { + if (stplyr == &players[secondarydisplayplayer]) cy += adjusty; - option &= ~V_SNAPTOTOP; - } } } @@ -323,6 +309,37 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal if (option & V_NOSCALESTART) sdupx = sdupy = 2.0f; + if (splitscreen && (option & V_PERPLAYER)) + { + float adjusty = ((option & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + pdupy /= 2; + cy /= 2; + // unlike software no need to adjust texture sourcing +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + float adjustx = ((option & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f; + pdupx /= 2; + cx /= 2; + if (stplyr == &players[secondarydisplayplayer]) + cx += adjustx; + else if (stplyr == &players[thirddisplayplayer]) + cy += adjusty; + if (stplyr == &players[fourthdisplayplayer]) + { + cx += adjustx; + cy += adjusty; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[secondarydisplayplayer]) + cy += adjusty; + } + } + v[0].x = v[3].x = (cx*sdupx - gpatch->leftoffset * pdupx) / vid.width - 1; v[2].x = v[1].x = (cx*sdupx + ((w) - gpatch->leftoffset) * pdupx) / vid.width - 1; v[0].y = v[1].y = 1 - (cy*sdupy - gpatch->topoffset * pdupy) / vid.height; @@ -718,6 +735,36 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) if (color & V_NOSCALESTART) sdupx = sdupy = 2.0f; + if (splitscreen && (color & V_PERPLAYER)) + { + float adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + w >>= 1; + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + float adjustx = ((color & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f; + w >>= 1; + x >>= 1; + if (stplyr == &players[secondarydisplayplayer]) + x += adjustx; + else if (stplyr == &players[thirddisplayplayer]) + y += adjusty; + else if (stplyr == &players[fourthdisplayplayer]) + { + x += adjustx; + y += adjusty; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[secondarydisplayplayer]) + y += adjusty; + } + } + v[0].x = v[3].x = (x*sdupx)/vid.width - 1; v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1; v[0].y = v[1].y = 1-(y*sdupy)/vid.height; diff --git a/src/v_video.c b/src/v_video.c index c9ab2933d..10d2d9af5 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -714,9 +714,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t if (vid.height != BASEVIDHEIGHT * dupy) { // same thing here - /*if ((scrn & (V_PERPLAYER|V_SNAPTOBOTTOM)) == (V_PERPLAYER|V_SNAPTOBOTTOM)) - y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); - else */if (scrn & V_SNAPTOBOTTOM) + if (scrn & V_SNAPTOBOTTOM) y += (vid.height - (BASEVIDHEIGHT * dupy)); else if (!(scrn & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; @@ -837,6 +835,60 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ y -= FixedMul(SHORT(patch->topoffset)<leftoffset)<>= 1; + rowfrac <<= 1; + y >>= 1; + sy >>= 1; + h >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1)); + colfrac <<= 1; + x >>= 1; + sx >>= 1; + w >>= 1; + if (stplyr == &players[displayplayer]) + scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + else if (stplyr == &players[secondarydisplayplayer]) + { + x += adjustx; + sx += adjustx; + scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + y += adjusty; + sy += adjusty; + scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + x += adjustx; + sx += adjustx; + y += adjusty; + sy += adjusty; + scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + scrn &= ~V_SNAPTOBOTTOM; + else //if (stplyr == &players[secondarydisplayplayer]) + { + y += adjusty; + sy += adjusty; + scrn &= ~V_SNAPTOTOP; + } + } + } + desttop = screens[scrn&V_PARAMMASK]; if (!desttop) @@ -879,9 +931,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (vid.height != BASEVIDHEIGHT * dupy) { // same thing here - if ((scrn & (V_PERPLAYER|V_SNAPTOBOTTOM)) == (V_PERPLAYER|V_SNAPTOBOTTOM)) - y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); - else if (scrn & V_SNAPTOBOTTOM) + if (scrn & V_SNAPTOBOTTOM) y += (vid.height - (BASEVIDHEIGHT * dupy)); else if (!(scrn & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; @@ -1042,6 +1092,50 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) } #endif + if (splitscreen && (c & V_PERPLAYER)) + { + fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1; + h >>= 1; + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1; + w >>= 1; + x >>= 1; + if (stplyr == &players[displayplayer]) + c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + else if (stplyr == &players[secondarydisplayplayer]) + { + x += adjustx; + c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + y += adjusty; + c &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + x += adjustx; + y += adjusty; + c &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + c &= ~V_SNAPTOBOTTOM; + else //if (stplyr == &players[secondarydisplayplayer]) + { + y += adjusty; + c &= ~V_SNAPTOTOP; + } + } + } + if (!(c & V_NOSCALESTART)) { INT32 dupx = vid.dupx, dupy = vid.dupy; diff --git a/src/v_video.h b/src/v_video.h index 66fd2f430..c5dfd35a5 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -112,8 +112,8 @@ extern RGBA_t *pMasterPalette; #define V_WRAPX 0x10000000 // Don't clamp texture on X (for HW mode) #define V_WRAPY 0x20000000 // Don't clamp texture on Y (for HW mode) -#define V_NOSCALESTART 0x40000000 // don't scale x, y, start coords -#define V_PERPLAYER 0x80000000 +#define V_NOSCALESTART 0x40000000 // don't scale x, y, start coords +#define V_PERPLAYER 0x80000000 // automatically adjust coordinates/scaling for splitscreen mode // defines for old functions #define V_DrawPatch(x,y,s,p) V_DrawFixedPatch((x)< Date: Mon, 22 Jan 2018 18:41:14 +0000 Subject: [PATCH 025/212] Hardcoded LUA_THZT from THZ1.wad, giving us the funny-looking steam whistle tree This concludes hardcoding of scenery items for THZ --- src/dehacked.c | 18 +++++++++++++ src/info.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 19 ++++++++++++++ src/p_mobj.c | 8 ++++++ 4 files changed, 116 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 067cea460..97c1cef03 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4714,6 +4714,22 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_THZFLOWERB", // THZ1 Spin flower (red) "S_THZFLOWERC", // THZ1 Spin flower (yellow) + // THZ Steam Whistle tree/bush + "S_THZTREE", + "S_THZTREEBRANCH1", + "S_THZTREEBRANCH2", + "S_THZTREEBRANCH3", + "S_THZTREEBRANCH4", + "S_THZTREEBRANCH5", + "S_THZTREEBRANCH6", + "S_THZTREEBRANCH7", + "S_THZTREEBRANCH8", + "S_THZTREEBRANCH9", + "S_THZTREEBRANCH10", + "S_THZTREEBRANCH11", + "S_THZTREEBRANCH12", + "S_THZTREEBRANCH13", + // THZ Alarm "S_ALARM1", @@ -6171,6 +6187,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_THZFLOWER1", "MT_THZFLOWER2", "MT_THZFLOWER3", + "MT_THZTREE", // Steam whistle tree/bush + "MT_THZTREEBRANCH", // branch of said tree "MT_ALARM", // Deep Sea Scenery diff --git a/src/info.c b/src/info.c index c2eccd421..59930f3eb 100644 --- a/src/info.c +++ b/src/info.c @@ -193,6 +193,7 @@ char sprnames[NUMSPRITES + 1][5] = "THZP", // THZ1 Steam Flower "FWR5", // THZ1 Spin flower (red) "FWR6", // THZ1 Spin flower (yellow) + "THZT", // Steam Whistle tree/bush "ALRM", // THZ2 Alarm // Deep Sea Scenery @@ -1918,6 +1919,22 @@ state_t states[NUMSTATES] = {SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERB {SPR_FWR6, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERC + // THZ Steam Whistle tree/bush + {SPR_THZT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_THZTREE + {SPR_THZT, 1|FF_PAPERSPRITE, 40, {NULL}, 0, 0, S_THZTREEBRANCH2}, // S_THZTREEBRANCH1 + {SPR_THZT, 2|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH3}, // S_THZTREEBRANCH2 + {SPR_THZT, 3|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH4}, // S_THZTREEBRANCH3 + {SPR_THZT, 4|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH5}, // S_THZTREEBRANCH4 + {SPR_THZT, 5|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH6}, // S_THZTREEBRANCH5 + {SPR_THZT, 6|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH7}, // S_THZTREEBRANCH6 + {SPR_THZT, 7|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH8}, // S_THZTREEBRANCH7 + {SPR_THZT, 8|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH9}, // S_THZTREEBRANCH8 + {SPR_THZT, 9|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH10}, // S_THZTREEBRANCH9 + {SPR_THZT, 10|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH11}, // S_THZTREEBRANCH10 + {SPR_THZT, 11|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH12}, // S_THZTREEBRANCH11 + {SPR_THZT, 12|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH13}, // S_THZTREEBRANCH12 + {SPR_THZT, 13|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH1}, // S_THZTREEBRANCH13 + // THZ Alarm {SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1 @@ -8670,6 +8687,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_THZTREE + 904, // doomednum + S_THZTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_THZTREEBRANCH + -1, // doomednum + S_THZTREEBRANCH1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 1*FRACUNIT, // radius + 1*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_ALARM 901, // doomednum S_ALARM1, // spawnstate diff --git a/src/info.h b/src/info.h index 92786e376..03774ae5e 100644 --- a/src/info.h +++ b/src/info.h @@ -393,6 +393,7 @@ typedef enum sprite SPR_THZP, // THZ1 Steam Flower SPR_FWR5, // THZ1 Spin flower (red) SPR_FWR6, // THZ1 Spin flower (yellow) + SPR_THZT, // Steam Whistle tree/bush SPR_ALRM, // THZ2 Alarm // Deep Sea Scenery @@ -2026,6 +2027,22 @@ typedef enum state S_THZFLOWERB, // THZ1 Spin flower (red) S_THZFLOWERC, // THZ1 Spin flower (yellow) + // THZ Steam Whistle tree/bush + S_THZTREE, + S_THZTREEBRANCH1, + S_THZTREEBRANCH2, + S_THZTREEBRANCH3, + S_THZTREEBRANCH4, + S_THZTREEBRANCH5, + S_THZTREEBRANCH6, + S_THZTREEBRANCH7, + S_THZTREEBRANCH8, + S_THZTREEBRANCH9, + S_THZTREEBRANCH10, + S_THZTREEBRANCH11, + S_THZTREEBRANCH12, + S_THZTREEBRANCH13, + // THZ Alarm S_ALARM1, @@ -3503,6 +3520,8 @@ typedef enum mobj_type MT_THZFLOWER1, MT_THZFLOWER2, MT_THZFLOWER3, + MT_THZTREE, // Steam whistle tree/bush + MT_THZTREEBRANCH, // branch of said tree MT_ALARM, // Deep Sea Scenery diff --git a/src/p_mobj.c b/src/p_mobj.c index ca921ba9c..a4f5c8151 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10096,6 +10096,14 @@ domaceagain: mobj->destscale = mobj->scale; } break; + case MT_THZTREE: + { // Spawn the branches + angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); + P_SpawnMobjFromMobj(mobj, 1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; + P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; + P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; + } + break; default: break; } From dd3b39089f4e339399011632ebb554f5331cd323 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 22 Jan 2018 23:29:57 +0000 Subject: [PATCH 026/212] * Improve the rendering of emerald coinboxes. * Make emeralds fall onto the end tally. https://cdn.discordapp.com/attachments/400761370800422922/405122775272128512/srb20003.gif --- src/y_inter.c | 52 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index eb5e742ea..ebadfd324 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -176,14 +176,10 @@ static void Y_IntermissionTokenDrawer(void) lowy = BASEVIDHEIGHT - 32 - 8; temp = SHORT(tokenicon->height)/2; - if (!(emeralds & EMERALD1)) em = 0; - else if (!(emeralds & EMERALD2)) em = 1; - else if (!(emeralds & EMERALD3)) em = 2; - else if (!(emeralds & EMERALD4)) em = 3; - else if (!(emeralds & EMERALD5)) em = 4; - else if (!(emeralds & EMERALD6)) em = 5; - else if (!(emeralds & EMERALD7)) em = 6; - else return; + em = 0; + while (emeralds & (1 << em)) + if (++em == 7) + return; if (tallydonetic != -1) { @@ -325,7 +321,7 @@ void Y_IntermissionDrawer(void) Y_IntermissionTokenDrawer(); // draw the header - if (intertic <= TICRATE) + if (intertic <= 2*TICRATE) animatetic = 0; else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0') animatetic = intertic; @@ -378,12 +374,46 @@ void Y_IntermissionDrawer(void) //if (intertic & 1) { INT32 emeraldx = 152 - 3*28; + INT32 em = (gamemap - sstage_start); + for (i = 0; i < 7; ++i) { - if ((emeralds & (1 << i)) && ((intertic & 1) || i != (gamemap + 1 - sstage_start))) + if ((i != em) && !(intertic & 1) && (emeralds & (1 << i))) V_DrawScaledPatch(emeraldx, 74, 0, emeraldpics[0][i]); emeraldx += 28; } + + if (em < 7) + { + static UINT8 emeraldbounces = 0; + static INT32 emeraldmomy = 20; + static INT32 emeraldy = -40; + + emeraldx = 152 + (em-3)*28; + + if (intertic <= 1) + { + emeraldbounces = 0; + emeraldmomy = 20; + emeraldy = -40; + } + else + { + if (emeraldbounces < 3) + { + emeraldmomy += 1; + emeraldy += emeraldmomy; + if (emeraldy > 74) + { + S_StartSound(NULL, sfx_tink); // tink + emeraldbounces++; + emeraldmomy = -(emeraldmomy/2); + emeraldy = 74; + } + } + V_DrawScaledPatch(emeraldx, emeraldy, 0, emeraldpics[0][em]); + } + } } V_DrawScaledPatch(152, 108, 0, data.spec.bonuspatch); @@ -812,7 +842,7 @@ void Y_Ticker(void) tallydonetic = -1; } - if (intertic < TICRATE) // one second pause before tally begins + if (intertic < 2*TICRATE) // one second pause before tally begins return; for (i = 0; i < MAXPLAYERS; i++) From ab0296d1c1f3380a4e5d554170826a4f23dd0ce1 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 23 Jan 2018 23:13:56 +0000 Subject: [PATCH 027/212] Added a failure animation if you don't get the emerald. https://cdn.discordapp.com/attachments/402861856219463681/405477752972509185/srb20004.gif --- src/y_inter.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index ebadfd324..063268626 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -399,13 +399,29 @@ void Y_IntermissionDrawer(void) } else { - if (emeraldbounces < 3) + if (emeralds & (1 << em)) + { + if (emeraldbounces < 3) + { + emeraldmomy += 1; + emeraldy += emeraldmomy; + if (emeraldy > 74) + { + S_StartSound(NULL, sfx_tink); // tink + emeraldbounces++; + emeraldmomy = -(emeraldmomy/2); + emeraldy = 74; + } + } + } + else { emeraldmomy += 1; emeraldy += emeraldmomy; - if (emeraldy > 74) + emeraldx += intertic - 6; + if (emeraldbounces < 1 && emeraldy > 74) { - S_StartSound(NULL, sfx_tink); // tink + S_StartSound(NULL, sfx_shldls); // nope emeraldbounces++; emeraldmomy = -(emeraldmomy/2); emeraldy = 74; From eba0978a0015527c6536596420253a7452cbabdb Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 24 Jan 2018 02:07:30 +0000 Subject: [PATCH 028/212] RIP smiles --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 52cf179e7..8a8e23654 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6165,7 +6165,7 @@ static void M_DrawLoadGameData(void) { V_DrawSmallScaledPatch(x+2, y+64, 0, savselp[5]); } -#ifndef PERFECTSAVE // disabled, don't touch +#ifdef PERFECTSAVE // disabled on request else if ((savegameinfo[savetodraw].skinnum == 1) && (savegameinfo[savetodraw].lives == 99) && (savegameinfo[savetodraw].gamemap & 8192) From 0cc4b8d6db42e403b2692eb5e8f97ff0686c2320 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 6 Feb 2018 14:50:08 -0500 Subject: [PATCH 029/212] Smoother MD2 interpolation --- src/hardware/hw_md2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index f59c1d4fc..d1315979a 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1347,7 +1347,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->header.numFrames; buff = md2->model->glCommandBuffer; curr = &md2->model->frames[frame]; - if (cv_grmd2.value == 1) + if (cv_grmd2.value == 1 && tics <= durs) { // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation if (spr->mobj->frame & FF_ANIMATE) From bf88407d00858d2523e41dda5d24cc8485a659b8 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 9 Feb 2018 17:23:35 +0000 Subject: [PATCH 030/212] Make sure both software and OpenGL ignore patches that are completely out of a multi-patch texture's bounds. This fixes OpenGL in particular crashing because of such a weird situation. --- src/hardware/hw_cache.c | 16 ++++++++++++++-- src/r_data.c | 11 +++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 78fc31afc..919bbb31c 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -62,19 +62,31 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, UINT8 texel; UINT16 texelu16; + if (!ptexturewidth) + return; + x1 = originx; x2 = x1 + SHORT(realpatch->width); + if (x1 > ptexturewidth || x2 < 0) + return; // patch not located within texture's x bounds, ignore + + if (originy > ptextureheight || (originy + SHORT(realpatch->height)) < 0) + return; // patch not located within texture's y bounds, ignore + + // patch is actually inside the texture! + // now check if texture is partly off-screen and adjust accordingly + + // left edge if (x1 < 0) x = 0; else x = x1; + // right edge if (x2 > ptexturewidth) x2 = ptexturewidth; - if (!ptexturewidth) - return; col = x * pblockwidth / ptexturewidth; ncols = ((x2 - x) * pblockwidth) / ptexturewidth; diff --git a/src/r_data.c b/src/r_data.c index c4209fad6..169b04201 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -439,11 +439,22 @@ static UINT8 *R_GenerateTexture(size_t texnum) height = SHORT(realpatch->height); x2 = x1 + width; + if (x1 > texture->width || x2 < 0) + continue; // patch not located within texture's x bounds, ignore + + if (patch->originy > texture->height || (patch->originy + height) < 0) + continue; // patch not located within texture's y bounds, ignore + + // patch is actually inside the texture! + // now check if texture is partly off-screen and adjust accordingly + + // left edge if (x1 < 0) x = 0; else x = x1; + // right edge if (x2 > texture->width) x2 = texture->width; From c1b48ea79fb53cac98b1a5d30dcbfc65973c9ce7 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 12 Feb 2018 17:47:31 +0000 Subject: [PATCH 031/212] * Total overhaul of V_DrawFadeScreen(color, strength! - controllable strengths between 0-31 for COLORMAP lump like before - arbitrary colour indices in the palette via TRANSMAP lumps, with strengths 0-9 - exposed to Lua as v.fadeScreen(color, strength)! * Remove last vestiges of V_STATICPATCH. --- src/d_clisrv.c | 2 +- src/hardware/hw_draw.c | 28 ++++++++++++++-------------- src/hardware/hw_main.h | 2 +- src/lua_hudlib.c | 18 ++++++++++++++++++ src/m_menu.c | 2 +- src/v_video.c | 36 +++++++++++++++++++++++++++--------- src/v_video.h | 2 +- 7 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 72f60aa9f..6a871057e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1125,7 +1125,7 @@ static inline void CL_DrawConnectionStatus(void) INT32 ccstime = I_GetTime(); // Draw background fade - V_DrawFadeScreen(); + V_DrawFadeScreen(0xFF00, 16); // Draw the bottom box. M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1); diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 0a09a2b41..0e10c6473 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -154,9 +154,7 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); - if (alphalevel == 12) - alphalevel = 0; - else if (alphalevel >= 10 && alphalevel < 13) + if (alphalevel >= 10 && alphalevel < 13) return; // make patch ready in hardware cache @@ -283,9 +281,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); - if (alphalevel == 12) - alphalevel = 0; - else if (alphalevel >= 10 && alphalevel < 13) + if (alphalevel >= 10 && alphalevel < 13) return; // make patch ready in hardware cache @@ -494,18 +490,14 @@ void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum // | /| // |/ | // 0--1 -void HWR_FadeScreenMenuBack(UINT32 color, INT32 height) +void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) { FOutVector v[4]; FSurfaceInfo Surf; - // setup some neat-o translucency effect - if (!height) //cool hack 0 height is full height - height = vid.height; - v[0].x = v[3].x = -1.0f; v[2].x = v[1].x = 1.0f; - v[0].y = v[1].y = 1.0f-((height<<1)/(float)vid.height); + v[0].y = v[1].y = -1.0f; v[2].y = v[3].y = 1.0f; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; @@ -514,8 +506,16 @@ void HWR_FadeScreenMenuBack(UINT32 color, INT32 height) v[0].tow = v[1].tow = 1.0f; v[2].tow = v[3].tow = 0.0f; - Surf.FlatColor.rgba = UINT2RGBA(color); - Surf.FlatColor.s.alpha = (UINT8)((0xff/2) * ((float)height / vid.height)); //calum: varies console alpha + if (color & 0xFF00) // Do COLORMAP fade. + { + Surf.FlatColor.rgba = UINT2RGBA(0x01010160); + Surf.FlatColor.s.alpha = 0xFF - (strength*8); + } + else // Do TRANSMAP** fade. + { + Surf.FlatColor.rgba = pLocalPalette[color].rgba; + Surf.FlatColor.s.alpha = (UINT8)((float)(10-strength)*25.5f); + } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index cb49f817c..1ae2d8fc3 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -33,7 +33,7 @@ void HWR_Shutdown(void); void HWR_clearAutomap(void); void HWR_drawAMline(const fline_t *fl, INT32 color); -void HWR_FadeScreenMenuBack(UINT32 color, INT32 height); +void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength); void HWR_DrawConsoleBack(UINT32 color, INT32 height); void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player); void HWR_RenderPlayerView(INT32 viewnumber, player_t *player); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 97835d845..c592cc2f1 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -679,6 +679,23 @@ static int libd_getColormap(lua_State *L) return 1; } +static int libd_fadeScreen(lua_State *L) +{ + UINT16 color = luaL_checkinteger(L, 1); + UINT8 strength = luaL_checkinteger(L, 2); + const UINT8 maxstrength = ((color & 0xFF00) ? 31 : 9); + + HUDONLY + if (!strength) + return 0; + + if (strength > maxstrength) + return luaL_error(L, "%s fade strength %d out of range (0 - %d)", ((color & 0xFF00) ? "COLORMAP" : "TRANSMAP"), strength, maxstrength); + + V_DrawFadeScreen(color, strength); + return 0; +} + static int libd_width(lua_State *L) { HUDONLY @@ -733,6 +750,7 @@ static luaL_Reg lib_draw[] = { {"drawString", libd_drawString}, {"stringWidth", libd_stringWidth}, {"getColormap", libd_getColormap}, + {"fadeScreen", libd_fadeScreen}, {"width", libd_width}, {"height", libd_height}, {"dupx", libd_dupx}, diff --git a/src/m_menu.c b/src/m_menu.c index 8a8e23654..9f1b7efe7 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2583,7 +2583,7 @@ void M_Drawer(void) { // now that's more readable with a faded background (yeah like Quake...) if (!WipeInAction) - V_DrawFadeScreen(); + V_DrawFadeScreen(0xFF00, 16); if (currentMenu->drawroutine) currentMenu->drawroutine(); // call current menu Draw routine diff --git a/src/v_video.c b/src/v_video.c index 10d2d9af5..daf0514d5 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1321,25 +1321,43 @@ void V_DrawPatchFill(patch_t *pat) // // Fade all the screen buffer, so that the menu is more readable, // especially now that we use the small hufont in the menus... +// If color is 0x00 to 0xFF, draw transtable (strength range 0-10). +// Else, use COLORMAP lump (strength range 0-31). +// IF YOU ARE NOT CAREFUL, THIS CAN AND WILL CRASH! +// I have kept the safety checks out of this function; +// the v.fadeScreen Lua interface handles those. // -void V_DrawFadeScreen(void) +void V_DrawFadeScreen(UINT16 color, UINT8 strength) { - const UINT8 *fadetable = (UINT8 *)colormaps + 16*256; - const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; - UINT8 *buf = screens[0]; + if (!strength) + return; + + if (!(color & 0xFF00) && strength == 10) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, color); + return; + } #ifdef HWRENDER if (rendermode != render_soft && rendermode != render_none) { - HWR_FadeScreenMenuBack(0x01010160, 0); // hack, 0 means full height + HWR_FadeScreenMenuBack(color, strength); return; } #endif - // heavily simplified -- we don't need to know x or y - // position when we're doing a full screen fade - for (; buf < deststop; ++buf) - *buf = fadetable[*buf]; + { + const UINT8 *fadetable = ((color & 0xFF00) // Color is not palette index? + ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. + : ((UINT8 *)transtables + ((10-strength)< Date: Mon, 12 Feb 2018 18:23:57 +0000 Subject: [PATCH 032/212] * Move the non-mapping drawFill out of the source code function and into the Lua interface. * Add a drawFill fallback for COLORMAP too. * Correct a few index mishaps. --- src/lua_hudlib.c | 9 ++++++++- src/v_video.c | 10 ++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index c592cc2f1..6991f00e7 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -683,15 +683,22 @@ static int libd_fadeScreen(lua_State *L) { UINT16 color = luaL_checkinteger(L, 1); UINT8 strength = luaL_checkinteger(L, 2); - const UINT8 maxstrength = ((color & 0xFF00) ? 31 : 9); + const UINT8 maxstrength = ((color & 0xFF00) ? 32 : 10); HUDONLY + if (!strength) return 0; if (strength > maxstrength) return luaL_error(L, "%s fade strength %d out of range (0 - %d)", ((color & 0xFF00) ? "COLORMAP" : "TRANSMAP"), strength, maxstrength); + if (strength == maxstrength) // Allow as a shortcut for drawfill... + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color)); + return 0; + } + V_DrawFadeScreen(color, strength); return 0; } diff --git a/src/v_video.c b/src/v_video.c index daf0514d5..47142484d 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1321,7 +1321,7 @@ void V_DrawPatchFill(patch_t *pat) // // Fade all the screen buffer, so that the menu is more readable, // especially now that we use the small hufont in the menus... -// If color is 0x00 to 0xFF, draw transtable (strength range 0-10). +// If color is 0x00 to 0xFF, draw transtable (strength range 0-9). // Else, use COLORMAP lump (strength range 0-31). // IF YOU ARE NOT CAREFUL, THIS CAN AND WILL CRASH! // I have kept the safety checks out of this function; @@ -1332,12 +1332,6 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) if (!strength) return; - if (!(color & 0xFF00) && strength == 10) - { - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, color); - return; - } - #ifdef HWRENDER if (rendermode != render_soft && rendermode != render_none) { @@ -1349,7 +1343,7 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) { const UINT8 *fadetable = ((color & 0xFF00) // Color is not palette index? ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. - : ((UINT8 *)transtables + ((10-strength)< Date: Mon, 12 Feb 2018 21:31:03 +0000 Subject: [PATCH 033/212] Fixed the strengths going in the wrong direction of transparency in GL! --- src/hardware/hw_draw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 0e10c6473..072380e6b 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -509,12 +509,12 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) if (color & 0xFF00) // Do COLORMAP fade. { Surf.FlatColor.rgba = UINT2RGBA(0x01010160); - Surf.FlatColor.s.alpha = 0xFF - (strength*8); + Surf.FlatColor.s.alpha = (strength*8); } else // Do TRANSMAP** fade. { Surf.FlatColor.rgba = pLocalPalette[color].rgba; - Surf.FlatColor.s.alpha = (UINT8)((float)(10-strength)*25.5f); + Surf.FlatColor.s.alpha = (UINT8)(strength*25.5f); } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } From 490f5beb89b90f77a98d49c39de700200859b170 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 13 Feb 2018 17:53:18 +0100 Subject: [PATCH 034/212] Do not prevent all net commands for the current tic from being executed because of an unkown net command ID --- src/d_clisrv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d48f223c7..87b154f8e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -401,8 +401,7 @@ static void ExtraDataTicker(void) DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); } CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); - D_FreeTextcmd(gametic); - return; + break; } } } From bd2334dd93985799cb6f77909f2a145ab1474ab5 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 14 Feb 2018 21:00:55 +0100 Subject: [PATCH 035/212] Fix SV_StopServer not calling D_Clearticcmd correctly --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 87b154f8e..e42bceef9 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3292,7 +3292,7 @@ void SV_StopServer(void) localtextcmd[0] = 0; localtextcmd2[0] = 0; - for (i = 0; i < BACKUPTICS; i++) + for (i = firstticstosend; i < firstticstosend + BACKUPTICS; i++) D_Clearticcmd(i); consoleplayer = 0; From d921f26e54c1f9234a6eca2a31225ffe5372de32 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 17 Feb 2018 00:01:42 -0500 Subject: [PATCH 036/212] Don't init the sound system on dedicated servers --- src/d_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 063d28453..ea24430ec 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1223,7 +1223,13 @@ void D_SRB2Main(void) CONS_Printf("R_Init(): Init SRB2 refresh daemon.\n"); R_Init(); - // setting up sound + // setting up sound + if (dedicated) + { + nosound = true; + nomidimusic = nodigimusic = true; + } + else CONS_Printf("S_Init(): Setting up sound.\n"); if (M_CheckParm("-nosound")) nosound = true; @@ -1239,7 +1245,7 @@ void D_SRB2Main(void) I_StartupSound(); I_InitMusic(); S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); - + CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); From 36d1259cebcfb7f3ecf7be7469724379e87e3d31 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 17 Feb 2018 00:37:17 -0500 Subject: [PATCH 037/212] Removed some redundant checks --- src/sdl/sdl_sound.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 1a2cabd23..6c70c163b 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -1180,12 +1180,6 @@ void I_StartupSound(void) audio.callback = I_UpdateStream; audio.userdata = &localdata; - if (dedicated) - { - nosound = nomidimusic = nodigimusic = true; - return; - } - // Configure sound device CONS_Printf("I_StartupSound:\n"); @@ -1481,9 +1475,6 @@ void I_InitMusic(void) I_AddExitFunc(I_ShutdownGMEMusic); #endif - if ((nomidimusic && nodigimusic) || dedicated) - return; - #ifdef HAVE_MIXER MIX_VERSION(&MIXcompiled) MIXlinked = Mix_Linked_Version(); From 33d5baa2aad5eb6f27f19eb15900c3883c8cc8ba Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 2 Mar 2018 13:32:55 +0000 Subject: [PATCH 038/212] * Add new console text colours - sky, purple, aqua, peridot, azure, brown, rosy, and invert. * Remove redundant check from V_DrawFadeScreen(). * Clean up potential endless sound source in Race HUD. --- src/console.c | 82 +++++++++++++++++++++++++++----------------------- src/console.h | 2 +- src/dehacked.c | 10 +++++- src/st_stuff.c | 2 +- src/v_video.c | 35 ++++++++++++++------- src/v_video.h | 10 +++++- 6 files changed, 88 insertions(+), 53 deletions(-) diff --git a/src/console.c b/src/console.c index a504af06d..842d8766d 100644 --- a/src/console.c +++ b/src/console.c @@ -226,13 +226,9 @@ static void CONS_Bind_f(void) // Font colormap colors // TODO: This could probably be improved somehow... // These colormaps are 99% identical, with just a few changed bytes -UINT8 *yellowmap; -UINT8 *purplemap; -UINT8 *lgreenmap; -UINT8 *bluemap; -UINT8 *graymap; -UINT8 *redmap; -UINT8 *orangemap; +// This could EASILY be handled by modifying a centralised colormap +// for software depending on the prior state - but yknow, OpenGL... +UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap, *skymap, *purplemap, *aquamap, *peridotmap, *azuremap, *brownmap, *rosymap, *invertmap; // Console BG color UINT8 *consolebgmap = NULL; @@ -280,45 +276,55 @@ static void CONS_backcolor_Change(void) static void CON_SetupColormaps(void) { INT32 i; + UINT8 *memorysrc = (UINT8 *)Z_Malloc((256*15), PU_STATIC, NULL); - yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - purplemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - lgreenmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - bluemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - redmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); + magentamap = memorysrc; + yellowmap = (magentamap+256); + lgreenmap = (yellowmap+256); + bluemap = (lgreenmap+256); + redmap = (bluemap+256); + graymap = (redmap+256); + orangemap = (graymap+256); + skymap = (orangemap+256); + purplemap = (skymap+256); + aquamap = (purplemap+256); + peridotmap = (aquamap+256); + azuremap = (peridotmap+256); + brownmap = (azuremap+256); + rosymap = (brownmap+256); + invertmap = (rosymap+256); // setup the other colormaps, for console text // these don't need to be aligned, unless you convert the // V_DrawMappedPatch() into optimised asm. - for (i = 0; i < 256; i++) - { - yellowmap[i] = (UINT8)i; // remap each color to itself... - graymap[i] = (UINT8)i; - purplemap[i] = (UINT8)i; - lgreenmap[i] = (UINT8)i; - bluemap[i] = (UINT8)i; - redmap[i] = (UINT8)i; - orangemap[i] = (UINT8)i; - } + for (i = 0; i < (256*15); i++, ++memorysrc) + *memorysrc = (UINT8)(i & 0xFF); // remap each color to itself... - yellowmap[3] = (UINT8)73; - yellowmap[9] = (UINT8)66; - purplemap[3] = (UINT8)184; - purplemap[9] = (UINT8)186; - lgreenmap[3] = (UINT8)98; - lgreenmap[9] = (UINT8)106; - bluemap[3] = (UINT8)147; - bluemap[9] = (UINT8)158; - graymap[3] = (UINT8)10; - graymap[9] = (UINT8)15; - redmap[3] = (UINT8)210; - redmap[9] = (UINT8)32; - orangemap[3] = (UINT8)52; - orangemap[9] = (UINT8)57; +#define colset(map, a, b, c) \ + map[1] = (UINT8)a;\ + map[3] = (UINT8)b;\ + map[9] = (UINT8)c + + colset(magentamap, 177, 178, 184); + colset(yellowmap, 82, 73, 66); + colset(lgreenmap, 97, 98, 106); + colset(bluemap, 146, 147, 155); + colset(redmap, 210, 32, 39); + colset(graymap, 8, 10, 15); + colset(orangemap, 51, 52, 57); + colset(skymap, 129, 130, 133); + colset(purplemap, 160, 161, 163); + colset(aquamap, 120, 121, 123); + colset(peridotmap, 88, 188, 190); + colset(azuremap, 144, 145, 170); + colset(brownmap, 219, 221, 224); + colset(rosymap, 200, 201, 203); + colset(invertmap, 27, 26, 22); + invertmap[26] = (UINT8)3; + +#undef colset // Init back colormap CON_SetupBackColormap(); diff --git a/src/console.h b/src/console.h index 1e510e89a..970f841d0 100644 --- a/src/console.h +++ b/src/console.h @@ -34,7 +34,7 @@ extern UINT32 con_scalefactor; // console text scale factor extern consvar_t cons_backcolor; -extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap; +extern UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap, *skymap, *purplemap, *aquamap, *peridotmap, *azuremap, *brownmap, *rosymap, *invertmap; // Console bg color (auto updated to match) extern UINT8 *consolebgmap; diff --git a/src/dehacked.c b/src/dehacked.c index bd4530e00..7202ba31b 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7311,13 +7311,21 @@ struct { {"V_6WIDTHSPACE",V_6WIDTHSPACE}, {"V_OLDSPACING",V_OLDSPACING}, {"V_MONOSPACE",V_MONOSPACE}, - {"V_PURPLEMAP",V_PURPLEMAP}, + {"V_MAGENTAMAP",V_MAGENTAMAP}, {"V_YELLOWMAP",V_YELLOWMAP}, {"V_GREENMAP",V_GREENMAP}, {"V_BLUEMAP",V_BLUEMAP}, {"V_REDMAP",V_REDMAP}, {"V_GRAYMAP",V_GRAYMAP}, {"V_ORANGEMAP",V_ORANGEMAP}, + {"V_SKYMAP",V_SKYMAP}, + {"V_PURPLEMAP",V_PURPLEMAP}, + {"V_AQUAMAP",V_AQUAMAP}, + {"V_PERIDOTMAP",V_PERIDOTMAP}, + {"V_AZUREMAP",V_AZUREMAP}, + {"V_BROWNMAP",V_BROWNMAP}, + {"V_ROSYMAP",V_ROSYMAP}, + {"V_INVERTMAP",V_INVERTMAP}, {"V_TRANSLUCENT",V_TRANSLUCENT}, {"V_10TRANS",V_10TRANS}, {"V_20TRANS",V_20TRANS}, diff --git a/src/st_stuff.c b/src/st_stuff.c index 1426ae405..6d6c2d017 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1684,7 +1684,7 @@ static inline void ST_drawRaceHUD(void) if (bounce < 3) { height -= (2 - bounce); - if (!bounce) + if (!(P_AutoPause() || paused) && !bounce) S_StartSound(0, ((racenum == racego) ? sfx_s3kad : sfx_s3ka7)); } V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(racenum->width))/2), (INT32)(SCZ(height)), V_NOSCALESTART|V_PERPLAYER, racenum); diff --git a/src/v_video.c b/src/v_video.c index 47142484d..d23e5f4f5 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1329,9 +1329,6 @@ void V_DrawPatchFill(patch_t *pat) // void V_DrawFadeScreen(UINT16 color, UINT8 strength) { - if (!strength) - return; - #ifdef HWRENDER if (rendermode != render_soft && rendermode != render_none) { @@ -1395,20 +1392,36 @@ static const UINT8 *V_GetStringColormap(INT32 colorflags) { switch ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT) { - case 1: // 0x81, purple - return purplemap; - case 2: // 0x82, yellow + case 1: // 0x81, magenta + return magentamap; + case 2: // 0x82, yellow return yellowmap; - case 3: // 0x83, lgreen + case 3: // 0x83, lgreen return lgreenmap; - case 4: // 0x84, blue + case 4: // 0x84, blue return bluemap; - case 5: // 0x85, red + case 5: // 0x85, red return redmap; - case 6: // 0x86, gray + case 6: // 0x86, gray return graymap; - case 7: // 0x87, orange + case 7: // 0x87, orange return orangemap; + case 8: // 0x88, sky + return skymap; + case 9: // 0x89, purple + return purplemap; + case 10: // 0x8A, aqua + return aquamap; + case 11: // 0x8B, peridot + return peridotmap; + case 12: // 0x8C, azure + return azuremap; + case 13: // 0x8D, brown + return brownmap; + case 14: // 0x8E, rosy + return rosymap; + case 15: // 0x8F, invert + return invertmap; default: // reset return NULL; } diff --git a/src/v_video.h b/src/v_video.h index ee244c671..5645ed2ce 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -73,13 +73,21 @@ extern RGBA_t *pMasterPalette; #define V_CHARCOLORSHIFT 12 #define V_CHARCOLORMASK 0x0000F000 // for simplicity's sake, shortcuts to specific colors -#define V_PURPLEMAP 0x00001000 +#define V_MAGENTAMAP 0x00001000 #define V_YELLOWMAP 0x00002000 #define V_GREENMAP 0x00003000 #define V_BLUEMAP 0x00004000 #define V_REDMAP 0x00005000 #define V_GRAYMAP 0x00006000 #define V_ORANGEMAP 0x00007000 +#define V_SKYMAP 0x00008000 +#define V_PURPLEMAP 0x00009000 +#define V_AQUAMAP 0x0000A000 +#define V_PERIDOTMAP 0x0000B000 +#define V_AZUREMAP 0x0000C000 +#define V_BROWNMAP 0x0000D000 +#define V_ROSYMAP 0x0000E000 +#define V_INVERTMAP 0x0000F000 // use bits 17-20 for alpha transparency #define V_ALPHASHIFT 16 From 1fe79a0d718bece374aa17b32c55c9a842137f6a Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 5 Mar 2018 19:08:53 +0000 Subject: [PATCH 039/212] Fix movies not recording the "extension" to special stage intro fades --- src/p_setup.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 8e746457b..52cd6ddbb 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2565,6 +2565,7 @@ boolean P_SetupLevel(boolean skipprecip) { tic_t starttime = I_GetTime(); tic_t endtime = starttime + (3*TICRATE)/2; + tic_t nowtime; S_StartSound(NULL, sfx_s3kaf); @@ -2574,9 +2575,17 @@ boolean P_SetupLevel(boolean skipprecip) F_WipeEndScreen(); F_RunWipe(wipedefs[wipe_speclevel_towhite], false); + nowtime = lastwipetic; // Hold on white for extra effect. - while (I_GetTime() < endtime) - I_Sleep(); + while (nowtime < endtime) + { + // wait loop + while (!((nowtime = I_GetTime()) - lastwipetic)) + I_Sleep(); + lastwipetic = nowtime; + if (moviemode) // make sure we save frames for the white hold too + M_SaveFrame(); + } ranspecialwipe = 1; } From e3151f26dc901fb9762ba28a5558b0704e6113a9 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 5 Mar 2018 22:24:03 +0000 Subject: [PATCH 040/212] rewrite download file screen code: * fix screen to properly truncate the filename to just the real name only * if the real name itself is too long, use ellipsis and paste in parts of the start and end of the actual name note: I haven't actually tested if this works or compiles yet, I haven't the time right now --- src/d_clisrv.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 004eed86f..8783fb365 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1158,21 +1158,38 @@ static inline void CL_DrawConnectionStatus(void) { INT32 dldlength; static char tempname[32]; + fileneeded_t *file = &fileneeded[lastfilenum]; + char *filename = file->filename; Net_GetNetStat(); - dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256); + dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); if (dldlength > 256) dldlength = 256; V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175); V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160); memset(tempname, 0, sizeof(tempname)); - nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31)); + // offset filename to just the name only part + filename += strlen(filename) - nameonlylength(filename); + + if (strlen(filename) > 31) // too long to display fully + { + size_t endhalfpos = strlen(filename)-12; + // display as first 16 chars + ... + last 12 chars + // which should add up to 31 if our math(s) is correct + strncpy(tempname, filename, 16); + strncpy(tempname+16, "...", 3); + strncpy(tempname+16+3, filename+endhalfpos, 12); + } + else // we can copy the whole thing in safely + { + strncpy(tempname, filename, 31); + } V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, va(M_GetText("Downloading \"%s\""), tempname)); V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, - va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10)); + va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, va("%3.1fK/s ", ((double)getbps)/1024)); } From a66824d63f5ed6eaeaca8afc518d5579247f0abb Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Tue, 6 Mar 2018 20:20:27 +0000 Subject: [PATCH 041/212] replace the 3 strncpys with a snprintf --- src/d_clisrv.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8783fb365..46f8a9a10 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1177,9 +1177,7 @@ static inline void CL_DrawConnectionStatus(void) size_t endhalfpos = strlen(filename)-12; // display as first 16 chars + ... + last 12 chars // which should add up to 31 if our math(s) is correct - strncpy(tempname, filename, 16); - strncpy(tempname+16, "...", 3); - strncpy(tempname+16+3, filename+endhalfpos, 12); + snprintf(tempname, 31, "%.16s...%.12s", filename, filename+endhalfpos); } else // we can copy the whole thing in safely { From aba4adfabca9adb9c3aa85b680c78bc685cea02b Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Tue, 6 Mar 2018 20:52:55 +0000 Subject: [PATCH 042/212] shrunk buffer from 32 to 28 so that all of "Downloading "extremely...longname.wad"" can fit on screen at once. --- src/d_clisrv.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 46f8a9a10..7d0e44b45 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1157,7 +1157,7 @@ static inline void CL_DrawConnectionStatus(void) if (lastfilenum != -1) { INT32 dldlength; - static char tempname[32]; + static char tempname[28]; fileneeded_t *file = &fileneeded[lastfilenum]; char *filename = file->filename; @@ -1172,16 +1172,16 @@ static inline void CL_DrawConnectionStatus(void) // offset filename to just the name only part filename += strlen(filename) - nameonlylength(filename); - if (strlen(filename) > 31) // too long to display fully + if (strlen(filename) > sizeof(tempname)-1) // too long to display fully { - size_t endhalfpos = strlen(filename)-12; - // display as first 16 chars + ... + last 12 chars - // which should add up to 31 if our math(s) is correct - snprintf(tempname, 31, "%.16s...%.12s", filename, filename+endhalfpos); + size_t endhalfpos = strlen(filename)-10; + // display as first 14 chars + ... + last 10 chars + // which should add up to 27 if our math(s) is correct + snprintf(tempname, sizeof(tempname), "%.14s...%.10s", filename, filename+endhalfpos); } else // we can copy the whole thing in safely { - strncpy(tempname, filename, 31); + strncpy(tempname, filename, sizeof(tempname)-1); } V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, From 67ee1637c98688f5d9cae6ad781373b27e372c48 Mon Sep 17 00:00:00 2001 From: Sryder Date: Tue, 6 Mar 2018 03:48:15 +0000 Subject: [PATCH 043/212] Decrease far clipping plane The Far clipping plane did not need to be nearly as high as it was, the new value is 32768, which I suspect is about how far software can render before it completely falls apart. It is desirable to increase the near clipping plane to between 6-10, but it can introduce more issues with close geometry not being drawn when the player or camera is scaled or viewheight is set to MIN in first person view. It would also stop sprites from being drawn ever so slightly too early, but this isn't too much of an issue and isn't too noticeable with those values. Might look into scaling near clipping plane in accordance to camera scale in the future. The reason for wanting to increase the near clipping plane is because the small value can cause very noticeable Z-fighting where there shouldn't be on older GPU's, usually Intel ones, that don't support 24-bits for the depth buffer. --- src/hardware/hw_defs.h | 4 ++-- src/hardware/hw_main.c | 13 +++++++------ src/hardware/r_opengl/r_opengl.c | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 70d776d9e..04802122e 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -20,8 +20,8 @@ #define _HWR_DEFS_ #include "../doomtype.h" -#define ZCLIP_PLANE 4.0f -#define NZCLIP_PLANE 0.9f +#define ZCLIP_PLANE 4.0f // Used for the actual game drawing +#define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures // ========================================================================== // SIMPLE TYPES diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3a2b0f0ed..3a1cf3d9b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5330,12 +5330,13 @@ static void HWR_DrawSkyBackground(player_t *player) //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 // because it's called just after clearing the screen // and thus, the near clipping plane is set to 3.99 - v[0].x = v[3].x = -4.0f; - v[1].x = v[2].x = 4.0f; - v[0].y = v[1].y = -4.0f; - v[2].y = v[3].y = 4.0f; + // Sryder: Just use the near clipping plane value then + v[0].x = v[3].x = -ZCLIP_PLANE-1; + v[1].x = v[2].x = ZCLIP_PLANE+1; + v[0].y = v[1].y = -ZCLIP_PLANE-1; + v[2].y = v[3].y = ZCLIP_PLANE+1; - v[0].z = v[1].z = v[2].z = v[3].z = 4.0f; + v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1; // X @@ -5403,7 +5404,7 @@ static inline void HWR_ClearView(void) (INT32)gr_viewwindowy, (INT32)(gr_viewwindowx + gr_viewwidth), (INT32)(gr_viewwindowy + gr_viewheight), - 3.99f); + ZCLIP_PLANE); HWD.pfnClearBuffer(false, true, 0); //disable clip window - set to full size diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 2ee5c8a80..0ab2bdae8 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -59,7 +59,7 @@ typedef struct GLRGBAFloat GLRGBAFloat; #define N_PI_DEMI (M_PIl/2.0f) //(1.5707963268f) #define ASPECT_RATIO (1.0f) //(320.0f/200.0f) -#define FAR_CLIPPING_PLANE 150000.0f // Draw further! Tails 01-21-2001 +#define FAR_CLIPPING_PLANE 32768.0f // Draw further! Tails 01-21-2001 static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE; // ************************************************************************** From 77af3a8f95c453cfd013cf37c97cfe03f5554e7f Mon Sep 17 00:00:00 2001 From: Sryder Date: Wed, 7 Mar 2018 05:19:06 +0000 Subject: [PATCH 044/212] Optimise the screen texture setup for SDL2, Post-processor, and wipes. Only use glCopyTexImage2D when first creating the screen texture, use glCopyTexSubImage2D anytime after that as it does not define a new texture each time. Flushing of the screen textures has been implemented for when the screen size changes (so that the screen textures don't stay at a wrong size) and the game is closed, I believe they would leave a memory leak before. --- src/hardware/hw_drv.h | 2 + src/hardware/hw_main.c | 3 + src/hardware/r_opengl/r_opengl.c | 145 +++++++++++++++++++++++-------- src/sdl/hwsym_sdl.c | 1 + src/sdl/i_video.c | 1 + src/sdl12/hwsym_sdl.c | 1 + src/sdl12/i_video.c | 1 + src/win32/win_dll.c | 2 + 8 files changed, 122 insertions(+), 34 deletions(-) diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 7672f47c2..a5ac82001 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -79,6 +79,7 @@ EXPORT char *HWRAPI(GetRenderer) (void); #define SCREENVERTS 10 EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); #endif +EXPORT void HWRAPI(FlushScreenTextures) (void); EXPORT void HWRAPI(StartScreenWipe) (void); EXPORT void HWRAPI(EndScreenWipe) (void); EXPORT void HWRAPI(DoScreenWipe) (float alpha); @@ -124,6 +125,7 @@ struct hwdriver_s #ifdef SHUFFLE PostImgRedraw pfnPostImgRedraw; #endif + FlushScreenTextures pfnFlushScreenTextures; StartScreenWipe pfnStartScreenWipe; EndScreenWipe pfnEndScreenWipe; DoScreenWipe pfnDoScreenWipe; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3a1cf3d9b..d401bc374 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5443,6 +5443,8 @@ void HWR_SetViewSize(void) gr_pspritexscale = gr_viewwidth / BASEVIDWIDTH; gr_pspriteyscale = ((vid.height*gr_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width; + + HWD.pfnFlushScreenTextures(); } // ========================================================================== @@ -6036,6 +6038,7 @@ void HWR_Shutdown(void) HWR_FreeExtraSubsectors(); HWR_FreePolyPool(); HWR_FreeTextureCache(); + HWD.pfnFlushScreenTextures(); } void transform(float *cx, float *cy, float *cz) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 0ab2bdae8..9eb013a13 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -107,10 +107,19 @@ static GLint viewport[4]; #endif // Yay for arbitrary numbers! NextTexAvail is buggy for some reason. -static GLuint screentexture = 60000; -static GLuint startScreenWipe = 60001; -static GLuint endScreenWipe = 60002; -static GLuint finalScreenTexture = 60003; +// Sryder: NextTexAvail is broken for these because palette changes or changes to the texture filter or antialiasing +// flush all of the stored textures, leaving them unavailable at times such as between levels +// These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs +// can know when the textures aren't there, as textures are always considered resident in their virtual memory +// TODO: Store them in a more normal way +#define SCRTEX_SCREENTEXTURE 65535 +#define SCRTEX_STARTSCREENWIPE 65534 +#define SCRTEX_ENDSCREENWIPE 65533 +#define SCRTEX_FINALSCREENTEXTURE 65532 +static GLuint screentexture = 0; +static GLuint startScreenWipe = 0; +static GLuint endScreenWipe = 0; +static GLuint finalScreenTexture = 0; #if 0 GLuint screentexture = FIRST_TEX_AVAIL; #endif @@ -263,6 +272,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) /* texture mapping */ //GL_EXT_copy_texture #ifndef KOS_GL_COMPATIBILITY #define pglCopyTexImage2D glCopyTexImage2D +#define pglCopyTexSubImage2D glCopyTexSubImage2D #endif #else //!STATIC_OPENGL @@ -387,6 +397,8 @@ static PFNglBindTexture pglBindTexture; /* texture mapping */ //GL_EXT_copy_texture typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); static PFNglCopyTexImage2D pglCopyTexImage2D; +typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +static PFNglCopyTexSubImage2D pglCopyTexSubImage2D; #endif /* GLU functions */ typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data); @@ -503,6 +515,7 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglBindTexture , glBindTexture) GETOPENGLFUNC(pglCopyTexImage2D , glCopyTexImage2D) + GETOPENGLFUNC(pglCopyTexSubImage2D , glCopyTexSubImage2D) #undef GETOPENGLFUNC @@ -654,6 +667,10 @@ void SetModelView(GLint w, GLint h) { // DBG_Printf("SetModelView(): %dx%d\n", (int)w, (int)h); + // The screen textures need to be flushed if the width or height change so that they be remade for the correct size + if (screen_width != w || screen_height != h) + FlushScreenTextures(); + screen_width = w; screen_height = h; @@ -801,6 +818,7 @@ void Flush(void) screentexture = FIRST_TEX_AVAIL; } #endif + tex_downloaded = 0; } @@ -2156,10 +2174,25 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) } #endif //SHUFFLE +// Sryder: This needs to be called whenever the screen changes resolution in order to reset the screen textures to use +// a new size +EXPORT void HWRAPI(FlushScreenTextures) (void) +{ + pglDeleteTextures(1, &screentexture); + pglDeleteTextures(1, &startScreenWipe); + pglDeleteTextures(1, &endScreenWipe); + pglDeleteTextures(1, &finalScreenTexture); + screentexture = 0; + startScreenWipe = 0; + endScreenWipe = 0; + finalScreenTexture = 0; +} + // Create Screen to fade from EXPORT void HWRAPI(StartScreenWipe) (void) { INT32 texsize = 2048; + boolean firstTime = (startScreenWipe == 0); // Use a power of two texture, dammit if(screen_width <= 512) @@ -2168,27 +2201,38 @@ EXPORT void HWRAPI(StartScreenWipe) (void) texsize = 1024; // Create screen texture + if (firstTime) + startScreenWipe = SCRTEX_STARTSCREENWIPE; pglBindTexture(GL_TEXTURE_2D, startScreenWipe); + + if (firstTime) + { #ifdef KOS_GL_COMPATIBILITY - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); #else - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #endif - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); + Clamp2D(GL_TEXTURE_WRAP_S); + Clamp2D(GL_TEXTURE_WRAP_T); #ifndef KOS_GL_COMPATIBILITY - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); +#endif + } + else +#ifndef KOS_GL_COMPATIBILITY + pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); #endif - tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now + tex_downloaded = startScreenWipe; } // Create Screen to fade to EXPORT void HWRAPI(EndScreenWipe)(void) { INT32 texsize = 2048; + boolean firstTime = (endScreenWipe == 0); // Use a power of two texture, dammit if(screen_width <= 512) @@ -2197,21 +2241,32 @@ EXPORT void HWRAPI(EndScreenWipe)(void) texsize = 1024; // Create screen texture + if (firstTime) + endScreenWipe = SCRTEX_ENDSCREENWIPE; pglBindTexture(GL_TEXTURE_2D, endScreenWipe); + + if (firstTime) + { #ifdef KOS_GL_COMPATIBILITY - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); #else - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #endif - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); + Clamp2D(GL_TEXTURE_WRAP_S); + Clamp2D(GL_TEXTURE_WRAP_T); #ifndef KOS_GL_COMPATIBILITY - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); +#endif + } + else +#ifndef KOS_GL_COMPATIBILITY + pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); #endif - tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now + + tex_downloaded = endScreenWipe; } @@ -2253,7 +2308,7 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) pglEnd(); - tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now + tex_downloaded = screentexture; } // Do screen fades! @@ -2344,6 +2399,7 @@ EXPORT void HWRAPI(DoScreenWipe)(float alpha) pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit pglActiveTexture(GL_TEXTURE0); + tex_downloaded = endScreenWipe; } else { @@ -2369,11 +2425,10 @@ EXPORT void HWRAPI(DoScreenWipe)(float alpha) pglTexCoord2f(xfix, 0.0f); pglVertex3f(1.0f, -1.0f, 1.0f); pglEnd(); + tex_downloaded = endScreenWipe; #ifndef MINI_GL_COMPATIBILITY } #endif - - tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now } @@ -2381,6 +2436,7 @@ EXPORT void HWRAPI(DoScreenWipe)(float alpha) EXPORT void HWRAPI(MakeScreenTexture) (void) { INT32 texsize = 2048; + boolean firstTime = (screentexture == 0); // Use a power of two texture, dammit if(screen_width <= 512) @@ -2389,7 +2445,12 @@ EXPORT void HWRAPI(MakeScreenTexture) (void) texsize = 1024; // Create screen texture + if (firstTime) + screentexture = SCRTEX_SCREENTEXTURE; pglBindTexture(GL_TEXTURE_2D, screentexture); + + if (firstTime) + { #ifdef KOS_GL_COMPATIBILITY pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); @@ -2400,15 +2461,21 @@ EXPORT void HWRAPI(MakeScreenTexture) (void) Clamp2D(GL_TEXTURE_WRAP_S); Clamp2D(GL_TEXTURE_WRAP_T); #ifndef KOS_GL_COMPATIBILITY - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); +#endif + } + else +#ifndef KOS_GL_COMPATIBILITY + pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); #endif - tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now + tex_downloaded = screentexture; } EXPORT void HWRAPI(MakeScreenFinalTexture) (void) { INT32 texsize = 2048; + boolean firstTime = (finalScreenTexture == 0); // Use a power of two texture, dammit if(screen_width <= 512) @@ -2417,21 +2484,31 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void) texsize = 1024; // Create screen texture + if (firstTime) + finalScreenTexture = SCRTEX_FINALSCREENTEXTURE; pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + + if (firstTime) + { #ifdef KOS_GL_COMPATIBILITY - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); #else - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #endif - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); + Clamp2D(GL_TEXTURE_WRAP_S); + Clamp2D(GL_TEXTURE_WRAP_T); #ifndef KOS_GL_COMPATIBILITY - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); +#endif + } + else +#ifndef KOS_GL_COMPATIBILITY + pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); #endif - tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now + tex_downloaded = finalScreenTexture; } @@ -2476,7 +2553,7 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) SetModelView(screen_width, screen_height); SetStates(); - tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now + tex_downloaded = finalScreenTexture; } #endif //HWRENDER diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index f4686d2bf..05ac6450e 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -94,6 +94,7 @@ void *hwSym(const char *funcName,void *handle) #ifdef SHUFFLE GETFUNC(PostImgRedraw); #endif //SHUFFLE + GETFUNC(FlushScreenTextures); GETFUNC(StartScreenWipe); GETFUNC(EndScreenWipe); GETFUNC(DoScreenWipe); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 1bda0e180..87ce84158 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1442,6 +1442,7 @@ void I_StartupGraphics(void) #ifdef SHUFFLE HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); #endif + HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); diff --git a/src/sdl12/hwsym_sdl.c b/src/sdl12/hwsym_sdl.c index 54f5da3a0..49340138f 100644 --- a/src/sdl12/hwsym_sdl.c +++ b/src/sdl12/hwsym_sdl.c @@ -100,6 +100,7 @@ void *hwSym(const char *funcName,void *handle) #ifdef SHUFFLE GETFUNC(PostImgRedraw); #endif //SHUFFLE + GETFUNC(FlushScreenTextures); GETFUNC(StartScreenWipe); GETFUNC(EndScreenWipe); GETFUNC(DoScreenWipe); diff --git a/src/sdl12/i_video.c b/src/sdl12/i_video.c index 197924eda..349e06cba 100644 --- a/src/sdl12/i_video.c +++ b/src/sdl12/i_video.c @@ -1972,6 +1972,7 @@ void I_StartupGraphics(void) #ifdef SHUFFLE HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); #endif + HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c index 8fa4d17f7..c9b3fba4e 100644 --- a/src/win32/win_dll.c +++ b/src/win32/win_dll.c @@ -117,6 +117,7 @@ static loadfunc_t hwdFuncTable[] = { #ifdef SHUFFLE {"PostImgRedraw@4", &hwdriver.pfnPostImgRedraw}, #endif + {"FlushScreenTextures@0",&hwdriver.pfnFlushScreenTextures}, {"StartScreenWipe@0", &hwdriver.pfnStartScreenWipe}, {"EndScreenWipe@0", &hwdriver.pfnEndScreenWipe}, {"DoScreenWipe@4", &hwdriver.pfnDoScreenWipe}, @@ -147,6 +148,7 @@ static loadfunc_t hwdFuncTable[] = { #ifdef SHUFFLE {"PostImgRedraw", &hwdriver.pfnPostImgRedraw}, #endif + {"FlushScreenTextures"},&hwdriver.pfnFlushScreenTextures}, {"StartScreenWipe", &hwdriver.pfnStartScreenWipe}, {"EndScreenWipe", &hwdriver.pfnEndScreenWipe}, {"DoScreenWipe", &hwdriver.pfnDoScreenWipe}, From 121fcd83692d2e3946678bc270a80fe679247110 Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 8 Mar 2018 22:28:38 +0000 Subject: [PATCH 045/212] Fix screenshot functionality in fullscreen in SDL2 --- src/hardware/hw_draw.c | 14 ++++++ src/hardware/hw_drv.h | 6 +++ src/hardware/r_opengl/r_opengl.c | 79 ++++++++++++++++++++++++++++++++ src/sdl/hwsym_sdl.c | 1 + src/sdl/i_video.c | 1 + src/sdl12/hwsym_sdl.c | 1 + src/sdl12/i_video.c | 1 + 7 files changed, 103 insertions(+) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index f23753ee5..867a86a15 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -769,6 +769,9 @@ UINT8 *HWR_GetScreenshot(void) if (!buf) return NULL; // returns 24bit 888 RGB +#ifdef HAVE_SDL + if (!HWD.pfnReadScreenTexture(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf)) +#endif HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); return buf; } @@ -782,8 +785,19 @@ boolean HWR_Screenshot(const char *lbmname) return false; // returns 24bit 888 RGB +#ifdef HAVE_SDL + // Sryder: SDL2 uses borderless fullscreen mode, and creates a screen texture to upscale to the screen size. + // This breaks screenshots because the code here takes a screenshot of just the resolution from the bottom + // left corner, while the "true" resolution is the monitor resolution. We can either take a screenshot of + // the true resolution or just use the already made screen texture + // NOTE: The SDL1.2 version should get a return of false from ReadScreenTexture as no screen texture will have + // been made, this will also mean that if the screen texture doesn't exist for some reason it will fall + // back to the old version + if (!HWD.pfnReadScreenTexture(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf)) +#endif HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); + #ifdef USE_PNG ret = M_SavePNG(lbmname, buf, vid.width, vid.height, NULL); #else diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index a5ac82001..ab4025697 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -58,6 +58,9 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); +#ifdef HAVE_SDL +EXPORT boolean HWRAPI(ReadScreenTexture) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 * dst_data); +#endif EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -104,6 +107,9 @@ struct hwdriver_s ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; ReadRect pfnReadRect; +#ifdef HAVE_SDL + ReadScreenTexture pfnReadScreenTexture; +#endif GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 9eb013a13..fb8555aa9 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -260,6 +260,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) #define pglTexEnvi glTexEnvi #define pglTexParameteri glTexParameteri #define pglTexImage2D glTexImage2D +#define pglGetTexImage glGetTexImage /* Fog */ #define pglFogf glFogf @@ -381,6 +382,8 @@ typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint static PFNglTexParameteri pglTexParameteri; typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); static PFNglTexImage2D pglTexImage2D; +typedef void (APIENTRY * PFNglGetTexImage) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +static PFNglGetTexImage pglGetTexImage; /* Fog */ typedef void (APIENTRY * PFNglFogf) (GLenum pname, GLfloat param); @@ -507,6 +510,7 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglTexEnvi , glTexEnvi) GETOPENGLFUNC(pglTexParameteri , glTexParameteri) GETOPENGLFUNC(pglTexImage2D , glTexImage2D) + GETOPENGLFUNC(pglGetTexImage , glGetTexImage) GETOPENGLFUNC(pglFogf , glFogf) GETOPENGLFUNC(pglFogfv , glFogfv) @@ -933,6 +937,81 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, #endif } +#ifdef HAVE_SDL +EXPORT boolean HWRAPI(ReadScreenTexture) (INT32 x, INT32 y, INT32 width, + INT32 height, INT32 dst_stride, + UINT16 * dst_data) +{ +#ifdef KOS_GL_COMPATIBILITY + (void)x; + (void)y; + (void)width; + (void)height; + (void)dst_stride; + (void)dst_data; +#else + INT32 i, j; + INT32 texsize = 2048; + GLubyte *image; + // DBG_Printf ("ReadScreenTexture()\n"); + if (screentexture == 0) + return false; // No screen texture + + if(screen_width <= 1024) + texsize = 1024; + if(screen_width <= 512) + texsize = 512; + + if (x < 0) + x = 0; + if (x + width > screen_width) + width = screen_width - x; + if (y < 0) + y = 0; + if (y + height > screen_height) + height = screen_height - y; + + image = malloc(texsize*texsize*3*sizeof (*image)); + if (!image) + return false; + pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + tex_downloaded = finalScreenTexture; + pglGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, image); + + if (dst_stride == width*3) + { + UINT8 *dest = (void *)dst_data; + for (i = y + height-1; i >= y; i--) + { + for (j = x; j < width + x; j++) + { + dest[((height-1-i-y)*width+j-x)*3] = image[(i*texsize+j)*3]; + dest[((height-1-i-y)*width+j-x)*3+1] = image[(i*texsize+j)*3+1]; + dest[((height-1-i-y)*width+j-x)*3+2] = image[(i*texsize+j)*3+2]; + } + } + } + else + { + // Sryder: NOTE: I'm not entirely sure this works, as far as I know nothing in the game uses it. + for (i = y + height-1; i >= y; i--) + { + for (j = x; j < width + x; j++) + { + dst_data[(height-1-i-y)*width+j-x] = + (UINT16)( + ((image[(i*texsize+j)*3]>>3)<<11) | + ((image[(i*texsize+j)*3+1]>>2)<<5) | + ((image[(i*texsize+j)*3+2]>>3))); + } + } + } + free(image); + return true; +#endif +} +#endif + // -----------------+ // GClipRect : Defines the 2D hardware clipping window diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 05ac6450e..33bcfd6f3 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -83,6 +83,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ClearBuffer); GETFUNC(SetTexture); GETFUNC(ReadRect); + GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 87ce84158..2df8a6ff5 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1430,6 +1430,7 @@ void I_StartupGraphics(void) HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL); + HWD.pfnReadScreenTexture= hwSym("ReadScreenTexture",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); diff --git a/src/sdl12/hwsym_sdl.c b/src/sdl12/hwsym_sdl.c index 49340138f..3a10d8253 100644 --- a/src/sdl12/hwsym_sdl.c +++ b/src/sdl12/hwsym_sdl.c @@ -89,6 +89,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ClearBuffer); GETFUNC(SetTexture); GETFUNC(ReadRect); + GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); diff --git a/src/sdl12/i_video.c b/src/sdl12/i_video.c index 349e06cba..076ce4fd2 100644 --- a/src/sdl12/i_video.c +++ b/src/sdl12/i_video.c @@ -1960,6 +1960,7 @@ void I_StartupGraphics(void) HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL); + HWD.pfnReadScreenTexture= hwSym("ReadScreenTexture",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); From e4ed3a793b7ad37db1ecb8cc600f300af6b20c91 Mon Sep 17 00:00:00 2001 From: Sryder Date: Fri, 9 Mar 2018 09:58:10 +0000 Subject: [PATCH 046/212] Small hacky fix for MD2s and sprites until sorting for walls, floors, and sprites is done Sorts all translucent sprites and MD2s so they're drawn after all the opaque ones. Fixes most of the observable issues between translucent MD2s and opaque sprites/MD2s. --- src/hardware/hw_main.c | 30 ++++++++++++++++++++++++++++++ src/hardware/r_opengl/r_opengl.c | 1 - 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d401bc374..33cf54a38 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4565,6 +4565,33 @@ static void HWR_SortVisSprites(void) gr_vsprsortedhead.prev->next = best; gr_vsprsortedhead.prev = best; } + + // Sryder: Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the + // mix and they want to be translucent. So let's place all the translucent sprites and MD2's AFTER + // everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine. + // We just need to move all translucent ones to the end in order + // TODO: Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that + best = gr_vsprsortedhead.next; + for (i = 0; i < gr_visspritecount; i++) + { + if ((best->mobj->flags2 & MF2_SHADOW) || (best->mobj->frame & FF_TRANSMASK)) + { + if (best == gr_vsprsortedhead.next) + { + gr_vsprsortedhead.next = best->next; + } + best->prev->next = best->next; + best->next->prev = best->prev; + best->prev = gr_vsprsortedhead.prev; + gr_vsprsortedhead.prev->next = best; + gr_vsprsortedhead.prev = best; + ds = best; + best = best->next; + ds->next = &gr_vsprsortedhead; + } + else + best = best->next; + } } // A drawnode is something that points to a 3D floor, 3D side, or masked @@ -4912,7 +4939,10 @@ static void HWR_DrawSprites(FTransform *stransform) { #ifdef HWPRECIP if (spr->precip) + { + HWD.pfnSetTransform(stransform); HWR_DrawPrecipitationSprite(spr); + } else #endif if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index fb8555aa9..14cff5995 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2100,7 +2100,6 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, if (color) pglDisable(GL_LIGHTING); pglShadeModel(GL_FLAT); - pglDepthMask(GL_TRUE); pglDisable(GL_CULL_FACE); } From aefe06e2ef61681a5c34b803e6cce739c12c7c52 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 9 Mar 2018 16:34:09 +0100 Subject: [PATCH 047/212] Fix Lua panic when archiving a table element with an userdata key --- src/lua_script.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lua_script.c b/src/lua_script.c index 167e4a0b4..ce96878bf 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -478,10 +478,10 @@ static const struct { {NULL, ARCH_NULL} }; -static UINT8 GetUserdataArchType(void) +static UINT8 GetUserdataArchType(int index) { UINT8 i; - lua_getmetatable(gL, -1); + lua_getmetatable(gL, index); for (i = 0; meta2arch[i].meta; i++) { @@ -560,7 +560,7 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) break; } case LUA_TUSERDATA: - switch (GetUserdataArchType()) + switch (GetUserdataArchType(myindex)) { case ARCH_MOBJINFO: { @@ -777,6 +777,7 @@ static void ArchiveTables(void) CONS_Alert(CONS_ERROR, "Type of value for table %d entry '%s' (%s) could not be archived!\n", i, lua_tostring(gL, -1), luaL_typename(gL, -1)); lua_pop(gL, 1); } + lua_pop(gL, 1); } lua_pop(gL, 1); From 68cb91920508ada5962640a46afe041873933e31 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 14 Mar 2018 16:47:19 +0000 Subject: [PATCH 048/212] down with cis --- src/f_finale.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 692abb35f..17110df4f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -969,7 +969,7 @@ static const char *credits[] = { "\1Programming", "Alam \"GBC\" Arias", "Logan \"GBA\" Arias", - "Tim \"RedEnchilada\" Bordelon", + "Colette \"fickle\" Bordelon", "Callum Dickinson", "Scott \"Graue\" Feeney", "Nathan \"Jazz\" Giroux", @@ -979,11 +979,11 @@ static const char *credits[] = { "John \"JTE\" Muniz", "Ehab \"Wolfy\" Saeed", "\"SSNTails\"", - "Matthew \"Inuyasha\" Walsh", + "\"Kaito Sinclaire\"", "", "\1Programming", "\1Assistance", - "\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom) + "\"chi.miru\"", // helped port slope drawing code from ZDoom "Andrew \"orospakr\" Clunis", "Gregor \"Oogaland\" Dick", "Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol) @@ -1047,7 +1047,7 @@ static const char *credits[] = { "Rob Tisdell", "Jarrett \"JEV3\" Voight", "Johnny \"Sonikku\" Wallbank", - "Matthew \"Inuyasha\" Walsh", + "\"Kaito Sinclaire\"", "Marco \"Digiku\" Zafra", "", "\1Boss Design", From a5ab9f01bbb9114af91b3073e845136a848192a9 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 14 Mar 2018 16:49:10 +0000 Subject: [PATCH 049/212] oh yeah this guy's name needs changing too --- src/f_finale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index 17110df4f..36258664a 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1017,7 +1017,7 @@ static const char *credits[] = { "\1Music and Sound", "\1Production", "Malcolm \"RedXVI\" Brown", - "David \"Bulmybag\" Bulmer", + "Dave \"DemonTomatoDave\" Bulmer", "Paul \"Boinciel\" Clempson", "Cyan Helkaraxe", "Kepa \"Nev3r\" Iceta", From fee87141096949b139cd052f9f0e7a13861180e8 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 14 Mar 2018 16:55:33 +0000 Subject: [PATCH 050/212] i suck at the alphabet! --- src/f_finale.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 36258664a..0bcf24ed5 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -978,8 +978,8 @@ static const char *credits[] = { "Ronald \"Furyhunter\" Kinard", // The SDL2 port "John \"JTE\" Muniz", "Ehab \"Wolfy\" Saeed", - "\"SSNTails\"", "\"Kaito Sinclaire\"", + "\"SSNTails\"", "", "\1Programming", "\1Assistance", @@ -1041,13 +1041,13 @@ static const char *credits[] = { "Kepa \"Nev3r\" Iceta", "Thomas \"Shadow Hog\" Igoe", "Erik \"Torgo\" Nielsen", + "\"Kaito Sinclaire\"", "Wessel \"Spherallic\" Smit", "\"Spazzo\"", "\"SSNTails\"", "Rob Tisdell", "Jarrett \"JEV3\" Voight", "Johnny \"Sonikku\" Wallbank", - "\"Kaito Sinclaire\"", "Marco \"Digiku\" Zafra", "", "\1Boss Design", From 5a4ea9fab3d447abc5374ab24a361c43e6784ddf Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 15 Mar 2018 23:58:37 +0000 Subject: [PATCH 051/212] Better fog block colouring They still aren't perfect, but now they are at least not quite so obviously just translucent polygons over the level. A mixture between partially modulating the background colours and adding the fog colour. Notably white fog blocks look like they're brightening what's behind them. Additive was also setting noalphatest before, can probably decide that depending on what it needs anyway. I don't think it's currently used anyway. --- src/hardware/hw_defs.h | 5 ++-- src/hardware/hw_main.c | 40 +++++++++++++++----------------- src/hardware/r_opengl/r_opengl.c | 8 +++++++ 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 04802122e..c05ff3e79 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -133,12 +133,13 @@ enum EPolyFlags PF_Masked = 0x00000001, // Poly is alpha scaled and 0 alpha pels are discarded (holes in texture) PF_Translucent = 0x00000002, // Poly is transparent, alpha = level of transparency - PF_Additive = 0x00000024, // Poly is added to the frame buffer + PF_Additive = 0x00000004, // Poly is added to the frame buffer PF_Environment = 0x00000008, // Poly should be drawn environment mapped. // Hurdler: used for text drawing PF_Substractive = 0x00000010, // for splat PF_NoAlphaTest = 0x00000020, // hiden param - PF_Blending = (PF_Environment|PF_Additive|PF_Translucent|PF_Masked|PF_Substractive)&~PF_NoAlphaTest, + PF_Fog = 0x00000040, // Fog blocks + PF_Blending = (PF_Environment|PF_Additive|PF_Translucent|PF_Masked|PF_Substractive|PF_Fog)&~PF_NoAlphaTest, // other flag bits diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 33cf54a38..284c2c555 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -489,10 +489,10 @@ UINT32 HWR_Lighting(INT32 light, UINT32 color, UINT32 fadecolor, boolean fogbloc } -static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color, UINT32 fadecolor) // Let's see if this can work +static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color) // Let's see if this can work { - RGBA_t realcolor, fogcolor, surfcolor; - INT32 alpha, fogalpha; + RGBA_t realcolor, surfcolor; + INT32 alpha; // Don't go out of bounds if (light < 0) @@ -501,13 +501,11 @@ static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color, UINT32 fadecolor) // L light = 255; realcolor.rgba = color; - fogcolor.rgba = fadecolor; alpha = (realcolor.s.alpha*255)/25; - fogalpha = (fogcolor.s.alpha*255)/25; - // Fog blocks seem to get slightly more opaque with more opaque colourmap opacity, and much more opaque with darker brightness - surfcolor.s.alpha = (UINT8)(CALCLIGHT(light, ((0xFF-light)+alpha)/2)+CALCLIGHT(0xFF-light, ((light)+fogalpha)/2)); + // at 255 brightness, alpha is between 0 and 127, at 0 brightness alpha will always be 255 + surfcolor.s.alpha = (alpha*light)/(2*256)+255-light; return surfcolor.s.alpha; } @@ -773,7 +771,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, true); } - if (PolyFlags & PF_Translucent) + if (PolyFlags & (PF_Translucent|PF_Fog)) { Surf.FlatColor.s.alpha = (UINT8)alpha; PolyFlags |= PF_Modulated|PF_Occlude|PF_Clip; @@ -1380,7 +1378,7 @@ static void HWR_SplitFog(sector_t *sector, wallVert3D *wallVerts, FSurfaceInfo* wallVerts[0].y = wallVerts[1].y = bot; if (!solid) // Don't draw it if there's more fog behind it - HWR_AddTransparentWall(wallVerts, Surf, 0, PF_Translucent|PF_NoTexture, true, lightnum, colormap); + HWR_AddTransparentWall(wallVerts, Surf, 0, PF_Fog|PF_NoTexture, true, lightnum, colormap); top = height; } @@ -2306,7 +2304,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { FBITFIELD blendmode; - blendmode = PF_Translucent|PF_NoTexture; + blendmode = PF_Fog|PF_NoTexture; lightnum = rover->master->frontsector->lightlevel; colormap = rover->master->frontsector->extra_colormap; @@ -2314,11 +2312,11 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) if (rover->master->frontsector->extra_colormap) { - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba,rover->master->frontsector->extra_colormap->fadergba); + Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba); } else { - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG,FADEFOG); + Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG); } if (gr_frontsector->numlights) @@ -2426,18 +2424,18 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) { FBITFIELD blendmode; - blendmode = PF_Translucent|PF_NoTexture; + blendmode = PF_Fog|PF_NoTexture; lightnum = rover->master->frontsector->lightlevel; colormap = rover->master->frontsector->extra_colormap; if (rover->master->frontsector->extra_colormap) { - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba,rover->master->frontsector->extra_colormap->fadergba); + Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,rover->master->frontsector->extra_colormap->rgba); } else { - Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG,FADEFOG); + Surf.FlatColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel,NORMALFOG); } if (gr_backsector->numlights) @@ -3547,16 +3545,16 @@ static void HWR_Subsector(size_t num) light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); if (rover->master->frontsector->extra_colormap) - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba, rover->master->frontsector->extra_colormap->fadergba); + alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba); else - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG, FADEFOG); + alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG); HWR_AddTransparentFloor(0, &extrasubsectors[num], false, *rover->bottomheight, *gr_frontsector->lightlist[light].lightlevel, - alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture, + alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient @@ -3610,16 +3608,16 @@ static void HWR_Subsector(size_t num) light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); if (rover->master->frontsector->extra_colormap) - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba, rover->master->frontsector->extra_colormap->fadergba); + alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap->rgba); else - alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG, FADEFOG); + alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG); HWR_AddTransparentFloor(0, &extrasubsectors[num], true, *rover->topheight, *gr_frontsector->lightlist[light].lightlevel, - alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture, + alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 14cff5995..cf87c101e 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1187,6 +1187,14 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); #ifndef KOS_GL_COMPATIBILITY pglAlphaFunc(GL_NOTEQUAL, 0.0f); +#endif + break; + case PF_Fog & PF_Fog: + // Sryder: Fog + // multiplies input colour by input alpha, and destination colour by input colour, then adds them + pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR); +#ifndef KOS_GL_COMPATIBILITY + pglAlphaFunc(GL_NOTEQUAL, 0.0f); #endif break; default : // must be 0, otherwise it's an error From 1b3e1f78af6d58519a011eb84b55f3edf22e3cd0 Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 15 Mar 2018 23:59:01 +0000 Subject: [PATCH 052/212] Translucent floors shouldn't write into the depth buffer --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 284c2c555..83783072f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -774,7 +774,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is if (PolyFlags & (PF_Translucent|PF_Fog)) { Surf.FlatColor.s.alpha = (UINT8)alpha; - PolyFlags |= PF_Modulated|PF_Occlude|PF_Clip; + PolyFlags |= PF_Modulated|PF_Clip; } else PolyFlags |= PF_Masked|PF_Modulated|PF_Clip; From 7764a1bb5dcc8c91929c5c9a475e1f61633dce0c Mon Sep 17 00:00:00 2001 From: Sryder Date: Fri, 16 Mar 2018 18:08:24 +0000 Subject: [PATCH 053/212] Match HWR_DrawFixedPatch to V_DrawFixedPatch --- src/hardware/hw_draw.c | 103 ++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 867a86a15..30b0518cb 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -147,10 +147,7 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, // | /| // |/ | // 0--1 - float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; - float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); - float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); + float dupx, dupy, fscale, fwidth, fheight; if (alphalevel >= 10 && alphalevel < 13) return; @@ -161,40 +158,104 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, else HWR_GetMappedPatch(gpatch, colormap); + dupx = (float)vid.dupx; + dupy = (float)vid.dupy; + switch (option & V_SCALEPATCHMASK) { case V_NOSCALEPATCH: - pdupx = pdupy = 2.0f; + dupx = dupy = 1.0f; break; case V_SMALLSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy); + dupx = (float)vid.smalldupx; + dupy = (float)vid.smalldupy; break; case V_MEDSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy); + dupx = (float)vid.meddupx; + dupy = (float)vid.meddupy; break; } - if (option & V_NOSCALESTART) - sdupx = sdupy = 2.0f; + dupx = dupy = (dupx < dupy ? dupx : dupy); + fscale = FIXED_TO_FLOAT(pscale); - if (option & V_SPLITSCREEN) - sdupy /= 2.0f; - - if (option & V_FLIP) // Need to flip both this and sow + if (option & V_OFFSET) { - v[0].x = v[3].x = (cx*sdupx-(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; - v[2].x = v[1].x = (cx*sdupx+gpatch->leftoffset*pdupx)/vid.width - 1; + cx -= (float)gpatch->leftoffset * dupx * fscale; + cy -= (float)gpatch->topoffset * dupy * fscale; } else { - v[0].x = v[3].x = (cx*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; - v[2].x = v[1].x = (cx*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; + cy -= (float)gpatch->topoffset * fscale; + if (option & V_FLIP) + cx -= ((float)gpatch->width - (float)gpatch->leftoffset) * fscale; + else + cx -= (float)gpatch->leftoffset * fscale; } - v[0].y = v[1].y = 1-(cy*sdupy-gpatch->topoffset*pdupy)/vid.height; - v[2].y = v[3].y = 1-(cy*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; + if (option & V_SPLITSCREEN) + cy /= 2; + + if (!(option & V_NOSCALESTART)) + { + cx = cx * dupx; + cy = cy * dupy; + + if (!(option & V_SCALEPATCHMASK)) + { + // centre screen + if (vid.width != BASEVIDWIDTH * vid.dupx) + { + if (option & V_SNAPTORIGHT) + cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); + else if (!(option & V_SNAPTOLEFT)) + cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2; + } + if (vid.height != BASEVIDHEIGHT * vid.dupy) + { + if ((option & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + cy += ((float)vid.height/2 - ((float)BASEVIDHEIGHT/2 * dupy)); + else if (option & V_SNAPTOBOTTOM) + cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); + else if (!(option & V_SNAPTOTOP)) + cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2; + } + // if it's meant to cover the whole screen, black out the rest + // TODO + /*if (x == 0 && SHORT(gpatch->width) == BASEVIDWIDTH && y == 0 && SHORT(gpatch->height) == BASEVIDHEIGHT) + { + const column_t *column = (const column_t *)((const UINT8 *)((patch_t *)gpatch) + LONG(((patch_t *)gpatch)->columnofs[0])); + const UINT8 *source = (const UINT8 *)(column) + 3; + HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + }*/ + } + } + + if (pscale != FRACUNIT) + { + fwidth = (float)gpatch->width * fscale * dupx; + fheight = (float)gpatch->height * fscale * dupy; + } + else + { + fwidth = (float)gpatch->width * dupx; + fheight = (float)gpatch->height * dupy; + } + + // positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1 + cx = -1 + (cx / (vid.width/2)); + cy = 1 - (cy / (vid.height/2)); + + // fwidth and fheight are similar + fwidth /= vid.width / 2; + fheight /= vid.height / 2; + + // set the polygon vertices to the right positions + v[0].x = v[3].x = cx; + v[2].x = v[1].x = cx + fwidth; + + v[0].y = v[1].y = cy; + v[2].y = v[3].y = cy - fheight; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; From 7830c031f786e8820c7b29b9da7d2b5f094f75be Mon Sep 17 00:00:00 2001 From: Sryder Date: Fri, 16 Mar 2018 19:46:45 +0000 Subject: [PATCH 054/212] Make HWR_DrawFill match V_DrawFill --- src/hardware/hw_draw.c | 81 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 30b0518cb..c9ba87786 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -717,7 +717,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) { FOutVector v[4]; FSurfaceInfo Surf; - float sdupx, sdupy; + float fx, fy, fw, fh; if (w < 0 || h < 0) return; // consistency w/ software @@ -726,16 +726,79 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) // | /| // |/ | // 0--1 - sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; - sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - if (color & V_NOSCALESTART) - sdupx = sdupy = 2.0f; + fx = (float)x; + fy = (float)y; + fw = (float)w; + fh = (float)h; - v[0].x = v[3].x = (x*sdupx)/vid.width - 1; - v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(y*sdupy)/vid.height; - v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height; + if (!(color & V_NOSCALESTART)) + { + float dupx = (float)vid.dupx, dupy = (float)vid.dupy; + + if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) + { + RGBA_t rgbaColour = V_GetColor(color); + FRGBAFloat clearColour; + clearColour.red = (float)rgbaColour.s.red / 255; + clearColour.green = (float)rgbaColour.s.green / 255; + clearColour.blue = (float)rgbaColour.s.blue / 255; + clearColour.alpha = 1; + HWD.pfnClearBuffer(true, false, &clearColour); + return; + } + + fx *= dupx; + fy *= dupy; + fw *= dupx; + fh *= dupy; + + if (vid.width != BASEVIDWIDTH * vid.dupx) + { + if (color & V_SNAPTORIGHT) + fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); + else if (!(color & V_SNAPTOLEFT)) + fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if (color & V_SNAPTOBOTTOM) + fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); + else if (!(color & V_SNAPTOTOP)) + fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2; + } + } + + if (fx >= vid.width || fy >= vid.height) + return; + if (fx < 0) + { + fw += fx; + fx = 0; + } + if (fy < 0) + { + fh += fy; + fy = 0; + } + + if (fw <= 0 || fh <= 0) + return; + if (fx + fw > vid.width) + fw = (float)vid.width - fx; + if (fy + fh > vid.height) + fh = (float)vid.height - fy; + + fx = -1 + fx / (vid.width / 2); + fy = 1 - fy / (vid.height / 2); + fw = fw / (vid.width / 2); + fh = fh / (vid.height / 2); + + v[0].x = v[3].x = fx; + v[2].x = v[1].x = fx + fw; + v[0].y = v[1].y = fy; + v[2].y = v[3].y = fy - fh; //Hurdler: do we still use this argb color? if not, we should remove it v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; From 801f7547d3893a338fa40fe86afeeab46a60f87d Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 17 Mar 2018 13:26:43 +0000 Subject: [PATCH 055/212] Add the full-screen drawfill functionality to HWR_DrawFixedPatch --- src/hardware/hw_draw.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index c9ba87786..8b5c2f76c 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -203,6 +203,18 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, if (!(option & V_SCALEPATCHMASK)) { + // if it's meant to cover the whole screen, black out the rest + // cx and cy are possibly *slightly* off from float maths + // This is done before here compared to software because we directly alter cx and cy to centre + if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) + { + // Need to temporarily cache the real patch to get the colour of the top left pixel + patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); + const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); + const UINT8 *source = (const UINT8 *)(column) + 3; + HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + Z_Free(realpatch); + } // centre screen if (vid.width != BASEVIDWIDTH * vid.dupx) { @@ -220,14 +232,6 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, else if (!(option & V_SNAPTOTOP)) cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2; } - // if it's meant to cover the whole screen, black out the rest - // TODO - /*if (x == 0 && SHORT(gpatch->width) == BASEVIDWIDTH && y == 0 && SHORT(gpatch->height) == BASEVIDHEIGHT) - { - const column_t *column = (const column_t *)((const UINT8 *)((patch_t *)gpatch) + LONG(((patch_t *)gpatch)->columnofs[0])); - const UINT8 *source = (const UINT8 *)(column) + 3; - HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); - }*/ } } From a9214ebd378414401d67c3beb720bcd7b8b1ecf3 Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 17 Mar 2018 13:58:44 +0000 Subject: [PATCH 056/212] Match HWR_DrawCroppedPatch to V_DrawCroppedPatch --- src/hardware/hw_draw.c | 108 +++++++++++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 15 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 8b5c2f76c..14e9b6f54 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -312,10 +312,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // | /| // |/ | // 0--1 - float sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; - float sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; - float pdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f*FIXED_TO_FLOAT(pscale); - float pdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f*FIXED_TO_FLOAT(pscale); + float dupx, dupy, fscale, fwidth, fheight; if (alphalevel >= 10 && alphalevel < 13) return; @@ -323,28 +320,109 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // make patch ready in hardware cache HWR_GetPatch(gpatch); + dupx = (float)vid.dupx; + dupy = (float)vid.dupy; + switch (option & V_SCALEPATCHMASK) { case V_NOSCALEPATCH: - pdupx = pdupy = 2.0f; + dupx = dupy = 1.0f; break; case V_SMALLSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fsmalldupy); + dupx = (float)vid.smalldupx; + dupy = (float)vid.smalldupy; break; case V_MEDSCALEPATCH: - pdupx = 2.0f * FIXED_TO_FLOAT(vid.fmeddupx); - pdupy = 2.0f * FIXED_TO_FLOAT(vid.fmeddupy); + dupx = (float)vid.meddupx; + dupy = (float)vid.meddupy; break; } - if (option & V_NOSCALESTART) - sdupx = sdupy = 2.0f; + dupx = dupy = (dupx < dupy ? dupx : dupy); + fscale = FIXED_TO_FLOAT(pscale); - v[0].x = v[3].x = (cx*sdupx - gpatch->leftoffset * pdupx) / vid.width - 1; - v[2].x = v[1].x = (cx*sdupx + ((w-sx) - gpatch->leftoffset) * pdupx) / vid.width - 1; - v[0].y = v[1].y = 1 - (cy*sdupy - gpatch->topoffset * pdupy) / vid.height; - v[2].y = v[3].y = 1 - (cy*sdupy + ((h-sy) - gpatch->topoffset) * pdupy) / vid.height; + cy -= (float)gpatch->topoffset * fscale; + cx -= (float)gpatch->leftoffset * fscale; + + if (!(option & V_NOSCALESTART)) + { + cx = cx * dupx; + cy = cy * dupy; + + if (!(option & V_SCALEPATCHMASK)) + { + // if it's meant to cover the whole screen, black out the rest + // cx and cy are possibly *slightly* off from float maths + // This is done before here compared to software because we directly alter cx and cy to centre + if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) + { + // Need to temporarily cache the real patch to get the colour of the top left pixel + patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); + const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); + const UINT8 *source = (const UINT8 *)(column) + 3; + HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + Z_Free(realpatch); + } + // centre screen + if (vid.width != BASEVIDWIDTH * vid.dupx) + { + if (option & V_SNAPTORIGHT) + cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); + else if (!(option & V_SNAPTOLEFT)) + cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2; + } + if (vid.height != BASEVIDHEIGHT * vid.dupy) + { + if ((option & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + cy += ((float)vid.height/2 - ((float)BASEVIDHEIGHT/2 * dupy)); + else if (option & V_SNAPTOBOTTOM) + cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); + else if (!(option & V_SNAPTOTOP)) + cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2; + } + } + } + + fwidth = w; + fheight = h; + + if (fwidth > w - sx) + fwidth = w - sx; + + if (fheight > h - sy) + fheight = h - sy; + + if (fwidth > gpatch->width) + fwidth = gpatch->width; + + if (fheight > gpatch->height) + fheight = gpatch->height; + + if (pscale != FRACUNIT) + { + fwidth *= fscale * dupx; + fheight *= fscale * dupy; + } + else + { + fwidth *= dupx; + fheight *= dupy; + } + + // positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1 + cx = -1 + (cx / (vid.width/2)); + cy = 1 - (cy / (vid.height/2)); + + // fwidth and fheight are similar + fwidth /= vid.width / 2; + fheight /= vid.height / 2; + + // set the polygon vertices to the right positions + v[0].x = v[3].x = cx; + v[2].x = v[1].x = cx + fwidth; + + v[0].y = v[1].y = cy; + v[2].y = v[3].y = cy - fheight; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; From 6de0cc6bccb02529107cc2c7a093969784214d6f Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 17 Mar 2018 14:47:06 +0000 Subject: [PATCH 057/212] Remove the OpenGL only code from V_DrawPatchFill That's all of the HUD drawing functions that are currently used updated in GL. --- src/v_video.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index cc81cedbc..161c03d0b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -937,14 +937,6 @@ void V_DrawPatchFill(patch_t *pat) INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); INT32 x, y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz; -#ifdef HWRENDER - if (rendermode == render_opengl) - { - pw = FixedMul(SHORT(pat->width)*FRACUNIT, vid.fdupx)>>FRACBITS; - ph = FixedMul(SHORT(pat->height)*FRACUNIT, vid.fdupy)>>FRACBITS; - } -#endif - for (x = 0; x < vid.width; x += pw) { for (y = 0; y < vid.height; y += ph) From 527df5c248cbb9e453355cdd9a14aa8698dea00e Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 17 Mar 2018 15:11:32 +0000 Subject: [PATCH 058/212] Fix OpenGL Title Screen Sky My IDE doesn't seem to like Vada's name. --- src/f_finale.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 692abb35f..f2a9f4038 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -233,11 +233,19 @@ static void F_SkyScroll(INT32 scrollspeed) #ifdef HWRENDER else if (rendermode != render_none) { // if only software rendering could be this simple and retarded - scrolled = animtimer; - if (scrolled > 0) - V_DrawScaledPatch(scrolled - SHORT(pat->width), 0, 0, pat); - for (x = 0; x < fakedwidth; x += SHORT(pat->width)) - V_DrawScaledPatch(x + scrolled, 0, 0, pat); + INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); + INT32 x, y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz; + scrolled = animtimer * dupz; + for (x = 0; x < vid.width; x += pw) + { + for (y = 0; y < vid.height; y += ph) + { + if (scrolled > 0) + V_DrawScaledPatch(scrolled - pw, y, V_NOSCALESTART, pat); + + V_DrawScaledPatch(x + scrolled, y, V_NOSCALESTART, pat); + } + } } #endif @@ -999,7 +1007,7 @@ static const char *credits[] = { "", "\1Sprite Artists", "Odi \"Iceman404\" Atunzu", - "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: + "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: "Jim \"MotorRoach\" DeMello", "Desmond \"Blade\" DesJardins", "Sherman \"CoatRack\" DesJardins", From 31d1ef8db05c77a755d243c6b612fd32886cbc45 Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 17 Mar 2018 19:22:14 +0000 Subject: [PATCH 059/212] Draw the final screen texture in the centre with black bars Only applies when the monitor aspect ratio is different to the game's aspect ratio. --- src/hardware/r_opengl/r_opengl.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index cf87c101e..026d0126b 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2601,6 +2601,9 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void) EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) { float xfix, yfix; + float origaspect, newaspect; + float xoff = 1, yoff = 1; // xoffset and yoffset for the polygon to have black bars around the screen + FRGBAFloat clearColour; INT32 texsize = 2048; if(screen_width <= 1024) @@ -2611,28 +2614,43 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); - //pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + origaspect = (float)screen_width / screen_height; + newaspect = (float)width / height; + if (origaspect < newaspect) + { + xoff = origaspect / newaspect; + yoff = 1; + } + else if (origaspect > newaspect) + { + xoff = 1; + yoff = newaspect / origaspect; + } + pglViewport(0, 0, width, height); + clearColour.red = clearColour.green = clearColour.blue = 0; + clearColour.alpha = 1; + ClearBuffer(true, false, &clearColour); pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); pglBegin(GL_QUADS); pglColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Bottom left pglTexCoord2f(0.0f, 0.0f); - pglVertex3f(-1, -1, 1.0f); + pglVertex3f(-xoff, -yoff, 1.0f); // Top left pglTexCoord2f(0.0f, yfix); - pglVertex3f(-1, 1, 1.0f); + pglVertex3f(-xoff, yoff, 1.0f); // Top right pglTexCoord2f(xfix, yfix); - pglVertex3f(1, 1, 1.0f); + pglVertex3f(xoff, yoff, 1.0f); // Bottom right pglTexCoord2f(xfix, 0.0f); - pglVertex3f(1, -1, 1.0f); + pglVertex3f(xoff, -yoff, 1.0f); pglEnd(); From a984d979d113e119ca64ca4e53693064470c22f9 Mon Sep 17 00:00:00 2001 From: Sryder Date: Sun, 18 Mar 2018 17:12:12 +0000 Subject: [PATCH 060/212] Fix wipes in low resolutions --- src/hardware/r_opengl/r_opengl.c | 15 ++++++--------- src/sdl/ogl_sdl.c | 7 +++++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 026d0126b..5d861e618 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2538,14 +2538,14 @@ EXPORT void HWRAPI(MakeScreenTexture) (void) if (firstTime) { #ifdef KOS_GL_COMPATIBILITY - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_FILTER_NONE); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_FILTER_NONE); #else - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #endif - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); + Clamp2D(GL_TEXTURE_WRAP_S); + Clamp2D(GL_TEXTURE_WRAP_T); #ifndef KOS_GL_COMPATIBILITY pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); #endif @@ -2654,9 +2654,6 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) pglEnd(); - SetModelView(screen_width, screen_height); - SetStates(); - tex_downloaded = finalScreenTexture; } diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index cd7ced7ca..4347b35b2 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -214,8 +214,11 @@ void OglSdlFinishUpdate(boolean waitvbl) HWR_DrawScreenFinalTexture(sdlw, sdlh); SDL_GL_SwapWindow(window); - SetModelView(realwidth, realheight); - SetStates(); + GClipRect(0, 0, realwidth, realheight, NZCLIP_PLANE); + + // Sryder: We need to draw the final screen texture again into the other buffer in the original position so that + // effects that want to take the old screen can do so after this + HWR_DrawScreenFinalTexture(realwidth, realheight); } EXPORT void HWRAPI( OglSdlSetPalette) (RGBA_t *palette, RGBA_t *pgamma) From f3d63b82cedd57b668d334607d4d22f935c3381d Mon Sep 17 00:00:00 2001 From: Sryder Date: Sun, 18 Mar 2018 18:31:51 +0000 Subject: [PATCH 061/212] Revert "Fix screenshot functionality in fullscreen in SDL2" This reverts commit 121fcd83692d2e3946678bc270a80fe679247110. The reason I am reverting this is because the last commit actually fixes the *old* screenshot functionality, as the screen is being drawn back onto the buffer after they're swapped in the "real" size. Meaning the old function actually works perfectly fine now. --- src/hardware/hw_draw.c | 14 ------ src/hardware/hw_drv.h | 6 --- src/hardware/r_opengl/r_opengl.c | 79 -------------------------------- src/sdl/hwsym_sdl.c | 1 - src/sdl/i_video.c | 1 - src/sdl12/hwsym_sdl.c | 1 - src/sdl12/i_video.c | 1 - 7 files changed, 103 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 14e9b6f54..84081dd25 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -975,9 +975,6 @@ UINT8 *HWR_GetScreenshot(void) if (!buf) return NULL; // returns 24bit 888 RGB -#ifdef HAVE_SDL - if (!HWD.pfnReadScreenTexture(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf)) -#endif HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); return buf; } @@ -991,19 +988,8 @@ boolean HWR_Screenshot(const char *lbmname) return false; // returns 24bit 888 RGB -#ifdef HAVE_SDL - // Sryder: SDL2 uses borderless fullscreen mode, and creates a screen texture to upscale to the screen size. - // This breaks screenshots because the code here takes a screenshot of just the resolution from the bottom - // left corner, while the "true" resolution is the monitor resolution. We can either take a screenshot of - // the true resolution or just use the already made screen texture - // NOTE: The SDL1.2 version should get a return of false from ReadScreenTexture as no screen texture will have - // been made, this will also mean that if the screen texture doesn't exist for some reason it will fall - // back to the old version - if (!HWD.pfnReadScreenTexture(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf)) -#endif HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); - #ifdef USE_PNG ret = M_SavePNG(lbmname, buf, vid.width, vid.height, NULL); #else diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index ab4025697..a5ac82001 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -58,9 +58,6 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); -#ifdef HAVE_SDL -EXPORT boolean HWRAPI(ReadScreenTexture) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 * dst_data); -#endif EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -107,9 +104,6 @@ struct hwdriver_s ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; ReadRect pfnReadRect; -#ifdef HAVE_SDL - ReadScreenTexture pfnReadScreenTexture; -#endif GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 5d861e618..8e3ae3e21 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -260,7 +260,6 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) #define pglTexEnvi glTexEnvi #define pglTexParameteri glTexParameteri #define pglTexImage2D glTexImage2D -#define pglGetTexImage glGetTexImage /* Fog */ #define pglFogf glFogf @@ -382,8 +381,6 @@ typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint static PFNglTexParameteri pglTexParameteri; typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); static PFNglTexImage2D pglTexImage2D; -typedef void (APIENTRY * PFNglGetTexImage) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -static PFNglGetTexImage pglGetTexImage; /* Fog */ typedef void (APIENTRY * PFNglFogf) (GLenum pname, GLfloat param); @@ -510,7 +507,6 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglTexEnvi , glTexEnvi) GETOPENGLFUNC(pglTexParameteri , glTexParameteri) GETOPENGLFUNC(pglTexImage2D , glTexImage2D) - GETOPENGLFUNC(pglGetTexImage , glGetTexImage) GETOPENGLFUNC(pglFogf , glFogf) GETOPENGLFUNC(pglFogfv , glFogfv) @@ -937,81 +933,6 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, #endif } -#ifdef HAVE_SDL -EXPORT boolean HWRAPI(ReadScreenTexture) (INT32 x, INT32 y, INT32 width, - INT32 height, INT32 dst_stride, - UINT16 * dst_data) -{ -#ifdef KOS_GL_COMPATIBILITY - (void)x; - (void)y; - (void)width; - (void)height; - (void)dst_stride; - (void)dst_data; -#else - INT32 i, j; - INT32 texsize = 2048; - GLubyte *image; - // DBG_Printf ("ReadScreenTexture()\n"); - if (screentexture == 0) - return false; // No screen texture - - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; - - if (x < 0) - x = 0; - if (x + width > screen_width) - width = screen_width - x; - if (y < 0) - y = 0; - if (y + height > screen_height) - height = screen_height - y; - - image = malloc(texsize*texsize*3*sizeof (*image)); - if (!image) - return false; - pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); - tex_downloaded = finalScreenTexture; - pglGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - - if (dst_stride == width*3) - { - UINT8 *dest = (void *)dst_data; - for (i = y + height-1; i >= y; i--) - { - for (j = x; j < width + x; j++) - { - dest[((height-1-i-y)*width+j-x)*3] = image[(i*texsize+j)*3]; - dest[((height-1-i-y)*width+j-x)*3+1] = image[(i*texsize+j)*3+1]; - dest[((height-1-i-y)*width+j-x)*3+2] = image[(i*texsize+j)*3+2]; - } - } - } - else - { - // Sryder: NOTE: I'm not entirely sure this works, as far as I know nothing in the game uses it. - for (i = y + height-1; i >= y; i--) - { - for (j = x; j < width + x; j++) - { - dst_data[(height-1-i-y)*width+j-x] = - (UINT16)( - ((image[(i*texsize+j)*3]>>3)<<11) | - ((image[(i*texsize+j)*3+1]>>2)<<5) | - ((image[(i*texsize+j)*3+2]>>3))); - } - } - } - free(image); - return true; -#endif -} -#endif - // -----------------+ // GClipRect : Defines the 2D hardware clipping window diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 33bcfd6f3..05ac6450e 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -83,7 +83,6 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ClearBuffer); GETFUNC(SetTexture); GETFUNC(ReadRect); - GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 2df8a6ff5..87ce84158 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1430,7 +1430,6 @@ void I_StartupGraphics(void) HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL); - HWD.pfnReadScreenTexture= hwSym("ReadScreenTexture",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); diff --git a/src/sdl12/hwsym_sdl.c b/src/sdl12/hwsym_sdl.c index 3a10d8253..49340138f 100644 --- a/src/sdl12/hwsym_sdl.c +++ b/src/sdl12/hwsym_sdl.c @@ -89,7 +89,6 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ClearBuffer); GETFUNC(SetTexture); GETFUNC(ReadRect); - GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); diff --git a/src/sdl12/i_video.c b/src/sdl12/i_video.c index 076ce4fd2..349e06cba 100644 --- a/src/sdl12/i_video.c +++ b/src/sdl12/i_video.c @@ -1960,7 +1960,6 @@ void I_StartupGraphics(void) HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL); - HWD.pfnReadScreenTexture= hwSym("ReadScreenTexture",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); From 7d1885917ac8a06713b33f7cf68b79d630d2c2b5 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 18 Mar 2018 18:26:41 +0000 Subject: [PATCH 062/212] Some minor intro tweaks. --- src/f_finale.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 05c3d5fc0..a85655e53 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -322,7 +322,7 @@ void F_StartIntro(void) "hovers around the planet.\xBF It suddenly\n" "appears from nowhere, circles around, and\n" "\xB6- just as mysteriously as it arrives -\xB6\n" - "vanishes after about two months.\xBF\n" + "vanishes after about one week.\xBF\n" "No one knows why it appears, or how.\n#"); introtext[5] = M_GetText( @@ -334,11 +334,11 @@ void F_StartIntro(void) "the screen, and just shrugged it off.\n#"); introtext[6] = M_GetText( - "It was only later\n" + "It was hours later\n" "that he had an\n" "idea. \xBF\xA7\"The Black\n" - "Rock usually has a\n" - "lot of energy\n" + "Rock has a large\n" + "amount of energy\n" "within it\xAC...\xA7\xBF\n" "If I can somehow\n" "harness this,\xB8 I\n" @@ -356,37 +356,37 @@ void F_StartIntro(void) "a reunion party...\n#"); introtext[8] = M_GetText( - "\xA5\"We're\xB6 ready\xB6 to\xB4 fire\xB6 in\xB6 15\xB6 seconds!\"\xA8\xB8\n" - "The robot said, his voice crackling a\n" - "little down the com-link. \xBF\xA7\"Good!\"\xA8\xB8\n" - "Eggman sat back in his Egg-Mobile and\n" + "\xA5\"PRE-""\xB6""PARING-""\xB6""TO-""\xB4""FIRE-\xB6IN-""\xB6""15-""\xB6""SECONDS!\"\xA8\xB8\n" + "his targeting system crackled\n" + "robotically down the com-link. \xBF\xA7\"Good!\"\xA8\xB8\n" + "Eggman sat back in his eggmobile and\n" "began to count down as he saw the\n" - "GreenFlower city on the main monitor.\n#"); + "Greenflower mountain on the monitor.\n#"); introtext[9] = M_GetText( "\xA5\"10...\xD2""9...\xD2""8...\"\xA8\xD2\n" "Meanwhile, Sonic was tearing across the\n" "zones. Everything became a blur as he\n" - "ran around loops, skimmed over water,\n" + "ran up slopes, skimmed over water,\n" "and catapulted himself off rocks with\n" "his phenomenal speed.\n#"); introtext[10] = M_GetText( "\xA5\"6...\xD2""5...\xD2""4...\"\xA8\xD2\n" "Sonic knew he was getting closer to the\n" - "City, and pushed himself harder.\xB4 Finally,\n" - "the city appeared in the horizon.\xD2\xD2\n" + "zone, and pushed himself harder.\xB4 Finally,\n" + "the mountain appeared in the horizon.\xD2\xD2\n" "\xA5\"3...\xD2""2...\xD2""1...\xD2""Zero.\"\n#"); introtext[11] = M_GetText( - "GreenFlower City was gone.\xC4\n" + "Greenflower Mountain was no more.\xC4\n" "Sonic arrived just in time to see what\n" "little of the 'ruins' were left.\n" - "Everyone and everything in the city\n" + "The natural beauty of the zone\n" "had been obliterated.\n#"); introtext[12] = M_GetText( - "\xA7\"You're not quite as dead as we thought,\n" + "\xA7\"You're not quite as gone as we thought,\n" "huh?\xBF Are you going to tell us your plan as\n" "usual or will I \xA8\xB4'have to work it out'\xA7 or\n" "something?\"\xD2\xD2\n" @@ -400,8 +400,8 @@ void F_StartIntro(void) "leaving Sonic\n" "and Tails behind.\xB6\n" "Tails looked at\n" - "the ruins of the\n" - "Greenflower City\n" + "the once-perfect\n" + "mountainside\n" "with a grim face\n" "and sighed.\xC6\n" "\xA7\"Now\xB6 what do we\n" From c0cc1471e5b0842a0138be0df7842f6a8aea620e Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 19 Mar 2018 16:39:37 +0000 Subject: [PATCH 063/212] Make some tweaks to devmode offsets. --- src/st_stuff.c | 67 ++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 6d6c2d017..5601a85ee 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -470,55 +470,55 @@ static void ST_DrawNightsOverlayNum(fixed_t x /* right border */, fixed_t y, fix static void ST_drawDebugInfo(void) { INT32 height = 192; - INT32 dist = 8; if (!(stplyr->mo && cv_debug)) return; if (cv_ticrate.value) - { height -= 12; - dist >>= 1; - } + +#define dist 4 +#define VFLAGS V_MONOSPACE|V_SNAPTOBOTTOM|V_SNAPTORIGHT if (cv_debug & DBG_BASIC) { const fixed_t d = AngleFixed(stplyr->mo->angle); - V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); - V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS)); - V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS)); - V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d))); + V_DrawRightAlignedString(320, height - 24, VFLAGS, va("X: %6d", stplyr->mo->x>>FRACBITS)); + V_DrawRightAlignedString(320, height - 16, VFLAGS, va("Y: %6d", stplyr->mo->y>>FRACBITS)); + V_DrawRightAlignedString(320, height - 8, VFLAGS, va("Z: %6d", stplyr->mo->z>>FRACBITS)); + V_DrawRightAlignedString(320, height, VFLAGS, va("A: %6d", FixedInt(d))); height -= (32+dist); } if (cv_debug & DBG_DETAILED) { - V_DrawRightAlignedString(320, height - 104, V_MONOSPACE, va("SHIELD: %5x", stplyr->powers[pw_shield])); - V_DrawRightAlignedString(320, height - 96, V_MONOSPACE, va("SCALE: %5d%%", (stplyr->mo->scale*100)/FRACUNIT)); - V_DrawRightAlignedString(320, height - 88, V_MONOSPACE, va("CARRY: %5x", stplyr->powers[pw_carry])); - V_DrawRightAlignedString(320, height - 80, V_MONOSPACE, va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime])); + V_DrawRightAlignedString(320, height - 104, VFLAGS, va("SHIELD: %5x", stplyr->powers[pw_shield])); + V_DrawRightAlignedString(320, height - 96, VFLAGS, va("SCALE: %5d%%", (stplyr->mo->scale*100)/FRACUNIT)); + V_DrawRightAlignedString(320, height - 88, VFLAGS, va("CARRY: %5x", stplyr->powers[pw_carry])); + V_DrawRightAlignedString(320, height - 80, VFLAGS, va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime])); // Flags - V_DrawRightAlignedString(304-92, height - 72, V_MONOSPACE, "PF:"); - V_DrawString(304-90, height - 72, (stplyr->pflags & PF_STARTJUMP) ? V_GREENMAP : V_REDMAP, "SJ"); - V_DrawString(304-72, height - 72, (stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP, "JD"); - V_DrawString(304-54, height - 72, (stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP, "SP"); - V_DrawString(304-36, height - 72, (stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP, "ST"); - V_DrawString(304-18, height - 72, (stplyr->pflags & PF_THOKKED) ? V_GREENMAP : V_REDMAP, "TH"); - V_DrawString(304, height - 72, (stplyr->pflags & PF_SHIELDABILITY) ? V_GREENMAP : V_REDMAP, "SH"); + V_DrawRightAlignedString(304-92, height - 72, VFLAGS, "PF:"); + V_DrawString(304-90, height - 72, VFLAGS|((stplyr->pflags & PF_STARTJUMP) ? V_GREENMAP : V_REDMAP), "SJ"); + V_DrawString(304-72, height - 72, VFLAGS|((stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP), "JD"); + V_DrawString(304-54, height - 72, VFLAGS|((stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP), "SP"); + V_DrawString(304-36, height - 72, VFLAGS|((stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP), "ST"); + V_DrawString(304-18, height - 72, VFLAGS|((stplyr->pflags & PF_THOKKED) ? V_GREENMAP : V_REDMAP), "TH"); + V_DrawString(304, height - 72, VFLAGS|((stplyr->pflags & PF_SHIELDABILITY) ? V_GREENMAP : V_REDMAP), "SH"); - V_DrawRightAlignedString(320, height - 64, V_MONOSPACE, va("CEILZ: %6d", stplyr->mo->ceilingz>>FRACBITS)); - V_DrawRightAlignedString(320, height - 56, V_MONOSPACE, va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS)); + V_DrawRightAlignedString(320, height - 64, VFLAGS, va("CEILZ: %6d", stplyr->mo->ceilingz>>FRACBITS)); + V_DrawRightAlignedString(320, height - 56, VFLAGS, va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS)); - V_DrawRightAlignedString(320, height - 48, V_MONOSPACE, va("CNVX: %6d", stplyr->cmomx>>FRACBITS)); - V_DrawRightAlignedString(320, height - 40, V_MONOSPACE, va("CNVY: %6d", stplyr->cmomy>>FRACBITS)); - V_DrawRightAlignedString(320, height - 32, V_MONOSPACE, va("PLTZ: %6d", stplyr->mo->pmomz>>FRACBITS)); + V_DrawRightAlignedString(320, height - 48, VFLAGS, va("CNVX: %6d", stplyr->cmomx>>FRACBITS)); + V_DrawRightAlignedString(320, height - 40, VFLAGS, va("CNVY: %6d", stplyr->cmomy>>FRACBITS)); + V_DrawRightAlignedString(320, height - 32, VFLAGS, va("PLTZ: %6d", stplyr->mo->pmomz>>FRACBITS)); - V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("MOMX: %6d", stplyr->rmomx>>FRACBITS)); - V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("MOMY: %6d", stplyr->rmomy>>FRACBITS)); - V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS)); - V_DrawRightAlignedString(320, height, V_MONOSPACE, va("SPEED: %6d", stplyr->speed>>FRACBITS)); + V_DrawRightAlignedString(320, height - 24, VFLAGS, va("MOMX: %6d", stplyr->rmomx>>FRACBITS)); + V_DrawRightAlignedString(320, height - 16, VFLAGS, va("MOMY: %6d", stplyr->rmomy>>FRACBITS)); + V_DrawRightAlignedString(320, height - 8, VFLAGS, va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS)); + + V_DrawRightAlignedString(320, height, VFLAGS, va("SPEED: %6d", stplyr->speed>>FRACBITS)); height -= (112+dist); } @@ -529,17 +529,20 @@ static void ST_drawDebugInfo(void) peekres *= 10000; // Change from fixed point peekres >>= FRACBITS; // to displayable decimal - V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Init: %08x", P_GetInitSeed())); - V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Seed: %08x", P_GetRandSeed())); - V_DrawRightAlignedString(320, height, V_MONOSPACE, va("== : .%04d", peekres)); + V_DrawRightAlignedString(320, height - 16, VFLAGS, va("Init: %08x", P_GetInitSeed())); + V_DrawRightAlignedString(320, height - 8, VFLAGS, va("Seed: %08x", P_GetRandSeed())); + V_DrawRightAlignedString(320, height, VFLAGS, va("== : .%04d", peekres)); height -= (24+dist); } if (cv_debug & DBG_MEMORY) { - V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); + V_DrawRightAlignedString(320, height, VFLAGS, va("Heap: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); } + +#undef VFLAGS +#undef dist } static void ST_drawScore(void) From 4798f853826820d12fc81b4cbe9b0617898d6908 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 19 Mar 2018 16:40:15 +0000 Subject: [PATCH 064/212] Fix issues with the level platter in nonstandard resolutions. --- src/m_menu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 9f1b7efe7..24beff317 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4425,14 +4425,14 @@ static void M_DrawLevelPlatterMenu(void) V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); // finds row at top of the screen - while (y > 0) + while (y > -8) { iter = ((iter == 0) ? levelselect.numrows-1 : iter-1); y -= lsvseperation(iter); } // draw from top to bottom - while (y < 200) + while (y < (vid.height/vid.dupy)) { M_DrawLevelPlatterRow(iter, y); y += lsvseperation(iter); From 7885ae57e2e33af4e62025bea18c749ca62168d1 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 19 Mar 2018 23:08:51 +0000 Subject: [PATCH 065/212] * Allow for V_ flag control for hudinfo SOC/Lua stuff through hudinfo[n].f (for flags). * Fix Old Special Stage offsets. * Fix drowning number offsets. * Remove useless "WS" macros. --- src/dehacked.c | 4 + src/lua_hudlib.c | 10 ++- src/st_stuff.c | 194 ++++++++++++++++++++++++----------------------- src/st_stuff.h | 2 +- src/y_inter.c | 6 +- 5 files changed, 117 insertions(+), 99 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 7202ba31b..0804999a8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1584,6 +1584,10 @@ static void readhuditem(MYFILE *f, INT32 num) { hudinfo[num].y = i; } + else if (fastcmp(word, "F")) + { + hudinfo[num].f = i; + } else deh_warning("Level header %d: unknown word '%s'", num, word); } diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 6991f00e7..a709ba9f4 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -63,12 +63,14 @@ static const char *const hud_disable_options[] = { enum hudinfo { hudinfo_x = 0, - hudinfo_y + hudinfo_y, + hudinfo_f }; static const char *const hudinfo_opt[] = { "x", "y", + "f", NULL}; enum patch { @@ -198,6 +200,9 @@ static int hudinfo_get(lua_State *L) case hudinfo_y: lua_pushinteger(L, info->y); break; + case hudinfo_f: + lua_pushinteger(L, info->f); + break; } return 1; } @@ -216,6 +221,9 @@ static int hudinfo_set(lua_State *L) case hudinfo_y: info->y = (INT32)luaL_checkinteger(L, 3); break; + case hudinfo_f: + info->f = (INT32)luaL_checkinteger(L, 3); + break; } return 0; } diff --git a/src/st_stuff.c b/src/st_stuff.c index 5601a85ee..4f7c8fc28 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -125,32 +125,34 @@ static boolean facefreed[MAXPLAYERS]; hudinfo_t hudinfo[NUMHUDITEMS] = { - { 16, 176}, // HUD_LIVES + { 16, 176, V_SNAPTOLEFT|V_SNAPTOBOTTOM}, // HUD_LIVES - { 16, 42}, // HUD_RINGS - { 96, 42}, // HUD_RINGSNUM - { 120, 42}, // HUD_RINGSNUMTICS + { 16, 42, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_RINGS + { 96, 42, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_RINGSNUM + { 120, 42, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_RINGSNUMTICS - { 16, 10}, // HUD_SCORE - { 120, 10}, // HUD_SCORENUM + { 16, 10, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_SCORE + { 120, 10, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_SCORENUM - { 16, 26}, // HUD_TIME - { 72, 26}, // HUD_MINUTES - { 72, 26}, // HUD_TIMECOLON - { 96, 26}, // HUD_SECONDS - { 96, 26}, // HUD_TIMETICCOLON - { 120, 26}, // HUD_TICS + { 16, 26, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_TIME + { 72, 26, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_MINUTES + { 72, 26, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_TIMECOLON + { 96, 26, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_SECONDS + { 96, 26, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_TIMETICCOLON + { 120, 26, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_TICS - { 120, 56}, // HUD_SS_TOTALRINGS + { 0, 56, V_SNAPTOLEFT|V_SNAPTOTOP}, // HUD_SS_TOTALRINGS - { 110, 93}, // HUD_GETRINGS - { 160, 93}, // HUD_GETRINGSNUM - { 124, 160}, // HUD_TIMELEFT - { 168, 176}, // HUD_TIMELEFTNUM - { 130, 93}, // HUD_TIMEUP - { 152, 168}, // HUD_HUNTPICS - { 152, 24}, // HUD_GRAVBOOTSICO - { 240, 160}, // HUD_LAP + { 110, 93, 0}, // HUD_GETRINGS + { 160, 93, 0}, // HUD_GETRINGSNUM + { 124, 160, 0}, // HUD_TIMELEFT + { 168, 176, 0}, // HUD_TIMELEFTNUM + { 130, 93, 0}, // HUD_TIMEUP + { 152, 168, 0}, // HUD_HUNTPICS + + { 152, 24, V_SNAPTORIGHT}, // HUD_GRAVBOOTSICO + + { 240, 160, V_SNAPTOBOTTOM|V_SNAPTORIGHT}, // HUD_LAP }; // @@ -427,12 +429,9 @@ static INT32 SCX(INT32 x) #define ST_DrawTopLeftOverlayNum(x,y,n) V_DrawTallNum(x, y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, n) #define ST_DrawTopLeftOverlayPatch(x,y,p) V_DrawScaledPatch(x, y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, p) #define ST_DrawMappedOverlayPatch(x,y,p,c) V_DrawMappedScaledPatch(x, y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, p, c) -#define ST_DrawNumFromHud(h,n,f) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n) -#define ST_DrawPadNumFromHud(h,n,q,f) V_DrawPaddedTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n, q) -#define ST_DrawPatchFromHud(h,p,f) V_DrawScaledPatch(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, p) -#define ST_DrawNumFromHudWS(h,n,f) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n) -#define ST_DrawPadNumFromHudWS(h,n,q,f) V_DrawPaddedTallNum(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, n, q) -#define ST_DrawPatchFromHudWS(h,p,f) V_DrawScaledPatch(hudinfo[h].x, hudinfo[h].y, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|f, p) +#define ST_DrawNumFromHud(h,n,flags) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f|V_PERPLAYER|flags, n) +#define ST_DrawPadNumFromHud(h,n,q,flags) V_DrawPaddedTallNum(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f|V_PERPLAYER|flags, n, q) +#define ST_DrawPatchFromHud(h,p,flags) V_DrawScaledPatch(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f|V_PERPLAYER|flags, p) // Draw a number, scaled, over the view, maybe with set translucency // Always draw the number completely since it's overlay @@ -565,7 +564,7 @@ static void ST_drawTime(void) INT32 seconds, minutes, tictrn, tics; // TIME: - ST_DrawPatchFromHudWS(HUD_TIME, ((mapheaderinfo[gamemap-1]->countdown && countdowntimer < 11*TICRATE && leveltime/5 & 1) ? sboredtime : sbotime), V_HUDTRANS); + ST_DrawPatchFromHud(HUD_TIME, ((mapheaderinfo[gamemap-1]->countdown && countdowntimer < 11*TICRATE && leveltime/5 & 1) ? sboredtime : sbotime), V_HUDTRANS); if (objectplacing) { @@ -583,12 +582,12 @@ static void ST_drawTime(void) } if (cv_timetic.value == 1) // Tics only -- how simple is this? - ST_DrawNumFromHudWS(HUD_SECONDS, tics, V_HUDTRANS); + ST_DrawNumFromHud(HUD_SECONDS, tics, V_HUDTRANS); else { - ST_DrawNumFromHudWS(HUD_MINUTES, minutes, V_HUDTRANS); // Minutes - ST_DrawPatchFromHudWS(HUD_TIMECOLON, sbocolon, V_HUDTRANS); // Colon - ST_DrawPadNumFromHudWS(HUD_SECONDS, seconds, 2, V_HUDTRANS); // Seconds + ST_DrawNumFromHud(HUD_MINUTES, minutes, V_HUDTRANS); // Minutes + ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon, V_HUDTRANS); // Colon + ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2, V_HUDTRANS); // Seconds if (cv_timetic.value == 2 || cv_timetic.value == 3 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! { @@ -602,7 +601,7 @@ static inline void ST_drawRings(void) { INT32 ringnum; - ST_DrawPatchFromHudWS(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); + ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); if (objectplacing) ringnum = op_currentdoomednum; @@ -620,7 +619,7 @@ static inline void ST_drawRings(void) if (cv_timetic.value == 3) // Yes, even in modeattacking ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); else - ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); + ST_DrawNumFromHud(HUD_RINGSNUM, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); } static void ST_drawLivesArea(void) @@ -633,7 +632,7 @@ static void ST_drawLivesArea(void) // face background V_DrawSmallScaledPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, - V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, livesback); + hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, livesback); // face if (stplyr->spectator) @@ -641,7 +640,7 @@ static void ST_drawLivesArea(void) // spectator face UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, SKINCOLOR_CLOUDY, GTC_CACHE); V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, - V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANSHALF, faceprefix[stplyr->skin], colormap); + hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANSHALF, faceprefix[stplyr->skin], colormap); } else if (stplyr->mo && stplyr->mo->color) { @@ -651,7 +650,7 @@ static void ST_drawLivesArea(void) if (stplyr->powers[pw_super]) face = superprefix[stplyr->skin]; V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, - V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, face, colormap); + hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, face, colormap); if (cv_translucenthud.value == 10 && stplyr->powers[pw_super] == 1 && stplyr->mo->tracer) { INT32 v_supertrans = (stplyr->mo->tracer->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; @@ -660,7 +659,7 @@ static void ST_drawLivesArea(void) v_supertrans <<= V_ALPHASHIFT; colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->tracer->color, GTC_CACHE); V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, - V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|v_supertrans, face, colormap); + hudinfo[HUD_LIVES].f|V_PERPLAYER|v_supertrans, face, colormap); } } } @@ -669,7 +668,7 @@ static void ST_drawLivesArea(void) // skincolor face UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, - V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, faceprefix[stplyr->skin], colormap); + hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, faceprefix[stplyr->skin], colormap); } // Lives number @@ -677,7 +676,7 @@ static void ST_drawLivesArea(void) { // x V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10, - V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, stlivex); + hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, stlivex); // lives number if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) @@ -713,19 +712,19 @@ static void ST_drawLivesArea(void) if (livescount == 0x7f) V_DrawCharacter(hudinfo[HUD_LIVES].x+50, hudinfo[HUD_LIVES].y+8, - '\x16' | 0x80 | V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|V_HUDTRANS, false); + '\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false); else { if (livescount > 99) livescount = 99; V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, - V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), va("%d",livescount)); + hudinfo[HUD_LIVES].f|V_PERPLAYER|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), va("%d",livescount)); } } // Spectator else if (stplyr->spectator) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "SPECTATE"); + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "SPECTATE"); v_colmap = V_GRAYMAP; } // Tag @@ -733,17 +732,17 @@ static void ST_drawLivesArea(void) { if (stplyr->pflags & PF_TAGIT) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, (gametype == GT_HIDEANDSEEK) ? "SEEKER" : "IT!"); + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, (gametype == GT_HIDEANDSEEK) ? "SEEKER" : "IT!"); v_colmap = V_ORANGEMAP; } else if (stplyr->pflags & PF_GAMETYPEOVER) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANSHALF|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "FAILED"); + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANSHALF|hudinfo[HUD_LIVES].f|V_PERPLAYER, "FAILED"); v_colmap = V_GRAYMAP; } else { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, (gametype == GT_HIDEANDSEEK) ? "HIDER" : "RUNNER"); + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, (gametype == GT_HIDEANDSEEK) ? "HIDER" : "RUNNER"); v_colmap = V_GREENMAP; } } @@ -752,12 +751,12 @@ static void ST_drawLivesArea(void) { if (stplyr->ctfteam == 1) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "RED"); + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "RED"); v_colmap = V_REDMAP; } else if (stplyr->ctfteam == 2) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "BLUE"); + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "BLUE"); v_colmap = V_BLUEMAP; } else @@ -765,11 +764,11 @@ static void ST_drawLivesArea(void) } else { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, "PLAYING"); + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "PLAYING"); } // name - v_colmap |= (V_HUDTRANS|V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOBOTTOM); + v_colmap |= (V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER); if (strlen(skins[stplyr->skin].hudname) <= 5) V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); else if (V_ThinStringWidth(skins[stplyr->skin].hudname, v_colmap) <= 40) @@ -789,7 +788,7 @@ static void ST_drawLivesArea(void) { for (j = 0; j < 7; ++j) // "super" indicator { - V_DrawScaledPatch(workx, hudinfo[HUD_LIVES].y-9, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, emeraldpics[1][j]); + V_DrawScaledPatch(workx, hudinfo[HUD_LIVES].y-9, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, emeraldpics[1][j]); workx += 8; } } @@ -798,7 +797,7 @@ static void ST_drawLivesArea(void) for (j = 0; j < 7; ++j) // powerstones { if (stplyr->powers[pw_emeralds] & (1 << j)) - V_DrawScaledPatch(workx, hudinfo[HUD_LIVES].y-9, V_HUDTRANS|V_SNAPTOLEFT|V_PERPLAYER|V_SNAPTOBOTTOM, emeraldpics[1][j]); + V_DrawScaledPatch(workx, hudinfo[HUD_LIVES].y-9, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, emeraldpics[1][j]); workx += 8; } } @@ -817,23 +816,23 @@ static void ST_drawInput(void) y -= 16; // O backing - V_DrawFill(x, y-1, 16, 16, V_SNAPTOLEFT|V_SNAPTOBOTTOM|20); - V_DrawFill(x, y+15, 16, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_LIVES].f|20); + V_DrawFill(x, y+15, 16, 1, hudinfo[HUD_LIVES].f|29); if (cv_showinputjoy.value) // joystick render! { - /*V_DrawFill(x , y , 16, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); - V_DrawFill(x , y+15, 16, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); - V_DrawFill(x , y+ 1, 1, 14, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); - V_DrawFill(x+15, y+ 1, 1, 14, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); -- red's outline*/ + /*V_DrawFill(x , y , 16, 1, hudinfo[HUD_LIVES].f|16); + V_DrawFill(x , y+15, 16, 1, hudinfo[HUD_LIVES].f|16); + V_DrawFill(x , y+ 1, 1, 14, hudinfo[HUD_LIVES].f|16); + V_DrawFill(x+15, y+ 1, 1, 14, hudinfo[HUD_LIVES].f|16); -- red's outline*/ if (stplyr->cmd.sidemove || stplyr->cmd.forwardmove) { // joystick hole - V_DrawFill(x+5, y+4, 6, 6, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+5, y+4, 6, 6, hudinfo[HUD_LIVES].f|29); // joystick top V_DrawFill(x+3+stplyr->cmd.sidemove/12, y+2-stplyr->cmd.forwardmove/12, - 10, 10, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + 10, 10, hudinfo[HUD_LIVES].f|29); V_DrawFill(x+3+stplyr->cmd.sidemove/9, y+1-stplyr->cmd.forwardmove/9, 10, 10, accent); @@ -841,10 +840,10 @@ static void ST_drawInput(void) else { // just a limited, greyed out joystick top - V_DrawFill(x+3, y+11, 10, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + V_DrawFill(x+3, y+11, 10, 1, hudinfo[HUD_LIVES].f|29); V_DrawFill(x+3, y+1, - 10, 10, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); + 10, 10, hudinfo[HUD_LIVES].f|16); } } else // arrows! @@ -858,10 +857,10 @@ static void ST_drawInput(void) else { offs = 1; - col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; - V_DrawFill(x- 2, y+10, 6, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+ 4, y+ 9, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+ 5, y+ 8, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + col = hudinfo[HUD_LIVES].f|16; + V_DrawFill(x- 2, y+10, 6, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+ 4, y+ 9, 1, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+ 5, y+ 8, 1, 1, hudinfo[HUD_LIVES].f|29); } V_DrawFill(x- 2, y+ 5-offs, 6, 6, col); V_DrawFill(x+ 4, y+ 6-offs, 1, 4, col); @@ -876,12 +875,12 @@ static void ST_drawInput(void) else { offs = 1; - col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; - V_DrawFill(x+ 5, y+ 3, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+ 6, y+ 4, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+ 7, y+ 5, 2, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+ 9, y+ 4, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+10, y+ 3, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + col = hudinfo[HUD_LIVES].f|16; + V_DrawFill(x+ 5, y+ 3, 1, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+ 6, y+ 4, 1, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+ 7, y+ 5, 2, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+ 9, y+ 4, 1, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+10, y+ 3, 1, 1, hudinfo[HUD_LIVES].f|29); } V_DrawFill(x+ 5, y- 2-offs, 6, 6, col); V_DrawFill(x+ 6, y+ 4-offs, 4, 1, col); @@ -896,10 +895,10 @@ static void ST_drawInput(void) else { offs = 1; - col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; - V_DrawFill(x+12, y+10, 6, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+11, y+ 9, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); - V_DrawFill(x+10, y+ 8, 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + col = hudinfo[HUD_LIVES].f|16; + V_DrawFill(x+12, y+10, 6, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+11, y+ 9, 1, 1, hudinfo[HUD_LIVES].f|29); + V_DrawFill(x+10, y+ 8, 1, 1, hudinfo[HUD_LIVES].f|29); } V_DrawFill(x+12, y+ 5-offs, 6, 6, col); V_DrawFill(x+11, y+ 6-offs, 1, 4, col); @@ -914,8 +913,8 @@ static void ST_drawInput(void) else { offs = 1; - col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16; - V_DrawFill(x+ 5, y+17, 6, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29); + col = hudinfo[HUD_LIVES].f|16; + V_DrawFill(x+ 5, y+17, 6, 1, hudinfo[HUD_LIVES].f|29); } V_DrawFill(x+ 5, y+12-offs, 6, 6, col); V_DrawFill(x+ 6, y+11-offs, 4, 1, col); @@ -931,16 +930,16 @@ static void ST_drawInput(void) else\ {\ offs = 1;\ - col = V_SNAPTOLEFT|V_SNAPTOBOTTOM|16;\ - V_DrawFill(x+16+(xoffs), y+9+(yoffs), 10, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|29);\ + col = hudinfo[HUD_LIVES].f|16;\ + V_DrawFill(x+16+(xoffs), y+9+(yoffs), 10, 1, hudinfo[HUD_LIVES].f|29);\ }\ V_DrawFill(x+16+(xoffs), y+(yoffs)-offs, 10, 10, col);\ - V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, V_SNAPTOLEFT|V_SNAPTOBOTTOM|symb, false) + V_DrawCharacter(x+16+1+(xoffs), y+1+(yoffs)-offs, hudinfo[HUD_LIVES].f|symb, false) drawbutt( 4,-3, BT_JUMP, 'J'); drawbutt(15,-3, BT_USE, 'S'); - V_DrawFill(x+16+4, y+8, 21, 10, V_SNAPTOLEFT|V_SNAPTOBOTTOM|20); // sundial backing + V_DrawFill(x+16+4, y+8, 21, 10, hudinfo[HUD_LIVES].f|20); // sundial backing if (stplyr->mo) { UINT8 i, precision; @@ -960,7 +959,7 @@ static void ST_drawInput(void) { V_DrawFill(x+16+14-(i*xcomp)/precision, y+12-(i*ycomp)/precision, - 1, 1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|16); + 1, 1, hudinfo[HUD_LIVES].f|16); } if (ycomp <= 0) @@ -977,7 +976,7 @@ static void ST_drawInput(void) if (stplyr->pflags & PF_AUTOBRAKE) { V_DrawThinString(x, y, - V_SNAPTOLEFT|V_SNAPTOBOTTOM| + hudinfo[HUD_LIVES].f| ((!stplyr->powers[pw_carry] && (stplyr->pflags & PF_APPLYAUTOBRAKE) && !(stplyr->cmd.sidemove || stplyr->cmd.forwardmove) @@ -988,12 +987,12 @@ static void ST_drawInput(void) } if (stplyr->pflags & PF_ANALOGMODE) { - V_DrawThinString(x, y, V_SNAPTOLEFT|V_SNAPTOBOTTOM, "ANALOG"); + V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "ANALOG"); y -= 8; } } if (!demosynced) // should always be last, so it doesn't push anything else around - V_DrawThinString(x, y, V_SNAPTOLEFT|V_SNAPTOBOTTOM|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!"); + V_DrawThinString(x, y, hudinfo[HUD_LIVES].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!"); } static void ST_drawLevelTitle(void) @@ -1146,8 +1145,8 @@ static void ST_drawFirstPersonHUD(void) // Display the countdown drown numbers! if (p) - V_DrawScaledPatch(SCX((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset)), SCZ(60 - SHORT(p->topoffset)), - V_PERPLAYER|V_NOSCALESTART|V_PERPLAYER|V_OFFSET|V_TRANSLUCENT, p); + V_DrawScaledPatch((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset), + V_PERPLAYER|V_PERPLAYER|V_TRANSLUCENT, p); } static void ST_drawNightsRecords(void) @@ -1696,9 +1695,9 @@ static inline void ST_drawRaceHUD(void) if (circuitmap) { if (stplyr->exiting) - V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, V_YELLOWMAP, "FINISHED!"); + V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f|V_YELLOWMAP, "FINISHED!"); else - V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, 0, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); + V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); } } @@ -1800,7 +1799,14 @@ static void ST_drawCTFHUD(void) static void ST_drawSpecialStageHUD(void) { if (totalrings > 0) - ST_DrawNumFromHudWS(HUD_SS_TOTALRINGS, totalrings, V_HUDTRANS); + { + if (hudinfo[HUD_SS_TOTALRINGS].x) + ST_DrawNumFromHud(HUD_SS_TOTALRINGS, totalrings, V_HUDTRANS); + else if (cv_timetic.value == 3) + V_DrawTallNum(hudinfo[HUD_RINGSNUMTICS].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUMTICS].f|V_PERPLAYER|V_HUDTRANS, totalrings); + else + V_DrawTallNum(hudinfo[HUD_RINGSNUM].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUM].f|V_PERPLAYER|V_HUDTRANS, totalrings); + } if (leveltime < 5*TICRATE && totalrings > 0) { @@ -1810,7 +1816,7 @@ static void ST_drawSpecialStageHUD(void) if (sstimer) { - V_DrawString(hudinfo[HUD_TIMELEFT].x, hudinfo[HUD_TIMELEFT].y, V_PERPLAYER|V_HUDTRANS, M_GetText("TIME LEFT")); + V_DrawString(hudinfo[HUD_TIMELEFT].x, hudinfo[HUD_TIMELEFT].y, hudinfo[HUD_TIMELEFT].f|V_PERPLAYER|V_HUDTRANS, M_GetText("TIME LEFT")); ST_DrawNumFromHud(HUD_TIMELEFTNUM, sstimer/TICRATE, V_HUDTRANS); } else @@ -1853,7 +1859,7 @@ static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offse interval = 0; } - V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, V_PERPLAYER|V_HUDTRANS, patches[i]); + V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, hudinfo[HUD_HUNTPICS].f|V_PERPLAYER|V_HUDTRANS, patches[i]); return interval; } @@ -2059,7 +2065,7 @@ static void ST_overlayDrawer(void) ST_doHuntIconsAndSound(); if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1)) - V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, hudinfo[HUD_GRAVBOOTSICO].y, V_PERPLAYER|V_SNAPTORIGHT, gravboots); + V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, hudinfo[HUD_GRAVBOOTSICO].y, hudinfo[HUD_GRAVBOOTSICO].f|V_PERPLAYER, gravboots); if(!P_IsLocalPlayer(stplyr)) { diff --git a/src/st_stuff.h b/src/st_stuff.h index 2294c35e4..50937907f 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -72,7 +72,7 @@ extern patch_t *ngradeletters[7]; */ typedef struct { - INT32 x, y; + INT32 x, y, f; } hudinfo_t; typedef enum diff --git a/src/y_inter.c b/src/y_inter.c index 063268626..7ac28018b 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -161,9 +161,9 @@ static void Y_FollowIntermission(void); static void Y_UnloadData(void); // Stuff copy+pasted from st_stuff.c -#define ST_DrawNumFromHud(h,n) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, V_SNAPTOTOP|V_SNAPTOLEFT, n) -#define ST_DrawPadNumFromHud(h,n,q) V_DrawPaddedTallNum(hudinfo[h].x, hudinfo[h].y, V_SNAPTOTOP|V_SNAPTOLEFT, n, q) -#define ST_DrawPatchFromHud(h,p) V_DrawScaledPatch(hudinfo[h].x, hudinfo[h].y, V_SNAPTOTOP|V_SNAPTOLEFT, p) +#define ST_DrawNumFromHud(h,n) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f, n) +#define ST_DrawPadNumFromHud(h,n,q) V_DrawPaddedTallNum(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f, n, q) +#define ST_DrawPatchFromHud(h,p) V_DrawScaledPatch(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f, p) static void Y_IntermissionTokenDrawer(void) { From ae033a940911e15bd1c3bdae759f8b485550bb3a Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 20 Mar 2018 00:19:20 +0000 Subject: [PATCH 066/212] * Clean up a lot of NiGHTS stuff still using the old, shitty NOSCALESTART offsetting in nonstandard resolutions. * Clean up the ST_ drawing macro list. --- src/st_stuff.c | 70 +++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 4f7c8fc28..168c98724 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -410,25 +410,10 @@ void ST_changeDemoView(void) boolean st_overlay; -static INT32 SCZ(INT32 z) -{ - return FixedInt(FixedMul(z<bumpertime) - V_DrawString(SCX(locx), SCZ(locy - 8), V_NOSCALESTART|V_REDMAP|V_MONOSPACE, va("BUMPER: 0.%02d", G_TicsToCentiseconds(stplyr->bumpertime))); + V_DrawString(locx, locy - 8, V_REDMAP|V_MONOSPACE, va("BUMPER: 0.%02d", G_TicsToCentiseconds(stplyr->bumpertime))); else - V_DrawString(SCX(locx), SCZ(locy - 8), V_NOSCALESTART|V_MONOSPACE, va("Drill: %3d%%", (stplyr->drillmeter*100)/(96*20))); + V_DrawString(locx, locy - 8, V_MONOSPACE, va("Drill: %3d%%", (stplyr->drillmeter*100)/(96*20))); } } @@ -1416,10 +1401,10 @@ static void ST_drawNiGHTSHUD(void) for (r = 0; r < 5; r++) { - ST_DrawUnscaledOverlayPatch(SCX(230 - (7*r)), SCZ(144), redstat); - ST_DrawUnscaledOverlayPatch(SCX(188 - (7*r)), SCZ(144), orngstat); - ST_DrawUnscaledOverlayPatch(SCX(146 - (7*r)), SCZ(144), yelstat); - ST_DrawUnscaledOverlayPatch(SCX(104 - (7*r)), SCZ(144), byelstat); + V_DrawScaledPatch(230 - (7*r), 144, V_PERPLAYER|V_HUDTRANS, redstat); + V_DrawScaledPatch(188 - (7*r), 144, V_PERPLAYER|V_HUDTRANS, orngstat); + V_DrawScaledPatch(146 - (7*r), 144, V_PERPLAYER|V_HUDTRANS, yelstat); + V_DrawScaledPatch(104 - (7*r), 144, V_PERPLAYER|V_HUDTRANS, byelstat); } amount = (origamount - stplyr->capsule->health); @@ -1438,7 +1423,7 @@ static void ST_drawNiGHTSHUD(void) if (r > 10) ++t; if (r > 5) ++t; - ST_DrawUnscaledOverlayPatch(SCX(69 + (7*t)), SCZ(144), bluestat); + V_DrawScaledPatch(69 + (7*t), 144, V_PERPLAYER|V_HUDTRANS, bluestat); } } } @@ -1465,9 +1450,9 @@ static void ST_drawNiGHTSHUD(void) ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]); if (total_ringcount >= 100) - ST_DrawTopLeftOverlayNum((total_ringcount >= 1000) ? 76 : 72, 8 + 11, total_ringcount); + V_DrawTallNum((total_ringcount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_ringcount); else - ST_DrawTopLeftOverlayNum(68, 8 + 11, total_ringcount); + V_DrawTallNum(68, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_ringcount); #ifdef HAVE_BLUA } #endif @@ -1490,22 +1475,21 @@ static void ST_drawNiGHTSHUD(void) if (modeattacking == ATTACKING_NIGHTS) { INT32 maretime = max(stplyr->realtime - stplyr->marebegunat, 0); - fixed_t cornerx = vid.width, cornery = vid.height-SCZ(20); -#define ASSISHHUDFIX(n) (n*vid.dupx) - ST_DrawUnscaledOverlayPatch(cornerx-ASSISHHUDFIX(22), cornery, W_CachePatchName("NGRTIMER", PU_HUDGFX)); - ST_DrawUnscaledPaddedOverlayNum(cornerx-ASSISHHUDFIX(22), cornery, G_TicsToCentiseconds(maretime), 2); - ST_DrawUnscaledOverlayPatch(cornerx-ASSISHHUDFIX(46), cornery, sboperiod); +#define VFLAGS V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_PERPLAYER|V_HUDTRANS + V_DrawScaledPatch(BASEVIDWIDTH-22, BASEVIDHEIGHT-20, VFLAGS, W_CachePatchName("NGRTIMER", PU_HUDGFX)); + V_DrawPaddedTallNum(BASEVIDWIDTH-22, BASEVIDHEIGHT-20, VFLAGS, G_TicsToCentiseconds(maretime), 2); + V_DrawScaledPatch(BASEVIDWIDTH-46, BASEVIDHEIGHT-20, VFLAGS, sboperiod); if (maretime < 60*TICRATE) - ST_DrawUnscaledOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime)); + V_DrawTallNum(BASEVIDWIDTH-46, BASEVIDHEIGHT-20, VFLAGS, G_TicsToSeconds(maretime)); else { - ST_DrawUnscaledPaddedOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime), 2); - ST_DrawUnscaledOverlayPatch(cornerx-ASSISHHUDFIX(70), cornery, sbocolon); - ST_DrawUnscaledOverlayNum(cornerx-ASSISHHUDFIX(70), cornery, G_TicsToMinutes(maretime, true)); + V_DrawPaddedTallNum(BASEVIDWIDTH-46, BASEVIDHEIGHT-20, VFLAGS, G_TicsToSeconds(maretime), 2); + V_DrawScaledPatch(BASEVIDWIDTH-70, BASEVIDHEIGHT-20, VFLAGS, sbocolon); + V_DrawTallNum(BASEVIDWIDTH-70, BASEVIDHEIGHT-20, VFLAGS, G_TicsToMinutes(maretime, true)); } +#undef VFLAGS } -#undef ASSISHHUDFIX } // Ideya time remaining @@ -1534,10 +1518,10 @@ static void ST_drawNiGHTSHUD(void) if (flashingLeft < TICRATE/2) // Start fading out { UINT32 fadingFlag = (9 - 9*flashingLeft/(TICRATE/2)) << V_ALPHASHIFT; - V_DrawTranslucentPatch(SCX(160 - (minus5sec->width/2)), SCZ(28), V_NOSCALESTART|V_PERPLAYER|fadingFlag, minus5sec); + V_DrawTranslucentPatch(160 - (minus5sec->width/2), 28, V_PERPLAYER|fadingFlag, minus5sec); } else - V_DrawScaledPatch(SCX(160 - (minus5sec->width/2)), SCZ(28), V_NOSCALESTART|V_PERPLAYER, minus5sec); + V_DrawScaledPatch(160 - (minus5sec->width/2), 28, V_PERPLAYER, minus5sec); } if (realnightstime < 10) @@ -1563,22 +1547,22 @@ static void ST_drawNiGHTSHUD(void) if (stplyr->powers[pw_nights_superloop]) { pwr = stplyr->powers[pw_nights_superloop]; - V_DrawSmallScaledPatch(SCX(110), SCZ(44), V_NOSCALESTART, W_CachePatchName("NPRUA0",PU_CACHE)); - V_DrawThinString(SCX(106), SCZ(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_CACHE)); + V_DrawThinString(106, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_helper]) { pwr = stplyr->powers[pw_nights_helper]; - V_DrawSmallScaledPatch(SCX(150), SCZ(44), V_NOSCALESTART, W_CachePatchName("NPRUC0",PU_CACHE)); - V_DrawThinString(SCX(146), SCZ(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_CACHE)); + V_DrawThinString(146, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_linkfreeze]) { pwr = stplyr->powers[pw_nights_linkfreeze]; - V_DrawSmallScaledPatch(SCX(190), SCZ(44), V_NOSCALESTART, W_CachePatchName("NPRUE0",PU_CACHE)); - V_DrawThinString(SCX(186), SCZ(52), V_NOSCALESTART|V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_CACHE)); + V_DrawThinString(186, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } } @@ -1689,7 +1673,7 @@ static inline void ST_drawRaceHUD(void) if (!(P_AutoPause() || paused) && !bounce) S_StartSound(0, ((racenum == racego) ? sfx_s3kad : sfx_s3ka7)); } - V_DrawScaledPatch(SCX((BASEVIDWIDTH - SHORT(racenum->width))/2), (INT32)(SCZ(height)), V_NOSCALESTART|V_PERPLAYER, racenum); + V_DrawScaledPatch(((BASEVIDWIDTH - SHORT(racenum->width))/2), height, V_PERPLAYER, racenum); } if (circuitmap) From 4e95066f5ac700bd868c140c90394bd94a9c2fad Mon Sep 17 00:00:00 2001 From: Sryder Date: Tue, 20 Mar 2018 14:20:02 +0000 Subject: [PATCH 067/212] Some fixes and updates for HWR_SplitWall Solid walls *can* be cut Fix issues with water and fog FOFs not cutting each other out correctly Fix Fog colourmap and lighting setting that is done here. Remove HWR_SplitFog There is currently a bug with FF_DOUBLESHADOW (that also exists in software) but has a larger impact here. When 2 FF_DOUBLESHADOW lights are directly stacked on each other the bottom one has its height set incorrectly. This causes all the Fog in the timed gravity flipping section of ERZ2 to be drawn and it looks really bad. --- src/hardware/hw_main.c | 246 +++++++++++++---------------------------- 1 file changed, 76 insertions(+), 170 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 83783072f..c4e3d879e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1065,7 +1065,7 @@ static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2) // // HWR_SplitWall // -static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, FSurfaceInfo* Surf, UINT32 cutflag) +static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, FSurfaceInfo* Surf, UINT32 cutflag, ffloor_t *pfloor) { /* SoM: split up and light walls according to the lightlist. This may also include leaving out parts @@ -1093,7 +1093,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, lightlist_t * list = sector->lightlist; const UINT8 alpha = Surf->FlatColor.s.alpha; FUINT lightnum; - extracolormap_t *colormap; + extracolormap_t *colormap = NULL; realtop = top = wallVerts[3].y; realbot = bot = wallVerts[0].y; @@ -1109,7 +1109,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, endpegmul = (endpegb - endpegt) / (endtop - endbot); #endif - for (i = 1; i < sector->numlights; i++) + for (i = 0; i < sector->numlights; i++) { #ifdef ESLOPE if (endtop < endrealbot) @@ -1117,35 +1117,38 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, if (top < realbot) return; - //Hurdler: fix a crashing bug, but is it correct? -// if (!list[i].caster) -// continue; + // There's a compiler warning here if this comment isn't here because of indentation + if (!(list[i].flags & FF_NOSHADE)) + { + if (pfloor && (pfloor->flags & FF_FOG)) + { + lightnum = pfloor->master->frontsector->lightlevel; + colormap = pfloor->master->frontsector->extra_colormap; + } + else + { + lightnum = *list[i].lightlevel; + colormap = list[i].extra_colormap; + } + } solid = false; - if (list[i].caster) + if ((sector->lightlist[i].flags & FF_CUTSOLIDS) && !(cutflag & FF_EXTRA)) + solid = true; + else if ((sector->lightlist[i].flags & FF_CUTEXTRA) && (cutflag & FF_EXTRA)) { - if (sector->lightlist[i].caster->flags & FF_CUTSOLIDS && !(cutflag & FF_EXTRA)) - solid = true; - else if (sector->lightlist[i].caster->flags & FF_CUTEXTRA && cutflag & FF_EXTRA) + if (sector->lightlist[i].flags & FF_EXTRA) { - if (sector->lightlist[i].caster->flags & FF_EXTRA) - { - if (sector->lightlist[i].caster->flags == cutflag) // Only merge with your own types - solid = true; - } - else + if ((sector->lightlist[i].flags & (FF_FOG|FF_SWIMMABLE)) == (cutflag & (FF_FOG|FF_SWIMMABLE))) // Only merge with your own types solid = true; } else - solid = false; + solid = true; } else solid = false; - if (cutflag == FF_CUTSOLIDS) // These are regular walls sent in from StoreWallRange, they shouldn't be cut from this - solid = false; - #ifdef ESLOPE if (list[i].slope) { @@ -1185,34 +1188,53 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, if (solid && endtop > endbheight) endtop = endbheight; #endif - continue; } +#ifdef ESLOPE + if (i + 1 < sector->numlights) + { + if (list[i+1].slope) + { + temp = P_GetZAt(list[i+1].slope, v1x, v1y); + bheight = FIXED_TO_FLOAT(temp); + temp = P_GetZAt(list[i+1].slope, v2x, v2y); + endbheight = FIXED_TO_FLOAT(temp); + } + else + bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height); + } + else + { + bheight = realbot; + endbheight = endrealbot; + } +#else + if (i + 1 < sector->numlights) + { + bheight = FIXED_TO_FLOAT(list[i+1].height); + } + else + { + bheight = realbot; + } +#endif + + if (endbheight >= endtop) + if (bheight >= top) + continue; + //Found a break; - bot = height; + bot = bheight; if (bot < realbot) bot = realbot; #ifdef ESLOPE - endbot = endheight; + endbot = endbheight; if (endbot < endrealbot) endbot = endrealbot; #endif - - // colormap test - if (list[i-1].caster) - { - lightnum = *list[i-1].lightlevel; - colormap = list[i-1].extra_colormap; - } - else - { - lightnum = sector->lightlevel; - colormap = sector->extra_colormap; - } - Surf->FlatColor.s.alpha = alpha; #ifdef ESLOPE @@ -1235,20 +1257,16 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[0].y = wallVerts[1].y = bot; #endif - if (cutflag & FF_TRANSLUCENT) + if (cutflag & FF_FOG) + HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap); + else if (cutflag & FF_TRANSLUCENT) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap); - if (solid) - top = bheight; - else - top = height; + top = bot; #ifdef ESLOPE - if (solid) - endtop = endbheight; - else - endtop = endheight; + endtop = endbot; #endif } @@ -1260,17 +1278,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, if (top <= realbot) return; - if (list[i-1].caster) - { - lightnum = *list[i-1].lightlevel; - colormap = list[i-1].extra_colormap; - } - else - { - lightnum = sector->lightlevel; - colormap = sector->extra_colormap; - } - Surf->FlatColor.s.alpha = alpha; + Surf->FlatColor.s.alpha = alpha; #ifdef ESLOPE wallVerts[3].t = pegt + ((realtop - top) * pegmul); @@ -1292,116 +1300,14 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, wallVerts[0].y = wallVerts[1].y = bot; #endif - if (cutflag & FF_TRANSLUCENT) + if (cutflag & FF_FOG) + HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap); + else if (cutflag & FF_TRANSLUCENT) HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap); } -// -// HWR_SplitFog -// Exclusively for fog -// -static void HWR_SplitFog(sector_t *sector, wallVert3D *wallVerts, FSurfaceInfo* Surf, UINT32 cutflag, FUINT lightnum, extracolormap_t *colormap) -{ - /* SoM: split up and light walls according to the - lightlist. This may also include leaving out parts - of the wall that can't be seen */ - float realtop, realbot, top, bot; - float pegt, pegb, pegmul; - float height = 0.0f, bheight = 0.0f; - INT32 solid, i; - lightlist_t * list = sector->lightlist; - const UINT8 alpha = Surf->FlatColor.s.alpha; - - realtop = top = wallVerts[2].y; - realbot = bot = wallVerts[0].y; - pegt = wallVerts[2].t; - pegb = wallVerts[0].t; - pegmul = (pegb - pegt) / (top - bot); - - for (i = 1; i < sector->numlights; i++) - { - if (top < realbot) - return; - - //Hurdler: fix a crashing bug, but is it correct? -// if (!list[i].caster) -// continue; - - solid = false; - - if (list[i].caster) - { - if (sector->lightlist[i].caster->flags & FF_FOG && cutflag & FF_FOG) // Only fog cuts fog - { - if (sector->lightlist[i].caster->flags & FF_EXTRA) - { - if (sector->lightlist[i].caster->flags == cutflag) // only cut by the same - solid = true; - } - else - solid = true; - } - } - - height = FIXED_TO_FLOAT(list[i].height); - - if (solid) - bheight = FIXED_TO_FLOAT(*list[i].caster->bottomheight); - - if (height >= top) - { - if (solid && top > bheight) - top = bheight; - continue; - } - - //Found a break; - bot = height; - - if (bot < realbot) - bot = realbot; - - { - - - - Surf->FlatColor.s.alpha = alpha; - } - - wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul); - wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul); - - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = top; - wallVerts[0].y = wallVerts[1].y = bot; - - if (!solid) // Don't draw it if there's more fog behind it - HWR_AddTransparentWall(wallVerts, Surf, 0, PF_Fog|PF_NoTexture, true, lightnum, colormap); - - top = height; - } - - bot = realbot; - if (top <= realbot) - return; - - { - - Surf->FlatColor.s.alpha = alpha; - } - - wallVerts[3].t = wallVerts[2].t = pegt + ((realtop - top) * pegmul); - wallVerts[0].t = wallVerts[1].t = pegt + ((realtop - bot) * pegmul); - - // set top/bottom coords - wallVerts[2].y = wallVerts[3].y = top; - wallVerts[0].y = wallVerts[1].y = bot; - - HWR_AddTransparentWall(wallVerts, Surf, 0, PF_Translucent|PF_NoTexture, true, lightnum, colormap); -} - // HWR_DrawSkyWalls // Draw walls into the depth buffer so that anything behind is culled properly static void HWR_DrawSkyWall(wallVert3D *wallVerts, FSurfaceInfo *Surf, fixed_t bottom, fixed_t top) @@ -1678,7 +1584,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) #endif if (gr_frontsector->numlights) - HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS); + HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTLEVEL, NULL); else if (grTex->mipmap.flags & TF_TRANSPARENT) HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap); else @@ -1761,7 +1667,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) #endif if (gr_frontsector->numlights) - HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS); + HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTLEVEL, NULL); else if (grTex->mipmap.flags & TF_TRANSPARENT) HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap); else @@ -2027,10 +1933,10 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) if (gr_frontsector->numlights) { if (!(blendmode & PF_Masked)) - HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_TRANSLUCENT); + HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_TRANSLUCENT, NULL); else { - HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS); + HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL); } } else if (!(blendmode & PF_Masked)) @@ -2182,7 +2088,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) #endif // I don't think that solid walls can use translucent linedef types... if (gr_frontsector->numlights) - HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTSOLIDS); + HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, &Surf, FF_CUTLEVEL, NULL); else { if (grTex->mipmap.flags & TF_TRANSPARENT) @@ -2320,7 +2226,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } if (gr_frontsector->numlights) - HWR_SplitFog(gr_frontsector, wallVerts, &Surf, rover->flags, lightnum, colormap); + HWR_SplitWall(gr_frontsector, wallVerts, 0, &Surf, rover->flags, rover); else HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap); } @@ -2335,7 +2241,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } if (gr_frontsector->numlights) - HWR_SplitWall(gr_frontsector, wallVerts, texnum, &Surf, rover->flags); + HWR_SplitWall(gr_frontsector, wallVerts, texnum, &Surf, rover->flags, rover); else { if (blendmode != PF_Masked) @@ -2439,7 +2345,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } if (gr_backsector->numlights) - HWR_SplitFog(gr_backsector, wallVerts, &Surf, rover->flags, lightnum, colormap); + HWR_SplitWall(gr_backsector, wallVerts, 0, &Surf, rover->flags, rover); else HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap); } @@ -2454,7 +2360,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } if (gr_backsector->numlights) - HWR_SplitWall(gr_backsector, wallVerts, texnum, &Surf, rover->flags); + HWR_SplitWall(gr_backsector, wallVerts, texnum, &Surf, rover->flags, rover); else { if (blendmode != PF_Masked) From 05bf3674d3a34b868b215e78bb6c1b709d10ff45 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 20 Mar 2018 15:00:27 +0000 Subject: [PATCH 068/212] * M_Random function access to v! (so v.RandomFixed(), etc...) * Remove deprecated P_Random() from Lua. --- src/lua_baselib.c | 11 +------ src/lua_hudlib.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9d65a5832..ed29acc33 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -214,15 +214,7 @@ static int lib_pRandomRange(lua_State *L) return 1; } -// Deprecated, macros, etc. -static int lib_pRandom(lua_State *L) -{ - NOHUD - LUA_Deprecated(L, "P_Random", "P_RandomByte"); - lua_pushinteger(L, P_RandomByte()); - return 1; -} - +// Macros. static int lib_pSignedRandom(lua_State *L) { NOHUD @@ -2481,7 +2473,6 @@ static luaL_Reg lib[] = { {"P_RandomByte",lib_pRandomByte}, {"P_RandomKey",lib_pRandomKey}, {"P_RandomRange",lib_pRandomRange}, - {"P_Random",lib_pRandom}, // DEPRECATED {"P_SignedRandom",lib_pSignedRandom}, // MACRO {"P_RandomChance",lib_pRandomChance}, // MACRO diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index a709ba9f4..afc81c37d 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -20,6 +20,7 @@ #include "i_video.h" // rendermode #include "p_local.h" // camera_t #include "screen.h" // screen width/height +#include "m_random.h" // m_random #include "v_video.h" #include "w_wad.h" #include "z_zone.h" @@ -752,20 +753,92 @@ static int libd_renderer(lua_State *L) return 1; } +// M_RANDOM +////////////// + +static int libd_RandomFixed(lua_State *L) +{ + HUDONLY + lua_pushfixed(L, M_RandomFixed()); + return 1; +} + +static int libd_RandomByte(lua_State *L) +{ + HUDONLY + lua_pushinteger(L, M_RandomByte()); + return 1; +} + +static int libd_RandomKey(lua_State *L) +{ + INT32 a = (INT32)luaL_checkinteger(L, 1); + + HUDONLY + if (a > 65536) + LUA_UsageWarning(L, "v.RandomKey: range > 65536 is undefined behavior"); + lua_pushinteger(L, M_RandomKey(a)); + return 1; +} + +static int libd_RandomRange(lua_State *L) +{ + INT32 a = (INT32)luaL_checkinteger(L, 1); + INT32 b = (INT32)luaL_checkinteger(L, 2); + + HUDONLY + if (b < a) { + INT32 c = a; + a = b; + b = c; + } + if ((b-a+1) > 65536) + LUA_UsageWarning(L, "v.RandomRange: range > 65536 is undefined behavior"); + lua_pushinteger(L, M_RandomRange(a, b)); + return 1; +} + +// Macros. +static int libd_SignedRandom(lua_State *L) +{ + HUDONLY + lua_pushinteger(L, M_SignedRandom()); + return 1; +} + +static int libd_RandomChance(lua_State *L) +{ + fixed_t p = luaL_checkfixed(L, 1); + HUDONLY + lua_pushboolean(L, M_RandomChance(p)); + return 1; +} + static luaL_Reg lib_draw[] = { + // cache {"patchExists", libd_patchExists}, {"cachePatch", libd_cachePatch}, {"getSpritePatch", libd_getSpritePatch}, {"getSprite2Patch", libd_getSprite2Patch}, + {"getColormap", libd_getColormap}, + // drawing {"draw", libd_draw}, {"drawScaled", libd_drawScaled}, {"drawNum", libd_drawNum}, {"drawPaddedNum", libd_drawPaddedNum}, {"drawFill", libd_drawFill}, {"drawString", libd_drawString}, - {"stringWidth", libd_stringWidth}, - {"getColormap", libd_getColormap}, {"fadeScreen", libd_fadeScreen}, + // misc + {"stringWidth", libd_stringWidth}, + // m_random + {"RandomFixed",libd_RandomFixed}, + {"RandomByte",libd_RandomByte}, + {"RandomKey",libd_RandomKey}, + {"RandomRange",libd_RandomRange}, + {"SignedRandom",libd_SignedRandom}, // MACRO + {"RandomChance",libd_RandomChance}, // MACRO + // properties {"width", libd_width}, {"height", libd_height}, {"dupx", libd_dupx}, From 24c017564e603575cf8dc59923df45d7390a848d Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 21 Mar 2018 18:18:45 +0000 Subject: [PATCH 069/212] Mammoth commit! * Make TIME part of HUD count down in a bunch of circumstances where it was otherwise some other seperate thing. * Make race countdown happen in a bunch of appropriate circumstances. * Refactor race countdown. * Remove a lot of useless stuff from H&S/Tag UI. * Make co-op/competition/race end-of-act countdown use the race countdown and bigger HUD font. * Remove useless PLAYING/SPECTATE text from lives element. * Merge lap counter into lives element. * Move some other text around. --- src/hu_stuff.c | 16 +--- src/m_menu.c | 8 +- src/p_user.c | 4 +- src/screen.c | 11 +-- src/st_stuff.c | 238 ++++++++++++++++++++++++++++--------------------- src/st_stuff.h | 1 - 6 files changed, 152 insertions(+), 126 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7af7aa768..58db7961b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1591,20 +1591,8 @@ static void HU_DrawRankings(void) { if (cv_timelimit.value && timelimitintics > 0) { - INT32 timeval = (timelimitintics+1-leveltime)/TICRATE; - - if (leveltime <= timelimitintics) - { - V_DrawCenteredString(64, 8, 0, "TIME LEFT"); - V_DrawCenteredString(64, 16, 0, va("%u", timeval)); - } - - // overtime - if ((leveltime > (timelimitintics + TICRATE/2)) && cv_overtime.value) - { - V_DrawCenteredString(64, 8, 0, "TIME LEFT"); - V_DrawCenteredString(64, 16, 0, "OVERTIME"); - } + V_DrawCenteredString(64, 8, 0, "TIME"); + V_DrawCenteredString(64, 16, 0, va("%i:%02i", G_TicsToMinutes(stplyr->realtime, true), G_TicsToSeconds(stplyr->realtime))); } if (cv_pointlimit.value > 0) diff --git a/src/m_menu.c b/src/m_menu.c index 24beff317..e53d9012f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5682,7 +5682,7 @@ static void M_DrawChecklist(void) beat = va("Get %d points in %s", cond[condnum].requirement, level); break; case UC_MAPTIME: - beat = va("Beat %s in %d:%d.%d", level, + beat = va("Beat %s in %d:%02d.%02d", level, G_TicsToMinutes(cond[condnum].requirement, true), G_TicsToSeconds(cond[condnum].requirement), G_TicsToCentiseconds(cond[condnum].requirement)); @@ -5707,7 +5707,7 @@ static void M_DrawChecklist(void) beat = va("Get %d points over all maps", cond[condnum].requirement); break; case UC_OVERALLTIME: - beat = va("Get a total time of less than %d:%d.%d", + beat = va("Get a total time of less than %d:%02d.%02d", G_TicsToMinutes(cond[condnum].requirement, true), G_TicsToSeconds(cond[condnum].requirement), G_TicsToCentiseconds(cond[condnum].requirement)); @@ -5755,12 +5755,12 @@ static void M_DrawChecklist(void) break; case UC_NIGHTSTIME: if (cond[condnum].extrainfo2) - beat = va("Beat %s, mare %d in %d:%d.%d", level, cond[condnum].extrainfo2, + beat = va("Beat %s, mare %d in %d:%02d.%02d", level, cond[condnum].extrainfo2, G_TicsToMinutes(cond[condnum].requirement, true), G_TicsToSeconds(cond[condnum].requirement), G_TicsToCentiseconds(cond[condnum].requirement)); else - beat = va("Beat %s in %d:%d.%d", + beat = va("Beat %s in %d:%02d.%02d", level, G_TicsToMinutes(cond[condnum].requirement, true), G_TicsToSeconds(cond[condnum].requirement), diff --git a/src/p_user.c b/src/p_user.c index f422e9b65..d127e7139 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1725,7 +1725,7 @@ void P_DoPlayerExit(player_t *player) else if (gametype == GT_RACE || gametype == GT_COMPETITION) // If in Race Mode, allow { if (!countdown) // a 60-second wait ala Sonic 2. - countdown = cv_countdowntime.value*TICRATE + 1; // Use cv_countdowntime + countdown = (cv_countdowntime.value - 1)*TICRATE + 1; // Use cv_countdowntime player->exiting = 3*TICRATE; @@ -9538,7 +9538,7 @@ void P_PlayerThink(player_t *player) if (i == MAXPLAYERS && player->exiting == 3*TICRATE) // finished player->exiting = (14*TICRATE)/5 + 1; - // If 10 seconds are left on the timer, + // If 11 seconds are left on the timer, // begin the drown music for countdown! if (countdown == 11*TICRATE - 1) { diff --git a/src/screen.c b/src/screen.c index 28765785b..5120aa581 100644 --- a/src/screen.c +++ b/src/screen.c @@ -455,9 +455,8 @@ void SCR_ClosedCaptions(void) if (music && !gamestopped && (closedcaptions[i].t < flashingtics) && (closedcaptions[i].t & 1)) continue; - flags = V_NOSCALESTART|V_ALLOWLOWERCASE; - y = vid.height-((i + 2)*10*vid.dupy); - dot = ' '; + flags = V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_ALLOWLOWERCASE; + y = BASEVIDHEIGHT-((i + 2)*10); if (closedcaptions[i].b) y -= (closedcaptions[i].b--)*vid.dupy; @@ -469,8 +468,10 @@ void SCR_ClosedCaptions(void) dot = '\x19'; else if (closedcaptions[i].c && closedcaptions[i].c->origin) dot = '\x1E'; + else + dot = ' '; - V_DrawRightAlignedString(vid.width-(20*vid.dupx), y, - flags, va("%c [%s]", dot, (closedcaptions[i].s->caption[0] ? closedcaptions[i].s->caption : closedcaptions[i].s->name))); + V_DrawRightAlignedString(BASEVIDWIDTH - 20, y, flags, + va("%c [%s]", dot, (closedcaptions[i].s->caption[0] ? closedcaptions[i].s->caption : closedcaptions[i].s->name))); } } diff --git a/src/st_stuff.c b/src/st_stuff.c index 168c98724..b9005ab68 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -151,8 +151,6 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 152, 168, 0}, // HUD_HUNTPICS { 152, 24, V_SNAPTORIGHT}, // HUD_GRAVBOOTSICO - - { 240, 160, V_SNAPTOBOTTOM|V_SNAPTORIGHT}, // HUD_LAP }; // @@ -541,15 +539,46 @@ static void ST_drawScore(void) ST_DrawNumFromHud(HUD_SCORENUM, op_displayflags, V_HUDTRANS); } else - ST_DrawNumFromHud(HUD_SCORENUM, stplyr->score,V_HUDTRANS); + ST_DrawNumFromHud(HUD_SCORENUM, stplyr->score, V_HUDTRANS); +} + +static void ST_drawRaceNum(INT32 time) +{ + INT32 height, bounce; + patch_t *racenum; + + time += TICRATE; + height = ((3*BASEVIDHEIGHT)>>2) - 8; + bounce = TICRATE - (1 + (time % TICRATE)); + + switch (time/TICRATE) + { + case 3: + racenum = race3; + break; + case 2: + racenum = race2; + break; + case 1: + racenum = race1; + break; + default: + racenum = racego; + break; + } + if (bounce < 3) + { + height -= (2 - bounce); + if (!(P_AutoPause() || paused) && !bounce) + S_StartSound(0, ((racenum == racego) ? sfx_s3kad : sfx_s3ka7)); + } + V_DrawScaledPatch(((BASEVIDWIDTH - SHORT(racenum->width))/2), height, V_PERPLAYER, racenum); } static void ST_drawTime(void) { INT32 seconds, minutes, tictrn, tics; - - // TIME: - ST_DrawPatchFromHud(HUD_TIME, ((mapheaderinfo[gamemap-1]->countdown && countdowntimer < 11*TICRATE && leveltime/5 & 1) ? sboredtime : sbotime), V_HUDTRANS); + boolean downwards = false; if (objectplacing) { @@ -560,12 +589,61 @@ static void ST_drawTime(void) } else { - tics = (mapheaderinfo[gamemap-1]->countdown ? countdowntimer : stplyr->realtime); - seconds = G_TicsToSeconds(tics); + // Counting down the hidetime? + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (leveltime <= (hidetime*TICRATE))) + { + tics = (hidetime*TICRATE - leveltime); + if (tics < 3*TICRATE) + ST_drawRaceNum(tics); + downwards = true; + } + else + { + // Hidetime finish! + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (leveltime < ((hidetime+1)*TICRATE))) + ST_drawRaceNum(hidetime*TICRATE - leveltime); + + // Time limit? + if (gametype != GT_RACE && gametype != GT_COMPETITION && gametype != GT_COOP && cv_timelimit.value && timelimitintics > 0) + { + if (timelimitintics >= leveltime) + { + tics = (timelimitintics - leveltime); + if (tics < 3*TICRATE) + ST_drawRaceNum(tics); + } + else // Overtime! + tics = 0; + downwards = true; + } + // Post-hidetime normal. + else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + tics = stplyr->realtime - hidetime*TICRATE; + // "Shadow! What are you doing? Hurry and get back here + // right now before the island blows up with you on it!" + // "Blows up??" *awkward silence* "I've got to get outta + // here and find Amy and Tails right away!" + else if (mapheaderinfo[gamemap-1]->countdown) + { + tics = countdowntimer; + downwards = true; + } + // Normal. + else + tics = stplyr->realtime; + } + minutes = G_TicsToMinutes(tics, true); + seconds = G_TicsToSeconds(tics); tictrn = G_TicsToCentiseconds(tics); } + // TIME: + ST_DrawPatchFromHud(HUD_TIME, ((downwards && (tics < 30*TICRATE) && (leveltime/5 & 1)) ? sboredtime : sbotime), V_HUDTRANS); + + if (!tics && downwards && (leveltime/5 & 1)) // overtime! + return; + if (cv_timetic.value == 1) // Tics only -- how simple is this? ST_DrawNumFromHud(HUD_SECONDS, tics, V_HUDTRANS); else @@ -709,7 +787,7 @@ static void ST_drawLivesArea(void) // Spectator else if (stplyr->spectator) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "SPECTATE"); + //V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "SPECTATOR"); v_colmap = V_GRAYMAP; } // Tag @@ -747,10 +825,19 @@ static void ST_drawLivesArea(void) else v_colmap = V_GRAYMAP; } - else + else if (circuitmap) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "PLAYING"); + if (stplyr->exiting) + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "FINISHED"); + //V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f|V_YELLOWMAP, "FINISHED!"); + else + { + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, va("%u/%d", stplyr->laps+1, cv_numlaps.value)); + //V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); + } } + /*else + V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "PLAYING");*/ // name v_colmap |= (V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER); @@ -1647,92 +1734,34 @@ static void ST_drawMatchHUD(void) static inline void ST_drawRaceHUD(void) { - if (leveltime >= TICRATE && leveltime < 5*TICRATE) - { - INT32 height = ((3*BASEVIDHEIGHT)>>2) - 8; - INT32 bounce = (leveltime % TICRATE); - patch_t *racenum; - switch (leveltime/TICRATE) - { - case 1: - racenum = race3; - break; - case 2: - racenum = race2; - break; - case 3: - racenum = race1; - break; - default: - racenum = racego; - break; - } - if (bounce < 3) - { - height -= (2 - bounce); - if (!(P_AutoPause() || paused) && !bounce) - S_StartSound(0, ((racenum == racego) ? sfx_s3kad : sfx_s3ka7)); - } - V_DrawScaledPatch(((BASEVIDWIDTH - SHORT(racenum->width))/2), height, V_PERPLAYER, racenum); - } - - if (circuitmap) - { - if (stplyr->exiting) - V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f|V_YELLOWMAP, "FINISHED!"); - else - V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); - } + if (leveltime > TICRATE && leveltime <= 5*TICRATE) + ST_drawRaceNum(4*TICRATE - leveltime); } static void ST_drawTagHUD(void) { - char pstime[33] = ""; char pstext[33] = ""; // Figure out what we're going to print. if (leveltime < hidetime * TICRATE) //during the hide time, the seeker and hiders have different messages on their HUD. { - if (hidetime) - sprintf(pstime, "%d", (hidetime - leveltime/TICRATE)); //hide time is in seconds, not tics. - - if (stplyr->pflags & PF_TAGIT && !stplyr->spectator) - sprintf(pstext, "%s", M_GetText("WAITING FOR PLAYERS TO HIDE...")); - else - { - if (!stplyr->spectator) //spectators get a generic HUD message rather than a gametype specific one. - { - if (gametype == GT_HIDEANDSEEK) //hide and seek. - sprintf(pstext, "%s", M_GetText("HIDE BEFORE TIME RUNS OUT!")); - else //default - sprintf(pstext, "%s", M_GetText("FLEE BEFORE YOU ARE HUNTED!")); - } - else - sprintf(pstext, "%s", M_GetText("HIDE TIME REMAINING:")); - } - } - else - { - if (cv_timelimit.value && timelimitintics >= leveltime) - sprintf(pstime, "%d", (timelimitintics-leveltime)/TICRATE); - if (stplyr->pflags & PF_TAGIT) - sprintf(pstext, "%s", M_GetText("YOU'RE IT!")); - else - { - if (cv_timelimit.value) - sprintf(pstext, "%s", M_GetText("TIME REMAINING:")); - else //Since having no hud message in tag is not characteristic: - sprintf(pstext, "%s", M_GetText("NO TIME LIMIT")); - } + sprintf(pstext, "%s", M_GetText("Waiting for players to hide...")); + else if (gametype == GT_HIDEANDSEEK) //hide and seek. + sprintf(pstext, "%s", M_GetText("Hide before time runs out!")); + else //default + sprintf(pstext, "%s", M_GetText("Flee before you are hunted!")); } + else if (gametype == GT_HIDEANDSEEK && !(stplyr->pflags & PF_TAGIT)) + { + sprintf(pstext, "%s", M_GetText("You cannot move while hiding.")); + if (!splitscreen) + V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); + } // Print the stuff. if (pstext[0]) - V_DrawCenteredString(BASEVIDWIDTH/2, 168, V_PERPLAYER|V_SNAPTOBOTTOM, pstext); - - if (pstime[0]) - V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_PERPLAYER|V_SNAPTOBOTTOM, pstime); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER, pstext); } static void ST_drawCTFHUD(void) @@ -2010,8 +2039,24 @@ static void ST_overlayDrawer(void) if (!hu_showscores) // hide the following if TAB is held { // Countdown timer for Race Mode - if (countdown) - V_DrawCenteredString(BASEVIDWIDTH/2, 176, V_PERPLAYER, va("%d", countdown/TICRATE)); + if (countdown > 1) + { + tic_t time = countdown/TICRATE + 1; + if (time < 4) + ST_drawRaceNum(countdown); + else + { + tic_t num = time; + INT32 sz = SHORT(tallnum[0]->width)/2, width = 0; + do + { + width += sz; + num /= 10; + } while (num); + V_DrawTallNum((BASEVIDWIDTH/2) + width, ((3*BASEVIDHEIGHT)>>2) - 7, V_PERPLAYER, time); + //V_DrawCenteredString(BASEVIDWIDTH/2, 176, V_PERPLAYER, va("%d", countdown/TICRATE + 1)); + } + } // If you are in overtime, put a big honkin' flashin' message on the screen. if (G_RingSlingerGametype() && cv_overtime.value @@ -2032,7 +2077,7 @@ static void ST_overlayDrawer(void) if (gametype == GT_RACE || gametype == GT_COMPETITION) ST_drawRaceHUD(); // Tag HUD Stuff - else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) ST_drawTagHUD(); // CTF HUD Stuff else if (gametype == GT_CTF) @@ -2118,20 +2163,13 @@ static void ST_overlayDrawer(void) } else if (!splitscreen && gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); - else if (gametype == GT_HIDEANDSEEK && - (!stplyr->spectator && !(stplyr->pflags & PF_TAGIT)) && (leveltime > hidetime * TICRATE)) - { - V_DrawCenteredString(BASEVIDWIDTH/2, 116, V_PERPLAYER, M_GetText("You cannot move while hiding.")); - if (!splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); - } else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text. { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; if (respawntime > 0 && !stplyr->spectator) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, va(M_GetText("Respawn in: %d second%s."), respawntime, respawntime == 1 ? "" : "s")); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, va(M_GetText("Respawn in %d..."), respawntime)); else - V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Jump to respawn.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Jump to respawn.")); } else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE) #ifdef HAVE_BLUA @@ -2141,9 +2179,9 @@ static void ST_overlayDrawer(void) { V_DrawCenteredString(BASEVIDWIDTH/2, 60, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You are a spectator.")); if (G_GametypeHasTeams()) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to be assigned to a team.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to be assigned to a team.")); else if (G_IsSpecialStage(gamemap) && useNightsSS) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You cannot play until the stage has ended.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You cannot play until the stage has ended.")); else if (gametype == GT_COOP && stplyr->lives <= 0) { if (cv_cooplives.value == 2 @@ -2163,13 +2201,13 @@ static void ST_overlayDrawer(void) } if (i != MAXPLAYERS) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You'll steal a life on respawn.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You'll steal a life on respawn.")); } } else if (gametype != GT_COOP) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to enter the game.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to enter the game.")); if (!splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_HUDTRANSHALF, M_GetText("Press F12 to watch another player.")); + V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_HUDTRANSHALF, M_GetText("Press F12 to watch another player.")); V_DrawCenteredString(BASEVIDWIDTH/2, 148, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Jump to float and Spin to sink.")); } } diff --git a/src/st_stuff.h b/src/st_stuff.h index 50937907f..df1ac6433 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -102,7 +102,6 @@ typedef enum HUD_TIMEUP, HUD_HUNTPICS, HUD_GRAVBOOTSICO, - HUD_LAP, NUMHUDITEMS } hudnum_t; From 0885d271711155e02d389c04f12bf2c234d1a7f1 Mon Sep 17 00:00:00 2001 From: Sryder Date: Wed, 21 Mar 2018 19:45:37 +0000 Subject: [PATCH 070/212] Transform sprites in world space rather than screen space Transformation based on screen space would make sense if we didn't want anything in the world to effect the sprites. This should allow sprite splitting and sorting of sprites with level geometry easier. stransform is no longer needed. --- src/hardware/hw_glob.h | 1 + src/hardware/hw_main.c | 249 +++++++++++++---------------------------- 2 files changed, 79 insertions(+), 171 deletions(-) diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 94eef1d3e..fea06caff 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -68,6 +68,7 @@ typedef struct gr_vissprite_s struct gr_vissprite_s *prev; struct gr_vissprite_s *next; float x1, x2; + float z1, z2; float tz, ty; lumpnum_t patchlumpnum; boolean flip; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c4e3d879e..7b9628b3d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3928,12 +3928,10 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale) { - UINT8 i; - float tr_x, tr_y; - FOutVector *wv; FOutVector swallVerts[4]; FSurfaceInfo sSurf; fixed_t floorheight, mobjfloor; + float offset = 0; mobjfloor = HWR_OpaqueFloorAtPos( spr->mobj->x, spr->mobj->y, @@ -3972,6 +3970,8 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t } floorheight = FixedInt(spr->mobj->z - floorheight); + + offset = floorheight; } else floorheight = FixedInt(spr->mobj->z - mobjfloor); @@ -3984,47 +3984,42 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t // 0--1 // x1/x2 were already scaled in HWR_ProjectSprite + // First match the normal sprite swallVerts[0].x = swallVerts[3].x = spr->x1; swallVerts[2].x = swallVerts[1].x = spr->x2; + swallVerts[0].z = swallVerts[3].z = spr->z1; + swallVerts[2].z = swallVerts[1].z = spr->z2; if (spr->mobj && this_scale != 1.0f) { // Always a pixel above the floor, perfectly flat. swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3); - swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset) * this_scale; - swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset * this_scale; + // Now transform the TOP vertices along the floor in the direction of the camera + swallVerts[3].x = spr->x1 + ((gpatch->height * this_scale) + offset) * gr_viewcos; + swallVerts[2].x = spr->x2 + ((gpatch->height * this_scale) + offset) * gr_viewcos; + swallVerts[3].z = spr->z1 + ((gpatch->height * this_scale) + offset) * gr_viewsin; + swallVerts[2].z = spr->z2 + ((gpatch->height * this_scale) + offset) * gr_viewsin; } else { // Always a pixel above the floor, perfectly flat. swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3); - // Spread out top away from the camera. (Fixme: Make it always move out in the same direction!... somehow.) - swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset); - swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset; + // Now transform the TOP vertices along the floor in the direction of the camera + swallVerts[3].x = spr->x1 + (gpatch->height + offset) * gr_viewcos; + swallVerts[2].x = spr->x2 + (gpatch->height + offset) * gr_viewcos; + swallVerts[3].z = spr->z1 + (gpatch->height + offset) * gr_viewsin; + swallVerts[2].z = spr->z2 + (gpatch->height + offset) * gr_viewsin; } - // transform - wv = swallVerts; - - for (i = 0; i < 4; i++,wv++) + // We also need to move the bottom ones away when shadowoffs is on + if (cv_shadowoffs.value) { - // Offset away from the camera based on height from floor. - if (cv_shadowoffs.value) - wv->z += floorheight; - wv->z += 3; - - //look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - tr_x = wv->z; - tr_y = wv->y; - wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin); - wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos); - // ---------------------- mega lame test ---------------------------------- - - //scale y before frustum so that frustum can be scaled to screen height - wv->y *= ORIGINAL_ASPECT * gr_fovlud; - wv->x *= gr_fovlud; + swallVerts[0].x = spr->x1 + offset * gr_viewcos; + swallVerts[1].x = spr->x2 + offset * gr_viewcos; + swallVerts[0].z = spr->z1 + offset * gr_viewsin; + swallVerts[1].z = spr->z2 + offset * gr_viewsin; } if (spr->flip) @@ -4111,10 +4106,8 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t // -----------------+ static void HWR_DrawSprite(gr_vissprite_t *spr) { - UINT8 i; - float tr_x, tr_y, this_scale = 1.0f; + float this_scale = 1.0f; FOutVector wallVerts[4]; - FOutVector *wv; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); @@ -4161,24 +4154,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // make a wall polygon (with 2 triangles), using the floor/ceiling heights, // and the 2d map coords of start/end vertices - wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz; - - // transform - wv = wallVerts; - - for (i = 0; i < 4; i++,wv++) - { - //look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - tr_x = wv->z; - tr_y = wv->y; - wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin); - wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos); - // ---------------------- mega lame test ---------------------------------- - - //scale y before frustum so that frustum can be scaled to screen height - wv->y *= ORIGINAL_ASPECT * gr_fovlud; - wv->x *= gr_fovlud; - } + wallVerts[0].z = wallVerts[3].z = spr->z1; + wallVerts[1].z = wallVerts[2].z = spr->z2; if (spr->flip) { @@ -4289,11 +4266,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // Sprite drawer for precipitation static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) { - UINT8 i; FBITFIELD blend = 0; - float tr_x, tr_y; FOutVector wallVerts[4]; - FOutVector *wv; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; @@ -4319,24 +4293,8 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) // make a wall polygon (with 2 triangles), using the floor/ceiling heights, // and the 2d map coords of start/end vertices - wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz; - - // transform - wv = wallVerts; - - for (i = 0; i < 4; i++, wv++) - { - //look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - tr_x = wv->z; - tr_y = wv->y; - wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin); - wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos); - // ---------------------- mega lame test ---------------------------------- - - //scale y before frustum so that frustum can be scaled to screen height - wv->y *= ORIGINAL_ASPECT * gr_fovlud; - wv->x *= gr_fovlud; - } + wallVerts[0].z = wallVerts[3].z = spr->z1; + wallVerts[1].z = wallVerts[2].z = spr->z2; wallVerts[0].sow = wallVerts[3].sow = 0; wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; @@ -4830,7 +4788,7 @@ static void HWR_CreateDrawNodes(void) // -------------------------------------------------------------------------- #ifdef SORTING // added the stransform so they can be switched as drawing happenes so MD2s and sprites are sorted correctly with each other -static void HWR_DrawSprites(FTransform *stransform) +static void HWR_DrawSprites() { if (gr_visspritecount > 0) { @@ -4843,37 +4801,22 @@ static void HWR_DrawSprites(FTransform *stransform) { #ifdef HWPRECIP if (spr->precip) - { - HWD.pfnSetTransform(stransform); HWR_DrawPrecipitationSprite(spr); - } else #endif if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { if (!cv_grmd2.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) - { - HWD.pfnSetTransform(stransform); HWR_DrawSprite(spr); - } else - { - HWD.pfnSetTransform(&atransform); HWR_DrawMD2(spr); - } } else { if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) - { - HWD.pfnSetTransform(stransform); HWR_DrawSprite(spr); - } else - { - HWD.pfnSetTransform(&atransform); HWR_DrawMD2(spr); - } } } } @@ -4963,8 +4906,10 @@ static void HWR_ProjectSprite(mobj_t *thing) { gr_vissprite_t *vis; float tr_x, tr_y; - float tx, tz; + float tz; float x1, x2; + float z1, z2; + float rightsin, rightcos; float this_scale; float gz, gzt; spritedef_t *sprdef; @@ -4991,7 +4936,9 @@ static void HWR_ProjectSprite(mobj_t *thing) if (tz < ZCLIP_PLANE && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear return; - tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos); + // The above can stay as it works for cutting sprites that are too close + tr_x = FIXED_TO_FLOAT(thing->x); + tr_y = FIXED_TO_FLOAT(thing->y); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -5046,23 +4993,23 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); - // calculate edges of the shape + rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT)); + rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT)); if (flip) - tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale; + { + x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale); + x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale); + } else - tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale; + { + x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale); + x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale); + } - // project x - x1 = gr_windowcenterx + (tx * gr_centerx / tz); - - //faB : tr_x doesnt matter - // hurdler: it's used in cliptosolidsegs - tr_x = x1; - - x1 = tx; - - tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale; - x2 = gr_windowcenterx + (tx * gr_centerx / tz); + z1 = tr_y + x1 * rightsin; + z2 = tr_y - x2 * rightsin; + x1 = tr_x + x1 * rightcos; + x2 = tr_x - x2 * rightcos; if (thing->eflags & MFE_VERTICALFLIP) { @@ -5099,13 +5046,10 @@ static void HWR_ProjectSprite(mobj_t *thing) // store information in a vissprite vis = HWR_NewVisSprite(); vis->x1 = x1; -#if 0 vis->x2 = x2; -#else - (void)x2; -#endif - vis->x2 = tx; - vis->tz = tz; + vis->z1 = z1; + vis->z2 = z2; + vis->tz = tz; // Keep tz for the simple sprite sorting that happens vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST vis->patchlumpnum = sprframe->lumppat[rot]; vis->flip = flip; @@ -5136,7 +5080,7 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->colormap = colormaps; // set top/bottom coords - vis->ty = gzt - gr_viewz; + vis->ty = gzt; //CONS_Debug(DBG_RENDER, "------------------\nH: sprite : %d\nH: frame : %x\nH: type : %d\nH: sname : %s\n\n", // thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]); @@ -5155,8 +5099,10 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) { gr_vissprite_t *vis; float tr_x, tr_y; - float tx, tz; + float tz; float x1, x2; + float z1, z2; + float rightsin, rightcos; spritedef_t *sprdef; spriteframe_t *sprframe; size_t lumpoff; @@ -5174,7 +5120,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) if (tz < ZCLIP_PLANE) return; - tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos); + tr_x = FIXED_TO_FLOAT(thing->x); + tr_y = FIXED_TO_FLOAT(thing->y); // decide which patch to use for sprite relative to player if ((unsigned)thing->sprite >= numsprites) @@ -5201,32 +5148,32 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) lumpoff = sprframe->lumpid[0]; flip = sprframe->flip; // Will only be 0x00 or 0xFF - // calculate edges of the shape - tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset); + rightsin = FIXED_TO_FLOAT(FINESINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT)); + rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT)); + if (flip) + { + x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset); + x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset); + } + else + { + x1 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset); + x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset); + } - // project x - x1 = gr_windowcenterx + (tx * gr_centerx / tz); - - //faB : tr_x doesnt matter - // hurdler: it's used in cliptosolidsegs - tr_x = x1; - - x1 = tx; - - tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width); - x2 = gr_windowcenterx + (tx * gr_centerx / tz); + z1 = tr_y + x1 * rightsin; + z2 = tr_y - x2 * rightsin; + x1 = tr_x + x1 * rightcos; + x2 = tr_x - x2 * rightcos; // // store information in a vissprite // vis = HWR_NewVisSprite(); vis->x1 = x1; -#if 0 vis->x2 = x2; -#else - (void)x2; -#endif - vis->x2 = tx; + vis->z1 = z1; + vis->z2 = z2; vis->tz = tz; vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST vis->patchlumpnum = sprframe->lumppat[rot]; @@ -5236,7 +5183,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->colormap = colormaps; // set top/bottom coords - vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz; + vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); vis->precip = true; } @@ -5387,7 +5334,6 @@ void HWR_SetViewSize(void) void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) { const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd); - FTransform stransform; postimg_t *type; if (splitscreen && player == &players[secondarydisplayplayer]) @@ -5457,25 +5403,6 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) atransform.fovyangle = fpov; // Tails atransform.splitscreen = splitscreen; - // Transform for sprites - stransform.anglex = 0.0f; - stransform.angley = -270.0f; - - if (*type == postimg_flip) - stransform.flip = true; - else - stransform.flip = false; - - stransform.x = 0.0f; - stransform.y = 0.0f; - stransform.z = 0.0f; - stransform.scalex = 1; - stransform.scaley = 1; - stransform.scalez = 1; - stransform.fovxangle = 90.0f; - stransform.fovyangle = 90.0f; - stransform.splitscreen = splitscreen; - gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l))); //------------------------------------------------------------------------ @@ -5556,7 +5483,7 @@ if (0) #endif #ifdef SORTING - HWR_DrawSprites(&stransform); + HWR_DrawSprites(); #endif #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? @@ -5599,7 +5526,6 @@ if (0) void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) { const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd); - FTransform stransform; postimg_t *type; const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on @@ -5684,25 +5610,6 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) atransform.fovyangle = fpov; // Tails atransform.splitscreen = splitscreen; - // Transform for sprites - stransform.anglex = 0.0f; - stransform.angley = -270.0f; - - if (*type == postimg_flip) - stransform.flip = true; - else - stransform.flip = false; - - stransform.x = 0.0f; - stransform.y = 0.0f; - stransform.z = 0.0f; - stransform.scalex = 1; - stransform.scaley = 1; - stransform.scalez = 1; - stransform.fovxangle = 90.0f; - stransform.fovyangle = 90.0f; - stransform.splitscreen = splitscreen; - gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l))); //------------------------------------------------------------------------ @@ -5783,7 +5690,7 @@ if (0) #endif #ifdef SORTING - HWR_DrawSprites(&stransform); + HWR_DrawSprites(); #endif #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? From 839ee0ab852c0ccfe8b974b93dccbb0a38fdba6d Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 22 Mar 2018 00:52:14 +0000 Subject: [PATCH 071/212] OpenGL Sprite Splitting --- src/hardware/hw_main.c | 309 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 289 insertions(+), 20 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 7b9628b3d..b17ead955 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1219,7 +1219,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, } #endif +#ifdef ESLOPE if (endbheight >= endtop) +#endif if (bheight >= top) continue; @@ -4099,6 +4101,285 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t } } +static void HWR_SplitSprite(gr_vissprite_t *spr) +{ + float this_scale = 1.0f; + FOutVector wallVerts[4]; + GLPatch_t *gpatch; + FSurfaceInfo Surf; + const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); + extracolormap_t *colormap; + FUINT lightlevel; + FBITFIELD blend = 0; + UINT8 alpha; + + INT32 i; + float realtop, realbot, top, bot; + float towtop, towbot, towmult; + float bheight; + const sector_t *sector = spr->mobj->subsector->sector; + const lightlist_t *list = sector->lightlist; +#ifdef ESLOPE + float endrealtop, endrealbot, endtop, endbot; + float endbheight; + fixed_t temp; + fixed_t v1x, v1y, v2x, v2y; +#endif + + this_scale = FIXED_TO_FLOAT(spr->mobj->scale); + + if (hires) + this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale); + + gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + + // cache the patch in the graphics card memory + //12/12/99: Hurdler: same comment as above (for md2) + //Hurdler: 25/04/2000: now support colormap in hardware mode + HWR_GetMappedPatch(gpatch, spr->colormap); + + // Draw shadow BEFORE sprite + if (cv_shadow.value // Shadows enabled + && (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow. + && !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow. +#ifdef ALAM_LIGHTING + && !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow. + && (!spr->mobj->player || spr->mobj->player->powers[pw_super])) // Except for non-super players. +#endif + && (spr->mobj->z >= spr->mobj->floorz)) // Without this, your shadow shows on the floor, even after you die and fall through the ground. + { + //////////////////// + // SHADOW SPRITE! // + //////////////////// + HWR_DrawSpriteShadow(spr, gpatch, this_scale); + } + + wallVerts[0].x = wallVerts[3].x = spr->x1; + wallVerts[2].x = wallVerts[1].x = spr->x2; + wallVerts[0].z = wallVerts[3].z = spr->z1; + wallVerts[1].z = wallVerts[2].z = spr->z2; + + wallVerts[2].y = wallVerts[3].y = spr->ty; + if (spr->mobj && this_scale != 1.0f) + wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale; + else + wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; + + v1x = FLOAT_TO_FIXED(spr->x1); + v1y = FLOAT_TO_FIXED(spr->z1); + v2x = FLOAT_TO_FIXED(spr->x2); + v2y = FLOAT_TO_FIXED(spr->z2); + + if (spr->flip) + { + wallVerts[0].sow = wallVerts[3].sow = gpatch->max_s; + wallVerts[2].sow = wallVerts[1].sow = 0; + }else{ + wallVerts[0].sow = wallVerts[3].sow = 0; + wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; + } + + // flip the texture coords (look familiar?) + if (spr->vflip) + { + wallVerts[3].tow = wallVerts[2].tow = gpatch->max_t; + wallVerts[0].tow = wallVerts[1].tow = 0; + }else{ + wallVerts[3].tow = wallVerts[2].tow = 0; + wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t; + } + + realtop = top = wallVerts[3].y; + realbot = bot = wallVerts[0].y; + towtop = wallVerts[3].tow; + towbot = wallVerts[0].tow; + towmult = (towbot - towtop) / (top - bot); + +#ifdef ESLOPE + endrealtop = endtop = wallVerts[2].y; + endrealbot = endbot = wallVerts[1].y; +#endif + + if (!cv_translucency.value) // translucency disabled + { + Surf.FlatColor.s.alpha = 0xFF; + blend = PF_Translucent|PF_Occlude; + } + else if (spr->mobj->flags2 & MF2_SHADOW) + { + Surf.FlatColor.s.alpha = 0x40; + blend = PF_Translucent; + } + else if (spr->mobj->frame & FF_TRANSMASK) + blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + else + { + // BP: i agree that is little better in environement but it don't + // work properly under glide nor with fogcolor to ffffff :( + // Hurdler: PF_Environement would be cool, but we need to fix + // the issue with the fog before + Surf.FlatColor.s.alpha = 0xFF; + blend = PF_Translucent|PF_Occlude; + } + + alpha = Surf.FlatColor.s.alpha; + + // Start with the lightlevel and colormap from the top of the sprite + lightlevel = *list[sector->numlights - 1].lightlevel; + colormap = list[sector->numlights - 1].extra_colormap; + i = 0; + temp = FLOAT_TO_FIXED(realtop); + +#ifdef ESLOPE + for (i = 1; i < sector->numlights; i++) + { + fixed_t h = sector->lightlist[i].slope ? P_GetZAt(sector->lightlist[i].slope, spr->mobj->x, spr->mobj->y) + : sector->lightlist[i].height; + if (h <= temp) + { + lightlevel = *list[i-1].lightlevel; + colormap = list[i-1].extra_colormap; + break; + } + } +#else + i = R_GetPlaneLight(sector, temp, false); + lightlevel = *list[i].lightlevel; + colormap = list[i].extra_colormap; +#endif + + for (i = 0; i < sector->numlights; i++) + { +#ifdef ESLOPE + if (endtop < endrealbot) +#endif + if (top < realbot) + return; + + // even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite + if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) + { + lightlevel = *list[i].lightlevel; + colormap = list[i].extra_colormap; + } + +#ifdef ESLOPE + if (i + 1 < sector->numlights) + { + if (list[i+1].slope) + { + temp = P_GetZAt(list[i+1].slope, v1x, v1y); + bheight = FIXED_TO_FLOAT(temp); + temp = P_GetZAt(list[i+1].slope, v2x, v2y); + endbheight = FIXED_TO_FLOAT(temp); + } + else + bheight = endbheight = FIXED_TO_FLOAT(list[i+1].height); + } + else + { + bheight = realbot; + endbheight = endrealbot; + } +#else + if (i + 1 < sector->numlights) + { + bheight = FIXED_TO_FLOAT(list[i+1].height); + } + else + { + bheight = realbot; + } +#endif + +#ifdef ESLOPE + if (endbheight >= endtop) +#endif + if (bheight >= top) + continue; + + bot = bheight; + + if (bot < realbot) + bot = realbot; + +#ifdef ESLOPE + endbot = endbheight; + + if (endbot < endrealbot) + endbot = endrealbot; +#endif + +#ifdef ESLOPE + wallVerts[3].tow = towtop + ((realtop - top) * towmult); + wallVerts[2].tow = towtop + ((endrealtop - endtop) * towmult); + wallVerts[0].tow = towtop + ((realtop - bot) * towmult); + wallVerts[1].tow = towtop + ((endrealtop - endbot) * towmult); + + wallVerts[3].y = top; + wallVerts[2].y = endtop; + wallVerts[0].y = bot; + wallVerts[1].y = endbot; +#else + wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult); + wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult); + + wallVerts[2].y = wallVerts[3].y = top; + wallVerts[0].y = wallVerts[1].y = bot; +#endif + + if (colormap) + Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); + else + Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + + Surf.FlatColor.s.alpha = alpha; + + HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip); + + top = bot; +#ifdef ESLOPE + endtop = endbot; +#endif + } + + bot = realbot; +#ifdef ESLOPE + endbot = endrealbot; + if (endtop <= endrealbot) +#endif + if (top <= realbot) + return; + + // If we're ever down here, somehow the above loop hasn't draw all the light levels of sprite +#ifdef ESLOPE + wallVerts[3].tow = towtop + ((realtop - top) * towmult); + wallVerts[2].tow = towtop + ((endrealtop - endtop) * towmult); + wallVerts[0].tow = towtop + ((realtop - bot) * towmult); + wallVerts[1].tow = towtop + ((endrealtop - endbot) * towmult); + + wallVerts[3].y = top; + wallVerts[2].y = endtop; + wallVerts[0].y = bot; + wallVerts[1].y = endbot; +#else + wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult); + wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult); + + wallVerts[2].y = wallVerts[3].y = top; + wallVerts[0].y = wallVerts[1].y = bot; +#endif + + if (colormap) + Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); + else + Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false); + + Surf.FlatColor.s.alpha = alpha; + + HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip); +} + // -----------------+ // HWR_DrawSprite : Draw flat sprites // : (monsters, bonuses, weapons, lights, ...) @@ -4122,6 +4403,12 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) if (!spr->mobj->subsector) return; + if (spr->mobj->subsector->sector->numlights) + { + HWR_SplitSprite(spr); + return; + } + // cache sprite graphics //12/12/99: Hurdler: // OK, I don't change anything for MD2 support because I want to be @@ -4207,26 +4494,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) UINT8 lightlevel = 255; extracolormap_t *colormap = sector->extra_colormap; - if (sector->numlights) - { - INT32 light; - - light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before - - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *sector->lightlist[light].lightlevel; - - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; - } - else - { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = sector->lightlevel; - - if (sector->extra_colormap) - colormap = sector->extra_colormap; - } + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = sector->lightlevel; if (colormap) Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false); From fab4b7f5eab7509a6c2a3a6bc1b05ce7d3452ebd Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 22 Mar 2018 01:10:53 +0000 Subject: [PATCH 072/212] Stop squashing the screen vertically in non-green resolutions --- src/hardware/hw_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index b17ead955..86b80904f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5666,7 +5666,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) atransform.y = gr_viewy; // FIXED_TO_FLOAT(viewy) atransform.z = gr_viewz; // FIXED_TO_FLOAT(viewz) atransform.scalex = 1; - atransform.scaley = ORIGINAL_ASPECT; + atransform.scaley = (float)vid.width/vid.height; atransform.scalez = 1; atransform.fovxangle = fpov; // Tails atransform.fovyangle = fpov; // Tails @@ -5873,7 +5873,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) atransform.y = gr_viewy; // FIXED_TO_FLOAT(viewy) atransform.z = gr_viewz; // FIXED_TO_FLOAT(viewz) atransform.scalex = 1; - atransform.scaley = ORIGINAL_ASPECT; + atransform.scaley = (float)vid.width/vid.height; atransform.scalez = 1; atransform.fovxangle = fpov; // Tails atransform.fovyangle = fpov; // Tails From a431197921a847cf387da362dc2cbfebb0299ef8 Mon Sep 17 00:00:00 2001 From: jameds Date: Thu, 11 Jan 2018 17:35:39 -0800 Subject: [PATCH 073/212] Fixed "invalid pointer" error when passing "" to Command_connect(). --- src/d_clisrv.c | 2 +- src/m_menu.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7d0e44b45..36d13fc14 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2244,7 +2244,7 @@ static void Command_connect(void) // Assume we connect directly. boolean viams = false; - if (COM_Argc() < 2) + if (COM_Argc() < 2 || *COM_Argv(1) == 0) { CONS_Printf(M_GetText( "Connect (port): connect to a server\n" diff --git a/src/m_menu.c b/src/m_menu.c index ea93d1e2d..0ab771579 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6295,6 +6295,13 @@ static void M_DrawConnectIPMenu(void) static void M_ConnectIP(INT32 choice) { (void)choice; + + if (*setupm_ip == 0) + { + M_StartMessage("You must specify an IP address.\n", NULL, MM_NOTHING); + return; + } + COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); // A little "please wait" message. From f62cb3a30a7bd36d52a5c6a7853baf9aaf887aa9 Mon Sep 17 00:00:00 2001 From: Sryder Date: Fri, 23 Mar 2018 22:27:29 +0000 Subject: [PATCH 074/212] I've commented out the call to HWR_CorrectSWTricks. I don't think it does anything for us anymore, and might even break things with slopes. Someone let me know if I'm wrong and am breaking things horribly here. --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 8e746457b..e93cbed51 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2718,7 +2718,7 @@ boolean P_SetupLevel(boolean skipprecip) HWR_ResetLights(); #endif // Correct missing sidedefs & deep water trick - HWR_CorrectSWTricks(); + //HWR_CorrectSWTricks(); HWR_CreatePlanePolygons((INT32)numnodes - 1); } #endif From 876d0fa58b3ba39d86cfd4b46a488c711211d706 Mon Sep 17 00:00:00 2001 From: jameds Date: Fri, 23 Mar 2018 18:06:32 -0700 Subject: [PATCH 075/212] Removed contradictory `-connect` check --- src/d_main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 063d28453..7368383b5 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1068,7 +1068,7 @@ void D_SRB2Main(void) // add any files specified on the command line with -file wadfile // to the wad list - if (!(M_CheckParm("-connect"))) + if (!(M_CheckParm("-connect") && !M_CheckParm("-server"))) { if (M_CheckParm("-file")) { @@ -1323,7 +1323,7 @@ void D_SRB2Main(void) ultimatemode = true; } - if (autostart || netgame || M_CheckParm("+connect") || M_CheckParm("-connect")) + if (autostart || netgame) { gameaction = ga_nothing; @@ -1361,8 +1361,7 @@ void D_SRB2Main(void) } } - if (server && !M_CheckParm("+map") && !M_CheckParm("+connect") - && !M_CheckParm("-connect")) + if (server && !M_CheckParm("+map")) { // Prevent warping to nonexistent levels if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR) From dc9fd6f02ed4b681ed4982d119672f07cc91e585 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 25 Mar 2018 19:07:21 -0400 Subject: [PATCH 076/212] MT_NIGHTSBUMPER Spawn: Don't reset mthing->options --- src/p_mobj.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 8695d57e4..157092dea 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10060,9 +10060,6 @@ domaceagain: // the bumper in 30 degree increments. mobj->threshold = (mthing->options & 15) % 12; // It loops over, etc P_SetMobjState(mobj, mobj->info->spawnstate+mobj->threshold); - - // you can shut up now, OBJECTFLIP. And all of the other options, for that matter. - mthing->options &= ~0xF; break; case MT_EGGCAPSULE: if (mthing->angle <= 0) From d85f108997bfeca3e0b1731c1aad70617456400b Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 25 Mar 2018 19:42:46 -0400 Subject: [PATCH 077/212] P_SpawnMapThing: Ignore MTF_ flags if MT_NIGHTSBUMPER --- src/p_mobj.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 157092dea..4c0ebb657 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10261,6 +10261,14 @@ domaceagain: } } + // ignore MTF_ flags and return early + if (i == MT_NIGHTSBUMPER) + { + mobj->angle = FixedAngle(mthing->angle*FRACUNIT); + mthing->mobj = mobj; + return; + } + mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if ((mthing->options & MTF_AMBUSH) From 67e438128435aca992e2d45aa1f35603c5501984 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 26 Mar 2018 00:33:17 -0400 Subject: [PATCH 078/212] Fix NiGHTS drone loop detection by using pl->flyangle --- src/p_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 6d1760596..2704478e1 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -917,14 +917,14 @@ static boolean PIT_CheckThing(mobj_t *thing) // not (your direction) xor (stored direction) // In other words, you can't u-turn and respawn rings near the drone. if (pl->bonustime && (pl->powers[pw_carry] == CR_NIGHTSMODE) && (INT32)leveltime > droneobj->extravalue2 && ( - !(pl->anotherflyangle >= 90 && pl->anotherflyangle <= 270) + !(pl->flyangle >= 90 && pl->flyangle <= 270) ^ (droneobj->extravalue1 >= 90 && droneobj->extravalue1 <= 270) )) { // Reload all the fancy ring stuff! P_ReloadRings(); } - droneobj->extravalue1 = pl->anotherflyangle; + droneobj->extravalue1 = pl->flyangle; droneobj->extravalue2 = (INT32)leveltime + TICRATE; } From ce215195f89bf52e5c2e2ddd7d5444685edf835d Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 26 Mar 2018 01:04:02 -0400 Subject: [PATCH 079/212] NiGHTS drone loop: Change flyangle comparison to fix detection from vertical angles Use > 90 && < 270 instead of >= 90 && <= 270. Fixes a bug where if you fly directly up (flyangle 90) or directly down (flyangle 270), that registers as a backwards direction, so you trigger the loop detection by flying BACKWARDS, not FORWARDS. This edge case (only possible via JUMPTOAXIS) should default to FORWARDS looping. --- src/p_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 2704478e1..630dd87ae 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -917,8 +917,8 @@ static boolean PIT_CheckThing(mobj_t *thing) // not (your direction) xor (stored direction) // In other words, you can't u-turn and respawn rings near the drone. if (pl->bonustime && (pl->powers[pw_carry] == CR_NIGHTSMODE) && (INT32)leveltime > droneobj->extravalue2 && ( - !(pl->flyangle >= 90 && pl->flyangle <= 270) - ^ (droneobj->extravalue1 >= 90 && droneobj->extravalue1 <= 270) + !(pl->flyangle > 90 && pl->flyangle < 270) + ^ (droneobj->extravalue1 > 90 && droneobj->extravalue1 < 270) )) { // Reload all the fancy ring stuff! From 98601dc757cb2c06fe8402bbb76f92475b7bd0c5 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 26 Mar 2018 23:53:09 +0100 Subject: [PATCH 080/212] A lot! * cv_powerupdisplay. Never, First-person only (default), Always. * New monitor stuff. * Fixed hitmessages. * Some CTF stuff. * Aaaaugh it's a lot I hate myself I need to work on my coursework. * I'll figure out what I did here in the merge request when that's done. --- src/d_netcmd.c | 6 +- src/dehacked.c | 9 +- src/doomstat.h | 1 + src/hu_stuff.c | 22 +-- src/info.c | 163 +++++++++---------- src/info.h | 7 +- src/m_cheat.c | 2 +- src/m_menu.c | 27 ++-- src/p_inter.c | 5 +- src/p_spec.c | 9 +- src/p_user.c | 12 +- src/screen.c | 14 +- src/sounds.c | 16 +- src/st_stuff.c | 417 +++++++++++++++++++++++++++++++------------------ src/st_stuff.h | 2 +- 15 files changed, 415 insertions(+), 297 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 94eada152..cc641b8b0 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -309,9 +309,12 @@ consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Tics"}, {2, "Centiseconds"}, {3, "Mania"}, {0, NULL}}; +static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Centiseconds"}, {2, "Mania"}, {3, "Tics"}, {0, NULL}}; consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display +static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-person only"}, {2, "Always"}, {0, NULL}}; +consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display + consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}}; @@ -670,6 +673,7 @@ void D_RegisterClientCommands(void) // HUD CV_RegisterVar(&cv_timetic); + CV_RegisterVar(&cv_powerupdisplay); CV_RegisterVar(&cv_itemfinder); CV_RegisterVar(&cv_showinputjoy); diff --git a/src/dehacked.c b/src/dehacked.c index 704786879..3726cb381 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4521,6 +4521,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BOXSPARKLE1", "S_BOXSPARKLE2", "S_BOXSPARKLE3", + "S_BOXSPARKLE4", "S_BOX_FLICKER", "S_BOX_POP1", @@ -5511,8 +5512,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Got Flag Sign "S_GOTFLAG", - "S_GOTREDFLAG", - "S_GOTBLUEFLAG", "S_CORK", @@ -5852,6 +5851,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_XPLD_FLICKY", "S_XPLD1", "S_XPLD2", + "S_XPLD3", + "S_XPLD4", + "S_XPLD5", + "S_XPLD6", "S_XPLD_EGGTRAP", // Underwater Explosion @@ -6815,7 +6818,7 @@ static const char *const HUDITEMS_LIST[] = { "TIMELEFTNUM", "TIMEUP", "HUNTPICS", - "GRAVBOOTSICO", + "POWERUPS", "LAP" }; diff --git a/src/doomstat.h b/src/doomstat.h index de260ef06..d4735f6b2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -498,6 +498,7 @@ extern boolean singletics; #include "d_clisrv.h" extern consvar_t cv_timetic; // display high resolution timer +extern consvar_t cv_powerupdisplay; // display powerups extern consvar_t cv_showinputjoy; // display joystick in time attack extern consvar_t cv_forceskin; // force clients to use the server's skin extern consvar_t cv_downloading; // allow clients to downloading WADs. diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 58db7961b..c955a490d 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1547,7 +1547,7 @@ static inline void HU_DrawSpectatorTicker(void) templength = length; } - V_DrawString(templength, height + 8, V_TRANSLUCENT, current); + V_DrawString(templength, height + 8, V_TRANSLUCENT|V_ALLOWLOWERCASE, current); } length += (signed)strlen(player_names[i]) * 8 + 16; @@ -1559,7 +1559,6 @@ static inline void HU_DrawSpectatorTicker(void) // static void HU_DrawRankings(void) { - patch_t *p; playersort_t tab[MAXPLAYERS]; INT32 i, j, scorelines; boolean completed[MAXPLAYERS]; @@ -1568,25 +1567,6 @@ static void HU_DrawRankings(void) // draw the current gametype in the lower right HU_drawGametype(); - if (G_GametypeHasTeams()) - { - if (gametype == GT_CTF) - p = bflagico; - else - p = bmatcico; - - V_DrawSmallScaledPatch(128 - SHORT(p->width)/4, 4, 0, p); - V_DrawCenteredString(128, 16, 0, va("%u", bluescore)); - - if (gametype == GT_CTF) - p = rflagico; - else - p = rmatcico; - - V_DrawSmallScaledPatch(192 - SHORT(p->width)/4, 4, 0, p); - V_DrawCenteredString(192, 16, 0, va("%u", redscore)); - } - if (gametype != GT_RACE && gametype != GT_COMPETITION && gametype != GT_COOP) { if (cv_timelimit.value && timelimitintics > 0) diff --git a/src/info.c b/src/info.c index acb12379a..58a2ba8f4 100644 --- a/src/info.c +++ b/src/info.c @@ -680,7 +680,7 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY // 1-Up box sprites (uses player sprite) - {SPR_PLAY, SPR2_LIFE, 2, {NULL}, 0, 16, S_PLAY_BOX2}, // S_PLAY_BOX1 + {SPR_PLAY, SPR2_LIFE, 2, {NULL}, 0, 18, S_PLAY_BOX2}, // S_PLAY_BOX1 {SPR_NULL, 0, 1, {NULL}, 0, 0, S_PLAY_BOX1}, // S_PLAY_BOX2 {SPR_PLAY, SPR2_LIFE, 4, {NULL}, 0, 4, S_PLAY_ICON2}, // S_PLAY_ICON1 {SPR_NULL, 0, 12, {NULL}, 0, 0, S_PLAY_ICON3}, // S_PLAY_ICON2 @@ -1727,9 +1727,10 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 2, {A_SetRandomTics}, TICRATE/2, 3*TICRATE, S_CANNONLAUNCHER1}, // S_CANNONLAUNCHER3 // Monitor Miscellany - {SPR_NSPK, FF_TRANS40, 20, {NULL}, 0, 0, S_BOXSPARKLE2}, // S_BOXSPARKLE1 - {SPR_NSPK, FF_TRANS60, 10, {NULL}, 0, 0, S_BOXSPARKLE3}, // S_BOXSPARKLE2 - {SPR_NSPK, FF_TRANS80, 5, {NULL}, 0, 0, S_NULL}, // S_BOXSPARKLE3 + {SPR_NSPK, 0, 16, {NULL}, 0, 0, S_BOXSPARKLE2}, // S_BOXSPARKLE1 + {SPR_NSPK, 1, 12, {NULL}, 0, 0, S_BOXSPARKLE3}, // S_BOXSPARKLE2 + {SPR_NSPK, 2, 8, {NULL}, 0, 0, S_BOXSPARKLE4}, // S_BOXSPARKLE3 + {SPR_NSPK, 3, 4, {NULL}, 0, 0, S_NULL}, // S_BOXSPARKLE4 {SPR_MSTV, 0, 1, {NULL}, 0, 0, S_SPAWNSTATE}, // S_BOX_FLICKER {SPR_MSTV, 0, 4, {A_MonitorPop}, 0, 0, S_BOX_POP2}, // S_BOX_POP1 @@ -2735,8 +2736,6 @@ state_t states[NUMSTATES] = // CTF Sign {SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG - {SPR_GFLG, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTREDFLAG - {SPR_GFLG, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTBLUEFLAG {SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK @@ -3121,11 +3120,15 @@ state_t states[NUMSTATES] = {SPR_SPRK, FF_TRANS90|3, 1, {NULL}, 0, 0, S_NULL}, // S_SPRK16 // Robot Explosion - {SPR_BOM1, 0, 0, {A_FlickySpawn}, 0, 0, S_XPLD1}, // S_XPLD_FLICKY - {SPR_BOM1, 0, 1, {A_Scream}, 0, 0, S_XPLD2}, // S_XPLD1 - {SPR_BOM1, FF_ANIMATE|1, 15, {NULL}, 2, 5, S_NULL}, // S_XPLD2 + {SPR_BOM1, 0, 0, {A_FlickySpawn}, 0, 0, S_XPLD1}, // S_XPLD_FLICKY + {SPR_BOM1, 0, 2, {A_Scream}, 0, 0, S_XPLD2}, // S_XPLD1 + {SPR_BOM1, 1, 2, {NULL}, 0, 0, S_XPLD3}, // S_XPLD2 + {SPR_BOM1, 2, 3, {NULL}, 0, 0, S_XPLD4}, // S_XPLD3 + {SPR_BOM1, 3, 3, {NULL}, 0, 0, S_XPLD5}, // S_XPLD4 + {SPR_BOM1, 4, 4, {NULL}, 0, 0, S_XPLD6}, // S_XPLD5 + {SPR_BOM1, 5, 4, {NULL}, 0, 0, S_NULL}, // S_XPLD6 - {SPR_BOM1, FF_ANIMATE, 20, {NULL}, 3, 5, S_INVISIBLE}, // S_XPLD_EGGTRAP + {SPR_BOM1, FF_ANIMATE, 21, {NULL}, 5, 4, S_INVISIBLE}, // S_XPLD_EGGTRAP // Underwater Explosion {SPR_BOM4, 0, 3, {A_Scream}, 0, 0, S_WPLD2}, // S_WPLD1 @@ -6386,8 +6389,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_RING_ICON, // damage @@ -6413,8 +6416,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_PITY_ICON, // damage @@ -6440,8 +6443,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_ATTRACT_ICON,// damage @@ -6467,8 +6470,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_FORCE_ICON, // damage @@ -6494,8 +6497,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_ARMAGEDDON_ICON, // damage @@ -6521,8 +6524,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_WHIRLWIND_ICON, // damage @@ -6548,8 +6551,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_ELEMENTAL_ICON, // damage @@ -6575,8 +6578,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_SNEAKERS_ICON, // damage @@ -6602,8 +6605,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_INVULN_ICON, // damage @@ -6629,8 +6632,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_1UP_ICON, // damage @@ -6656,8 +6659,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_EGGMAN_ICON, // damage @@ -6683,8 +6686,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_MIXUP_ICON, // damage @@ -6710,8 +6713,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_UNKNOWN, // damage @@ -6737,8 +6740,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_GRAVITY_ICON, // damage @@ -6764,8 +6767,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_RECYCLER_ICON, // damage @@ -6791,8 +6794,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_SCORE1K_ICON, // damage @@ -6818,8 +6821,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_SCORE10K_ICON, // damage @@ -6845,8 +6848,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_FLAMEAURA_ICON, // damage @@ -6872,8 +6875,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_BUBBLEWRAP_ICON, // damage @@ -6899,8 +6902,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_THUNDERCOIN_ICON, // damage @@ -6926,8 +6929,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_PITY_ICON, // damage @@ -6953,8 +6956,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_ATTRACT_ICON,// damage @@ -6980,8 +6983,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_FORCE_ICON, // damage @@ -7007,8 +7010,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_ARMAGEDDON_ICON, // damage @@ -7034,8 +7037,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_WHIRLWIND_ICON, // damage @@ -7061,8 +7064,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_ELEMENTAL_ICON, // damage @@ -7088,8 +7091,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_SNEAKERS_ICON, // damage @@ -7115,8 +7118,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_INVULN_ICON, // damage @@ -7142,8 +7145,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_EGGMAN_ICON, // damage @@ -7169,8 +7172,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_GRAVITY_ICON, // damage @@ -7196,8 +7199,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_FLAMEAURA_ICON, // damage @@ -7223,8 +7226,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_BUBBLEWRAP_ICON, // damage @@ -7250,8 +7253,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 36*FRACUNIT, // height + 20*FRACUNIT, // radius + 44*FRACUNIT, // height 0, // display offset 100, // mass MT_THUNDERCOIN_ICON, // damage @@ -7277,8 +7280,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_RING_ICON, // damage @@ -7304,8 +7307,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 18*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 100, // mass MT_RING_ICON, // damage diff --git a/src/info.h b/src/info.h index 35a3f5f15..f9052b5da 100644 --- a/src/info.h +++ b/src/info.h @@ -1834,6 +1834,7 @@ typedef enum state S_BOXSPARKLE1, S_BOXSPARKLE2, S_BOXSPARKLE3, + S_BOXSPARKLE4, S_BOX_FLICKER, S_BOX_POP1, @@ -2826,8 +2827,6 @@ typedef enum state // Got Flag Sign S_GOTFLAG, - S_GOTREDFLAG, - S_GOTBLUEFLAG, S_CORK, @@ -3167,6 +3166,10 @@ typedef enum state S_XPLD_FLICKY, S_XPLD1, S_XPLD2, + S_XPLD3, + S_XPLD4, + S_XPLD5, + S_XPLD6, S_XPLD_EGGTRAP, // Underwater Explosion diff --git a/src/m_cheat.c b/src/m_cheat.c index a4eaede3a..174e2780d 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1266,7 +1266,7 @@ void Command_ObjectPlace_f(void) if (!COM_CheckParm("-silent")) { - HU_SetCEchoFlags(V_RETURN8|V_MONOSPACE); + HU_SetCEchoFlags(V_RETURN8|V_MONOSPACE|V_AUTOFADEOUT); HU_SetCEchoDuration(10); HU_DoCEcho(va(M_GetText( "\\\\\\\\\\\\\\\\\\\\\\\\\x82" diff --git a/src/m_menu.c b/src/m_menu.c index e53d9012f..4857df104 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1196,24 +1196,25 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Show HUD", &cv_showhud, 61}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "HUD Transparency", &cv_translucenthud, 66}, - {IT_STRING | IT_CVAR, NULL, "Time Display", &cv_timetic, 71}, + {IT_STRING | IT_CVAR, NULL, "Score/Time/Rings", &cv_timetic, 71}, + {IT_STRING | IT_CVAR, NULL, "Show Powerups", &cv_powerupdisplay, 76}, #ifdef SEENAMES - {IT_STRING | IT_CVAR, NULL, "Show player names", &cv_seenames, 76}, + {IT_STRING | IT_CVAR, NULL, "Show player names", &cv_seenames, 81}, #endif - {IT_HEADER, NULL, "Console", NULL, 85}, - {IT_STRING | IT_CVAR, NULL, "Background color", &cons_backcolor, 91}, - {IT_STRING | IT_CVAR, NULL, "Text Size", &cv_constextsize, 96}, + {IT_HEADER, NULL, "Console", NULL, 90}, + {IT_STRING | IT_CVAR, NULL, "Background color", &cons_backcolor, 96}, + {IT_STRING | IT_CVAR, NULL, "Text Size", &cv_constextsize, 101}, - {IT_HEADER, NULL, "Level", NULL, 105}, - {IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 111}, - {IT_STRING | IT_CVAR, NULL, "NiGHTS Draw Dist.", &cv_drawdist_nights, 116}, - {IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 121}, - {IT_STRING | IT_CVAR, NULL, "Weather Density", &cv_precipdensity, 126}, + {IT_HEADER, NULL, "Level", NULL, 110}, + {IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 116}, + {IT_STRING | IT_CVAR, NULL, "NiGHTS Draw Dist.", &cv_drawdist_nights, 121}, + {IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.", &cv_drawdist_precip, 126}, + {IT_STRING | IT_CVAR, NULL, "Weather Density", &cv_precipdensity, 131}, - {IT_HEADER, NULL, "Diagnostic", NULL, 135}, - {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 141}, - {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 146}, + {IT_HEADER, NULL, "Diagnostic", NULL, 140}, + {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 146}, + {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 151}, }; static menuitem_t OP_VideoModeMenu[] = diff --git a/src/p_inter.c b/src/p_inter.c index 4c9e231fe..833a9ba52 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3365,8 +3365,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da P_KillPlayer(player, source, damage); } - P_HitDeathMessages(player, inflictor, source, damagetype); - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); } @@ -3381,6 +3379,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da else target->health -= damage; + if (player) + P_HitDeathMessages(player, inflictor, source, damagetype); + if (source && source->player && target) G_GhostAddHit(target); diff --git a/src/p_spec.c b/src/p_spec.c index 0b005baff..595473a5c 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -31,6 +31,7 @@ #include "p_polyobj.h" #include "p_slopes.h" #include "hu_stuff.h" +#include "v_video.h" // V_AUTOFADEOUT|V_ALLOWLOWERCASE #include "m_misc.h" #include "m_cond.h" //unlock triggers #include "lua_hook.h" // LUAh_LinedefExecute @@ -3815,9 +3816,9 @@ DoneSection2: if (!P_IsFlagAtBase(MT_REDFLAG)) break; - HU_SetCEchoFlags(0); + HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE); HU_SetCEchoDuration(5); - HU_DoCEcho(va(M_GetText("%s\\captured the blue flag.\\\\\\\\"), player_names[player-players])); + HU_DoCEcho(va(M_GetText("%s%s%s\\CAPTURED THE %sBLUE FLAG%s.\\\\\\\\"), "\x85", player_names[player-players], "\x80", "\x84", "\x80")); if (splitscreen || players[consoleplayer].ctfteam == 1) S_StartSound(NULL, sfx_flgcap); @@ -3848,9 +3849,9 @@ DoneSection2: if (!P_IsFlagAtBase(MT_BLUEFLAG)) break; - HU_SetCEchoFlags(0); + HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE); HU_SetCEchoDuration(5); - HU_DoCEcho(va(M_GetText("%s\\captured the red flag.\\\\\\\\"), player_names[player-players])); + HU_DoCEcho(va(M_GetText("%s%s%s\\CAPTURED THE %sRED FLAG%s.\\\\\\\\"), "\x84", player_names[player-players], "\x80", "\x85", "\x80")); if (splitscreen || players[consoleplayer].ctfteam == 2) S_StartSound(NULL, sfx_flgcap); diff --git a/src/p_user.c b/src/p_user.c index d127e7139..86eb1bef4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2585,13 +2585,11 @@ static void P_DoPlayerHeadSigns(player_t *player) } else sign->z += P_GetPlayerHeight(player)+FixedMul(16*FRACUNIT, player->mo->scale); - if (leveltime & 4) - { - if (player->gotflag & GF_REDFLAG) - P_SetMobjStateNF(sign, S_GOTREDFLAG); - } - else if (player->gotflag & GF_BLUEFLAG) - P_SetMobjStateNF(sign, S_GOTBLUEFLAG); + + if (player->gotflag & GF_REDFLAG) + sign->frame = 1|FF_FULLBRIGHT; + else //if (player->gotflag & GF_BLUEFLAG) + sign->frame = 2|FF_FULLBRIGHT; } } } diff --git a/src/screen.c b/src/screen.c index 5120aa581..5b16992c7 100644 --- a/src/screen.c +++ b/src/screen.c @@ -440,6 +440,18 @@ void SCR_ClosedCaptions(void) { UINT8 i; boolean gamestopped = (paused || P_AutoPause()); + INT32 basey = BASEVIDHEIGHT; + + if (gamestate == GS_LEVEL) + { + if (splitscreen) + basey -= 8; + else if (((maptol & TOL_NIGHTS) && (modeattacking == ATTACKING_NIGHTS)) + || (cv_powerupdisplay.value == 2) + || (cv_powerupdisplay.value == 1 && ((stplyr == &players[displayplayer] && !camera.chase) + || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)))) + basey -= 16; + } for (i = 0; i < NUMCAPTIONS; i++) { @@ -456,7 +468,7 @@ void SCR_ClosedCaptions(void) continue; flags = V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_ALLOWLOWERCASE; - y = BASEVIDHEIGHT-((i + 2)*10); + y = basey-((i + 2)*10); if (closedcaptions[i].b) y -= (closedcaptions[i].b--)*vid.dupy; diff --git a/src/sounds.c b/src/sounds.c index 475d65cd1..293ce381d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -85,14 +85,14 @@ sfxinfo_t S_sfx[NUMSFX] = {"athun1", false, 16, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Thunder"}, {"athun2", false, 16, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Thunder"}, - {"amwtr1", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, - {"amwtr2", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, - {"amwtr3", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, - {"amwtr4", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, - {"amwtr5", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, - {"amwtr6", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, - {"amwtr7", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, - {"amwtr8", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running water"}, + {"amwtr1", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, + {"amwtr2", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, + {"amwtr3", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, + {"amwtr4", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, + {"amwtr5", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, + {"amwtr6", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, + {"amwtr7", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, + {"amwtr8", false, 12, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Stream"}, {"bubbl1", false, 11, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Glub"}, {"bubbl2", false, 11, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Glub"}, {"bubbl3", false, 11, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Glub"}, diff --git a/src/st_stuff.c b/src/st_stuff.c index 93709e453..25a61fa3a 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -101,6 +101,7 @@ static patch_t *invincibility; static patch_t *sneakers; static patch_t *gravboots; static patch_t *nonicon; +static patch_t *nonicon2; static patch_t *bluestat; static patch_t *byelstat; static patch_t *orngstat; @@ -150,7 +151,7 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 130, 93, 0}, // HUD_TIMEUP { 152, 168, 0}, // HUD_HUNTPICS - { 152, 24, V_SNAPTORIGHT}, // HUD_GRAVBOOTSICO + { 288, 176, V_SNAPTORIGHT|V_SNAPTOBOTTOM}, // HUD_POWERUPS }; // @@ -275,18 +276,18 @@ void ST_LoadGraphics(void) scatterring = W_CachePatchName("SCATIND", PU_HUDGFX); grenadering = W_CachePatchName("GRENIND", PU_HUDGFX); railring = W_CachePatchName("RAILIND", PU_HUDGFX); - jumpshield = W_CachePatchName("TVWWC0", PU_HUDGFX); - forceshield = W_CachePatchName("TVFOC0", PU_HUDGFX); - ringshield = W_CachePatchName("TVATC0", PU_HUDGFX); - watershield = W_CachePatchName("TVELC0", PU_HUDGFX); - bombshield = W_CachePatchName("TVARC0", PU_HUDGFX); - pityshield = W_CachePatchName("TVPIC0", PU_HUDGFX); - flameshield = W_CachePatchName("TVFLC0", PU_HUDGFX); - bubbleshield = W_CachePatchName("TVBBC0", PU_HUDGFX); - thundershield = W_CachePatchName("TVZPC0", PU_HUDGFX); - invincibility = W_CachePatchName("TVIVC0", PU_HUDGFX); - sneakers = W_CachePatchName("TVSSC0", PU_HUDGFX); - gravboots = W_CachePatchName("TVGVC0", PU_HUDGFX); + jumpshield = W_CachePatchName("TVWWICON", PU_HUDGFX); + forceshield = W_CachePatchName("TVFOICON", PU_HUDGFX); + ringshield = W_CachePatchName("TVATICON", PU_HUDGFX); + watershield = W_CachePatchName("TVELICON", PU_HUDGFX); + bombshield = W_CachePatchName("TVARICON", PU_HUDGFX); + pityshield = W_CachePatchName("TVPIICON", PU_HUDGFX); + flameshield = W_CachePatchName("TVFLICON", PU_HUDGFX); + bubbleshield = W_CachePatchName("TVBBICON", PU_HUDGFX); + thundershield = W_CachePatchName("TVZPICON", PU_HUDGFX); + invincibility = W_CachePatchName("TVIVICON", PU_HUDGFX); + sneakers = W_CachePatchName("TVSSICON", PU_HUDGFX); + gravboots = W_CachePatchName("TVGVICON", PU_HUDGFX); tagico = W_CachePatchName("TAGICO", PU_HUDGFX); rflagico = W_CachePatchName("RFLAGICO", PU_HUDGFX); @@ -296,6 +297,7 @@ void ST_LoadGraphics(void) gotrflag = W_CachePatchName("GOTRFLAG", PU_HUDGFX); gotbflag = W_CachePatchName("GOTBFLAG", PU_HUDGFX); nonicon = W_CachePatchName("NONICON", PU_HUDGFX); + nonicon2 = W_CachePatchName("NONICON2", PU_HUDGFX); // NiGHTS HUD things bluestat = W_CachePatchName("BLUESTAT", PU_HUDGFX); @@ -644,7 +646,7 @@ static void ST_drawTime(void) if (!tics && downwards && (leveltime/5 & 1)) // overtime! return; - if (cv_timetic.value == 1) // Tics only -- how simple is this? + if (cv_timetic.value == 3) // Tics only -- how simple is this? ST_DrawNumFromHud(HUD_SECONDS, tics, V_HUDTRANS); else { @@ -652,7 +654,7 @@ static void ST_drawTime(void) ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon, V_HUDTRANS); // Colon ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2, V_HUDTRANS); // Seconds - if (cv_timetic.value == 2 || cv_timetic.value == 3 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! + if (cv_timetic.value == 1 || cv_timetic.value == 2 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! { ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod, V_HUDTRANS); // Period ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2, V_HUDTRANS); // Tics @@ -679,7 +681,7 @@ static inline void ST_drawRings(void) else ringnum = max(stplyr->rings, 0); - if (cv_timetic.value == 3) // Yes, even in modeattacking + if (cv_timetic.value == 2) // Yes, even in modeattacking ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); else ST_DrawNumFromHud(HUD_RINGSNUM, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); @@ -1128,93 +1130,160 @@ static void ST_drawLevelTitle(void) V_DrawCenteredString(subttlxpos, lvlttly+48, V_ALLOWLOWERCASE, subttl); } -static void ST_drawFirstPersonHUD(void) +static void ST_drawPowerupHUD(void) { - player_t *player = stplyr; patch_t *p = NULL; UINT16 invulntime = 0; + INT32 offs = hudinfo[HUD_POWERUPS].x; + static INT32 flagoffs = 0, shieldoffs = 0; +#define ICONSEP (16+4) // matches weapon rings HUD - if (player->playerstate != PST_LIVE) + if (stplyr->spectator || stplyr->playerstate != PST_LIVE) return; // Graue 06-18-2004: no V_NOSCALESTART, no SCX, no SCY, snap to right - if ((player->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE) + if (stplyr->powers[pw_shield] & SH_NOSTACK) { - UINT8 i, max = (player->powers[pw_shield] & SH_FORCEHP); - for (i = 0; i <= max; i++) + shieldoffs = ICONSEP; + + if ((stplyr->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE) { - V_DrawScaledPatch(304-(3*i), 24+(3*i), (V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP)|((i == max) ? V_HUDTRANS : V_HUDTRANSHALF), forceshield); + UINT8 i, max = (stplyr->powers[pw_shield] & SH_FORCEHP); + for (i = 0; i <= max; i++) + { + V_DrawSmallScaledPatch(offs-(i<<1), hudinfo[HUD_POWERUPS].y-(i<<1), (V_PERPLAYER|hudinfo[HUD_POWERUPS].f)|((i == max) ? V_HUDTRANS : V_HUDTRANSHALF), forceshield); + } + } + else + { + switch (stplyr->powers[pw_shield] & SH_NOSTACK) + { + case SH_WHIRLWIND: p = jumpshield; break; + case SH_ELEMENTAL: p = watershield; break; + case SH_ARMAGEDDON: p = bombshield; break; + case SH_ATTRACT: p = ringshield; break; + case SH_PITY: p = pityshield; break; + case SH_FLAMEAURA: p = flameshield; break; + case SH_BUBBLEWRAP: p = bubbleshield; break; + case SH_THUNDERCOIN: p = thundershield; break; + default: break; + } + + if (p) + V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, p); } } - else switch (player->powers[pw_shield] & SH_NOSTACK) + else if (shieldoffs) { - case SH_WHIRLWIND: p = jumpshield; break; - case SH_ELEMENTAL: p = watershield; break; - case SH_ARMAGEDDON: p = bombshield; break; - case SH_ATTRACT: p = ringshield; break; - case SH_PITY: p = pityshield; break; - case SH_FLAMEAURA: p = flameshield; break; - case SH_BUBBLEWRAP: p = bubbleshield; break; - case SH_THUNDERCOIN: p = thundershield; break; - default: break; - } - - if (p) - V_DrawScaledPatch(304, 24, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); - - // pw_flashing just sets the icon to flash no matter what. - invulntime = player->powers[pw_flashing] ? 1 : player->powers[pw_invulnerability]; - if (invulntime > 3*TICRATE || (invulntime && leveltime & 1)) - V_DrawScaledPatch(304, 24 + 28, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, invincibility); - - if (player->powers[pw_sneakers] > 3*TICRATE || (player->powers[pw_sneakers] && leveltime & 1)) - { - V_DrawScaledPatch(304, 24 + 56, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, sneakers); - } - - p = NULL; - - { - UINT32 airtime; - UINT32 frame = 0; - spriteframe_t *sprframe; - // If both air timers are active, use the air timer with the least time left - if (player->powers[pw_underwater] && player->powers[pw_spacetime]) - airtime = min(player->powers[pw_underwater], player->powers[pw_spacetime]); - else // Use whichever one is active otherwise - airtime = (player->powers[pw_spacetime]) ? player->powers[pw_spacetime] : player->powers[pw_underwater]; - - if (!airtime) - return; // No air timers are active, nothing would be drawn anyway - - airtime--; // The original code was all n*TICRATE + 1, so let's remove 1 tic for simplicity - - if (airtime > 11*TICRATE) - return; // Not time to draw any drown numbers yet - // Choose which frame to use based on time left - if (airtime <= 11*TICRATE && airtime >= 10*TICRATE) - frame = 5; - else if (airtime <= 9*TICRATE && airtime >= 8*TICRATE) - frame = 4; - else if (airtime <= 7*TICRATE && airtime >= 6*TICRATE) - frame = 3; - else if (airtime <= 5*TICRATE && airtime >= 4*TICRATE) - frame = 2; - else if (airtime <= 3*TICRATE && airtime >= 2*TICRATE) - frame = 1; - else if (airtime <= 1*TICRATE && airtime > 0) - frame = 0; + if (shieldoffs > 1) + shieldoffs = 2*shieldoffs/3; else - return; // Don't draw anything between numbers - - if (player->charflags & SF_MACHINE) - frame += 6; // Robots use different drown numbers - - // Get the front angle patch for the frame - sprframe = &sprites[SPR_DRWN].spriteframes[frame]; - p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + shieldoffs = 0; } + offs -= shieldoffs; + + // YOU have a flag. Display a monitor-like icon for it. + if (stplyr->gotflag) + { + flagoffs = ICONSEP; + p = (stplyr->gotflag & GF_REDFLAG) ? gotrflag : gotbflag; + V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, p); + } + else if (flagoffs) + { + if (flagoffs > 1) + flagoffs = 2*flagoffs/3; + else + flagoffs = 0; + } + + offs -= flagoffs; + + invulntime = stplyr->powers[pw_flashing] ? stplyr->powers[pw_flashing] : stplyr->powers[pw_invulnerability]; + if (stplyr->powers[pw_invulnerability] > 3*TICRATE || (invulntime && leveltime & 1)) + { + V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, invincibility); + V_DrawRightAlignedThinString(offs + 16, hudinfo[HUD_POWERUPS].y + 8, V_PERPLAYER|hudinfo[HUD_POWERUPS].f, va("%d", invulntime/TICRATE)); + } + + if (invulntime > 7) + offs -= ICONSEP; + else + { + UINT8 a = ICONSEP, b = 7-invulntime; + while (b--) + a = 2*a/3; + offs -= a; + } + + if (stplyr->powers[pw_sneakers] > 3*TICRATE || (stplyr->powers[pw_sneakers] && leveltime & 1)) + { + V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, sneakers); + V_DrawRightAlignedThinString(offs + 16, hudinfo[HUD_POWERUPS].y + 8, V_PERPLAYER|hudinfo[HUD_POWERUPS].f, va("%d", stplyr->powers[pw_sneakers]/TICRATE)); + } + + if (stplyr->powers[pw_sneakers] > 7) + offs -= ICONSEP; + else + { + UINT8 a = ICONSEP, b = 7-stplyr->powers[pw_sneakers]; + while (b--) + a = 2*a/3; + offs -= a; + } + + if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1)) + { + V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, gravboots); + V_DrawRightAlignedThinString(offs + 16, hudinfo[HUD_POWERUPS].y + 8, V_PERPLAYER|hudinfo[HUD_POWERUPS].f, va("%d", stplyr->powers[pw_gravityboots]/TICRATE)); + } + +#undef ICONSEP +} + +static void ST_drawFirstPersonHUD(void) +{ + patch_t *p = NULL; + UINT32 airtime; + UINT32 frame = 0; + spriteframe_t *sprframe; + // If both air timers are active, use the air timer with the least time left + if (stplyr->powers[pw_underwater] && stplyr->powers[pw_spacetime]) + airtime = min(stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime]); + else // Use whichever one is active otherwise + airtime = (stplyr->powers[pw_spacetime]) ? stplyr->powers[pw_spacetime] : stplyr->powers[pw_underwater]; + + if (!airtime) + return; // No air timers are active, nothing would be drawn anyway + + airtime--; // The original code was all n*TICRATE + 1, so let's remove 1 tic for simplicity + + if (airtime > 11*TICRATE) + return; // Not time to draw any drown numbers yet + // Choose which frame to use based on time left + if (airtime <= 11*TICRATE && airtime >= 10*TICRATE) + frame = 5; + else if (airtime <= 9*TICRATE && airtime >= 8*TICRATE) + frame = 4; + else if (airtime <= 7*TICRATE && airtime >= 6*TICRATE) + frame = 3; + else if (airtime <= 5*TICRATE && airtime >= 4*TICRATE) + frame = 2; + else if (airtime <= 3*TICRATE && airtime >= 2*TICRATE) + frame = 1; + else if (airtime <= 1*TICRATE && airtime > 0) + frame = 0; + else + return; // Don't draw anything between numbers + + if (stplyr->charflags & SF_MACHINE) + frame += 6; // Robots use different drown numbers + + // Get the front angle patch for the frame + sprframe = &sprites[SPR_DRWN].spriteframes[frame]; + p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + // Display the countdown drown numbers! if (p) V_DrawScaledPatch((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset), @@ -1674,7 +1743,7 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I if (weapon == pw_infinityring || (stplyr->ringweapons & rwflag)) - txtflags |= V_20TRANS; + ; //txtflags |= V_20TRANS; else { txtflags |= V_TRANSLUCENT; @@ -1683,10 +1752,10 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I V_DrawScaledPatch(8 + xoffs, y, V_PERPLAYER|V_SNAPTOBOTTOM|patflags, pat); - if (stplyr->powers[weapon] > 99) - V_DrawThinString(8 + xoffs + 1, y, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon])); - else - V_DrawString(8 + xoffs, y, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon])); + //if (stplyr->powers[weapon] > 9) + V_DrawRightAlignedThinString(24 + xoffs, y + 8, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon])); + /*else + V_DrawRightAlignedString(24 + xoffs, y + 8, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon]));*/ if (stplyr->currentweapon == wepflag) V_DrawScaledPatch(6 + xoffs, y-2, V_PERPLAYER|V_SNAPTOBOTTOM, curweapon); @@ -1756,57 +1825,67 @@ static void ST_drawTagHUD(void) { sprintf(pstext, "%s", M_GetText("You cannot move while hiding.")); if (!splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); + V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); } // Print the stuff. if (pstext[0]) - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER, pstext); + V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, pstext); } -static void ST_drawCTFHUD(void) +static void ST_drawTeamHUD(void) { - INT32 i, y = 176; - UINT16 whichflag = 0; + patch_t *p; +#define SEP 20 - // Draw the flags - V_DrawSmallScaledPatch(256, y, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, rflagico); - V_DrawSmallScaledPatch(280, y, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, bflagico); + if (gametype == GT_CTF) + p = bflagico; + else + p = bmatcico; - for (i = 0; i < MAXPLAYERS; i++) + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); + + if (gametype == GT_CTF) + p = rflagico; + else + p = rmatcico; + + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); + + if (gametype != GT_CTF) + goto num; { - if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base - V_DrawScaledPatch(256, y-4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, nonicon); - else if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base - V_DrawScaledPatch(280, y-4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, nonicon); + INT32 i; + UINT16 whichflag = 0; - whichflag |= players[i].gotflag; - if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG)) - break; // both flags were found, let's stop early - } - - // YOU have a flag. Display a monitor-like icon for it. - if (stplyr->gotflag) - { - patch_t *p = (stplyr->gotflag & GF_REDFLAG) ? gotrflag : gotbflag; - V_DrawScaledPatch(304, 24 + 84, V_PERPLAYER|V_SNAPTORIGHT|V_SNAPTOTOP|V_HUDTRANS, p); - } - - // Display a countdown timer showing how much time left until the flag your team dropped returns to base. - { - char timeleft[33]; - if (redflag && redflag->fuse > 1) + // Show which flags aren't at base. + for (i = 0; i < MAXPLAYERS; i++) { - sprintf(timeleft, "%u", (redflag->fuse / TICRATE)); - V_DrawCenteredString(268, y+8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, timeleft); + if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base + V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(nonicon->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon); + if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base + V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2); + + whichflag |= players[i].gotflag; + if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG)) + break; // both flags were found, let's stop early } - if (blueflag && blueflag->fuse > 1) + // Display a countdown timer showing how much time left until the flag returns to base. { - sprintf(timeleft, "%u", (blueflag->fuse / TICRATE)); - V_DrawCenteredString(300, y+8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOBOTTOM|V_SNAPTORIGHT, timeleft); + if (blueflag && blueflag->fuse > 1) + V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (blueflag->fuse / TICRATE))); + + if (redflag && redflag->fuse > 1) + V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (redflag->fuse / TICRATE))); } } + +num: + V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", bluescore)); + V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore)); + +#undef SEP } static void ST_drawSpecialStageHUD(void) @@ -1815,7 +1894,7 @@ static void ST_drawSpecialStageHUD(void) { if (hudinfo[HUD_SS_TOTALRINGS].x) ST_DrawNumFromHud(HUD_SS_TOTALRINGS, totalrings, V_HUDTRANS); - else if (cv_timetic.value == 3) + else if (cv_timetic.value == 2) V_DrawTallNum(hudinfo[HUD_RINGSNUMTICS].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUMTICS].f|V_PERPLAYER|V_HUDTRANS, totalrings); else V_DrawTallNum(hudinfo[HUD_RINGSNUM].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUM].f|V_PERPLAYER|V_HUDTRANS, totalrings); @@ -2035,6 +2114,8 @@ static void ST_overlayDrawer(void) V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, BASEVIDHEIGHT/2 - (SHORT(p->height)/2), V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS), p); } + if (G_GametypeHasTeams()) + ST_drawTeamHUD(); if (!hu_showscores) // hide the following if TAB is held { @@ -2079,9 +2160,6 @@ static void ST_overlayDrawer(void) // Tag HUD Stuff else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) ST_drawTagHUD(); - // CTF HUD Stuff - else if (gametype == GT_CTF) - ST_drawCTFHUD(); // Special Stage HUD if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayer]) @@ -2093,9 +2171,6 @@ static void ST_overlayDrawer(void) else ST_doHuntIconsAndSound(); - if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1)) - V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, hudinfo[HUD_GRAVBOOTSICO].y, hudinfo[HUD_GRAVBOOTSICO].f|V_PERPLAYER, gravboots); - if(!P_IsLocalPlayer(stplyr)) { char name[MAXPLAYERNAME+1]; @@ -2109,10 +2184,14 @@ static void ST_overlayDrawer(void) // This is where we draw all the fun cheese if you have the chasecam off! if ((stplyr == &players[displayplayer] && !camera.chase) - || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)) + || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)) { ST_drawFirstPersonHUD(); + if (cv_powerupdisplay.value) + ST_drawPowerupHUD(); } + else if (cv_powerupdisplay.value == 2) + ST_drawPowerupHUD(); } #ifdef HAVE_BLUA @@ -2149,27 +2228,30 @@ static void ST_overlayDrawer(void) if (cv_playersforexit.value != 4) { total *= cv_playersforexit.value; - if (total % 4) total += 4; // round up + if (total & 3) + total += 4; // round up total /= 4; } if (exiting < total) { total -= exiting; - V_DrawCenteredString(BASEVIDWIDTH/2, 124, V_PERPLAYER, va(M_GetText("%d more player%s required to exit."), total, ((total == 1) ? "" : "s"))); + V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))); if (!splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); + { + V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); + } } } else if (!splitscreen && gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, 0, M_GetText("Press F12 to watch another player.")); + V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text. { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; if (respawntime > 0 && !stplyr->spectator) - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, va(M_GetText("Respawn in %d..."), respawntime)); + V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, va(M_GetText("Respawn in %d..."), respawntime)); else - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Jump to respawn.")); + V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""JUMP:""\x80 Respawn")); } else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE) #ifdef HAVE_BLUA @@ -2177,14 +2259,13 @@ static void ST_overlayDrawer(void) #endif ) { - V_DrawCenteredString(BASEVIDWIDTH/2, 60, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You are a spectator.")); - if (G_GametypeHasTeams()) - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to be assigned to a team.")); - else if (G_IsSpecialStage(gamemap) && useNightsSS) - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You cannot play until the stage has ended.")); - else if (gametype == GT_COOP && stplyr->lives <= 0) + INT32 y = 176 - 16; // HUD_LIVES + if (G_IsSpecialStage(gamemap) && useNightsSS) + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_YELLOWMAP, M_GetText("Wait for the stage to end...")); + else if (gametype == GT_COOP) { - if (cv_cooplives.value == 2 + if (stplyr->lives <= 0 + && cv_cooplives.value == 2 && (netgame || multiplayer)) { INT32 i; @@ -2201,14 +2282,26 @@ static void ST_overlayDrawer(void) } if (i != MAXPLAYERS) - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("You'll steal a life on respawn.")); + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("You'll steal a life on respawn...")); + else + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Wait to respawn...")); } + else + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Wait to respawn...")); } - else if (gametype != GT_COOP) - V_DrawCenteredString(BASEVIDWIDTH/2, 164, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Fire to enter the game.")); + else + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""FIRE:""\x80 Enter game")); + y -= 8; + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""SPIN:""\x80 Sink")); + y -= 8; + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""JUMP:""\x80 Float")); + y -= 8; if (!splitscreen) - V_DrawCenteredString(BASEVIDWIDTH/2, 132, V_HUDTRANSHALF, M_GetText("Press F12 to watch another player.")); - V_DrawCenteredString(BASEVIDWIDTH/2, 148, V_PERPLAYER|V_HUDTRANSHALF, M_GetText("Press Jump to float and Spin to sink.")); + { + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); + y -= 8; + } + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_GRAYMAP, M_GetText("Spectator mode:")); } } @@ -2252,6 +2345,24 @@ void ST_Drawer(void) #endif if (rendermode != render_none) ST_doPaletteStuff(); + // Blindfold! + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + && (leveltime < hidetime * TICRATE)) + { + if (players[displayplayer].pflags & PF_TAGIT) + { + stplyr = &players[displayplayer]; + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31|V_PERPLAYER); + V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_YELLOWMAP, M_GetText("You are blindfolded!")); + } + else if (splitscreen && players[secondarydisplayplayer].pflags & PF_TAGIT) + { + stplyr = &players[secondarydisplayplayer]; + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31|V_PERPLAYER); + V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_YELLOWMAP, M_GetText("You are blindfolded!")); + } + } + if (st_overlay) { // No deadview! diff --git a/src/st_stuff.h b/src/st_stuff.h index df1ac6433..df0adace3 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -101,7 +101,7 @@ typedef enum HUD_TIMELEFTNUM, HUD_TIMEUP, HUD_HUNTPICS, - HUD_GRAVBOOTSICO, + HUD_POWERUPS, NUMHUDITEMS } hudnum_t; From fc3e863fd3a371df6c21fcc222a656780df5bab0 Mon Sep 17 00:00:00 2001 From: Nevur Date: Thu, 29 Mar 2018 20:12:19 +0200 Subject: [PATCH 081/212] asdf Signed-off-by: Nevur --- src/p_slopes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_slopes.c b/src/p_slopes.c index f480b6e4f..7c84a2db5 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -251,7 +251,7 @@ void P_SpawnSlope_Line(int linenum) UINT8 flags = 0; // Slope flags if (line->flags & ML_NOSONIC) flags |= SL_NOPHYSICS; - if (line->flags & ML_NOTAILS) + if (!(line->flags & ML_NOTAILS)) flags |= SL_NODYNAMIC; if (line->flags & ML_NOKNUX) flags |= SL_ANCHORVERTEX; From 65c893da86e23bc3c75aeb16a4d4ec1cdebdc79d Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 29 Mar 2018 23:28:54 +0100 Subject: [PATCH 082/212] static tempsec for R_FakeFlat I don't fully understand this, but it's what software does and it fixes the issue of the lighting in DSZ3. Also don't need the extra call to R_Prep3DFloors. --- src/hardware/hw_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 86b80904f..a0ea9b47a 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2676,7 +2676,7 @@ static void HWR_AddLine(seg_t * line) angle_t span, tspan; // SoM: Backsector needs to be run through R_FakeFlat - sector_t tempsec; + static sector_t tempsec; if (line->polyseg && !(line->polyseg->flags & POF_RENDERSIDES)) return; @@ -3235,7 +3235,7 @@ static void HWR_Subsector(size_t num) INT16 count; seg_t *line; subsector_t *sub; - sector_t tempsec; //SoM: 4/7/2000 + static sector_t tempsec; //SoM: 4/7/2000 INT32 floorlightlevel; INT32 ceilinglightlevel; INT32 locFloorHeight, locCeilingHeight; @@ -3418,8 +3418,6 @@ static void HWR_Subsector(size_t num) { /// \todo fix light, xoffs, yoffs, extracolormap ? ffloor_t * rover; - - R_Prep3DFloors(gr_frontsector); for (rover = gr_frontsector->ffloors; rover; rover = rover->next) { From de8f1fa407beede452ad5d391f92a288c4b70cc3 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 30 Mar 2018 16:39:59 +0100 Subject: [PATCH 083/212] * Incorporate (almost) all of Mystic's feedback. * Prevent ANY input when blindfolded. * Make CECHOs always perplayer'd. (A little hacky; quads will need work here.) * Make NiGHTS link timer bounces not a mess, and only when the colour changes. --- src/g_game.c | 4 +- src/hu_stuff.c | 8 +- src/p_user.c | 2 +- src/st_stuff.c | 484 ++++++++++++++++++++++++++----------------------- 4 files changed, 264 insertions(+), 234 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 9db9c413b..984b1ec40 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -888,7 +888,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // why build a ticcmd if we're paused? // Or, for that matter, if we're being reborn. - if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN)) + // ...OR if we're blindfolded. No looking into the floor. + if (paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + && (leveltime < hidetime * TICRATE) && (player->pflags & PF_TAGIT))))) { cmd->angleturn = (INT16)(localangle >> 16); cmd->aiming = G_ClipAimingPitch(&localaiming); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index c955a490d..a13801388 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -947,7 +947,7 @@ static void HU_DrawCEcho(void) INT32 y = (BASEVIDHEIGHT/2)-4; INT32 pnumlines = 0; - UINT32 realflags = cechoflags; + UINT32 realflags = cechoflags|V_PERPLAYER; // requested as part of splitscreen's stuff INT32 realalpha = (INT32)((cechoflags & V_ALPHAMASK) >> V_ALPHASHIFT); char *line; @@ -990,6 +990,12 @@ static void HU_DrawCEcho(void) *line = '\0'; V_DrawCenteredString(BASEVIDWIDTH/2, y, realflags, echoptr); + if (splitscreen) + { + stplyr = ((stplyr == &players[displayplayer]) ? &players[secondarydisplayplayer] : &players[displayplayer]); + V_DrawCenteredString(BASEVIDWIDTH/2, y, realflags, echoptr); + stplyr = ((stplyr == &players[displayplayer]) ? &players[secondarydisplayplayer] : &players[displayplayer]); + } y += ((realflags & V_RETURN8) ? 8 : 12); echoptr = line; diff --git a/src/p_user.c b/src/p_user.c index 86eb1bef4..b8634afa8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9709,7 +9709,7 @@ void P_PlayerThink(player_t *player) } } - if (player->linktimer && (player->linktimer >= (2*TICRATE - 1) || !player->powers[pw_nights_linkfreeze])) + if (player->linktimer && !player->powers[pw_nights_linkfreeze]) { if (--player->linktimer <= 0) // Link timer player->linkcount = 0; diff --git a/src/st_stuff.c b/src/st_stuff.c index 25a61fa3a..3ae212bc1 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -737,14 +737,19 @@ static void ST_drawLivesArea(void) } // Lives number - if (G_GametypeUsesLives()) + if (G_GametypeUsesLives() || gametype == GT_RACE) { // x V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10, hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, stlivex); // lives number - if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) + if (gametype == GT_RACE) + { + livescount = 0x7f; + notgreyedout = true; + } + else if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) { INT32 i; livescount = 0; @@ -788,58 +793,30 @@ static void ST_drawLivesArea(void) } // Spectator else if (stplyr->spectator) - { - //V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "SPECTATOR"); v_colmap = V_GRAYMAP; - } // Tag else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK) { if (stplyr->pflags & PF_TAGIT) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, (gametype == GT_HIDEANDSEEK) ? "SEEKER" : "IT!"); + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "IT!"); v_colmap = V_ORANGEMAP; } - else if (stplyr->pflags & PF_GAMETYPEOVER) - { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANSHALF|hudinfo[HUD_LIVES].f|V_PERPLAYER, "FAILED"); - v_colmap = V_GRAYMAP; - } - else - { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, (gametype == GT_HIDEANDSEEK) ? "HIDER" : "RUNNER"); - v_colmap = V_GREENMAP; - } } // Team name else if (G_GametypeHasTeams()) { if (stplyr->ctfteam == 1) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "RED"); + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "RED"); v_colmap = V_REDMAP; } else if (stplyr->ctfteam == 2) { - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "BLUE"); + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "BLUE"); v_colmap = V_BLUEMAP; } - else - v_colmap = V_GRAYMAP; } - else if (circuitmap) - { - if (stplyr->exiting) - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "FINISHED"); - //V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f|V_YELLOWMAP, "FINISHED!"); - else - { - V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, va("%u/%d", stplyr->laps+1, cv_numlaps.value)); - //V_DrawString(hudinfo[HUD_LAP].x, hudinfo[HUD_LAP].y, hudinfo[HUD_LAP].f, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value)); - } - } - /*else - V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "PLAYING");*/ // name v_colmap |= (V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER); @@ -1074,13 +1051,8 @@ static void ST_drawLevelTitle(void) char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl; char *subttl = mapheaderinfo[gamemap-1]->subttl; INT32 actnum = mapheaderinfo[gamemap-1]->actnum; - INT32 lvlttlxpos; + INT32 lvlttly, zoney, lvlttlxpos, ttlnumxpos, zonexpos; INT32 subttlxpos = BASEVIDWIDTH/2; - INT32 ttlnumxpos; - INT32 zonexpos; - - INT32 lvlttly; - INT32 zoney; if (!(timeinmap > 2 && timeinmap-3 < 110)) return; @@ -1095,10 +1067,41 @@ static void ST_drawLevelTitle(void) ttlnumxpos = lvlttlxpos + V_LevelNameWidth(lvlttl); zonexpos = ttlnumxpos - V_LevelNameWidth(M_GetText("ZONE")); + ttlnumxpos++; if (lvlttlxpos < 0) lvlttlxpos = 0; +#if 0 // toaster's experiment. srb2&toast.exe one day, maybe? Requires stuff below to be converted to fixed point. +#define MIDTTLY 79 +#define MIDZONEY 105 +#define MIDDIFF 4 + + if (timeinmap < 10) + { + fixed_t z = ((timeinmap - 3)<levelflags & LF_NOZONE)) - V_DrawLevelTitle(zonexpos, zoney, 0, M_GetText("ZONE")); + V_DrawLevelTitle(zonexpos, zoney, V_PERPLAYER, M_GetText("ZONE")); if (lvlttly+48 < 200) - V_DrawCenteredString(subttlxpos, lvlttly+48, V_ALLOWLOWERCASE, subttl); + V_DrawCenteredString(subttlxpos, lvlttly+48, V_PERPLAYER|V_ALLOWLOWERCASE, subttl); } static void ST_drawPowerupHUD(void) @@ -1135,7 +1139,8 @@ static void ST_drawPowerupHUD(void) patch_t *p = NULL; UINT16 invulntime = 0; INT32 offs = hudinfo[HUD_POWERUPS].x; - static INT32 flagoffs = 0, shieldoffs = 0; + const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0); + static INT32 flagoffs[2] = {0, 0}, shieldoffs[2] = {0, 0}; #define ICONSEP (16+4) // matches weapon rings HUD if (stplyr->spectator || stplyr->playerstate != PST_LIVE) @@ -1144,7 +1149,7 @@ static void ST_drawPowerupHUD(void) // Graue 06-18-2004: no V_NOSCALESTART, no SCX, no SCY, snap to right if (stplyr->powers[pw_shield] & SH_NOSTACK) { - shieldoffs = ICONSEP; + shieldoffs[q] = ICONSEP; if ((stplyr->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE) { @@ -1173,32 +1178,32 @@ static void ST_drawPowerupHUD(void) V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, p); } } - else if (shieldoffs) + else if (shieldoffs[q]) { - if (shieldoffs > 1) - shieldoffs = 2*shieldoffs/3; + if (shieldoffs[q] > 1) + shieldoffs[q] = 2*shieldoffs[q]/3; else - shieldoffs = 0; + shieldoffs[q] = 0; } - offs -= shieldoffs; + offs -= shieldoffs[q]; // YOU have a flag. Display a monitor-like icon for it. if (stplyr->gotflag) { - flagoffs = ICONSEP; + flagoffs[q] = ICONSEP; p = (stplyr->gotflag & GF_REDFLAG) ? gotrflag : gotbflag; V_DrawSmallScaledPatch(offs, hudinfo[HUD_POWERUPS].y, V_PERPLAYER|hudinfo[HUD_POWERUPS].f|V_HUDTRANS, p); } - else if (flagoffs) + else if (flagoffs[q]) { - if (flagoffs > 1) - flagoffs = 2*flagoffs/3; + if (flagoffs[q] > 1) + flagoffs[q] = 2*flagoffs[q]/3; else - flagoffs = 0; + flagoffs[q] = 0; } - offs -= flagoffs; + offs -= flagoffs[q]; invulntime = stplyr->powers[pw_flashing] ? stplyr->powers[pw_flashing] : stplyr->powers[pw_invulnerability]; if (stplyr->powers[pw_invulnerability] > 3*TICRATE || (invulntime && leveltime & 1)) @@ -1394,7 +1399,6 @@ static void ST_drawNiGHTSHUD(void) INT32 origamount; INT32 minlink = 1; INT32 total_ringcount; - boolean nosshack = false; // When debugging, show "0 Link". if (cv_debug & DBG_NIGHTSBASIC) @@ -1411,21 +1415,10 @@ static void ST_drawNiGHTSHUD(void) #endif stplyr->powers[pw_carry] == CR_NIGHTSMODE) { - INT32 locx, locy; + INT32 locx = 16, locy = 180; INT32 dfill; UINT8 fillpatch; - if (splitscreen) - { - locx = 110; - locy = 188; - } - else - { - locx = 16; - locy = 180; - } - // Use which patch? if (stplyr->pflags & PF_DRILLING) fillpatch = (stplyr->drillmeter & 1) + 1; @@ -1446,14 +1439,17 @@ static void ST_drawNiGHTSHUD(void) } } - if (G_IsSpecialStage(gamemap)) + /*if (G_IsSpecialStage(gamemap)) { // Since special stages share score, time, rings, etc. // disable splitscreen mode for its HUD. + // -------------------------------------- + // NOPE! Consistency between different splitscreen stuffs + // now we've got the screen squashing instead. ~toast if (stplyr != &players[displayplayer]) return; nosshack = splitscreen; splitscreen = false; - } + }*/ // Link drawing if ( @@ -1462,42 +1458,39 @@ static void ST_drawNiGHTSHUD(void) #endif stplyr->linkcount > minlink) { + static INT32 prevsel[2] = {0, 0}, prevtime[2] = {0, 0}; + const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0); + INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? 1 : 0); skincolors_t colornum; - INT32 aflag = V_PERPLAYER; fixed_t x, y, scale; + if (sel != prevsel[q]) + { + prevsel[q] = sel; + prevtime[q] = 2 + mag; + } + if (stplyr->powers[pw_nights_linkfreeze] && (!(stplyr->powers[pw_nights_linkfreeze] & 2) || (stplyr->powers[pw_nights_linkfreeze] > flashingtics))) colornum = SKINCOLOR_ICY; else - colornum = linkColor[((stplyr->linkcount-1 >= 300) ? 1 : 0)][((stplyr->linkcount-1) / 5) % NUMLINKCOLORS]; + colornum = linkColor[mag][sel]; aflag |= ((stplyr->linktimer < 2*TICRATE/3) ? (9 - 9*stplyr->linktimer/(2*TICRATE/3)) << V_ALPHASHIFT : 0); - y = (nosshack ? 16+11+(BASEVIDHEIGHT/2) : 160+11)<linktimer) - { - case (2*TICRATE): - scale = (36*FRACUNIT)/32; - break; - case (2*TICRATE - 1): - scale = (34*FRACUNIT)/32; - break; - default: - scale = FRACUNIT; - break; - } + scale = FRACUNIT; y -= (11*scale); @@ -1619,7 +1612,7 @@ static void ST_drawNiGHTSHUD(void) && LUA_HudEnabled(hud_nightsscore) #endif ) - ST_DrawNightsOverlayNum(304<marescore, nightsnum, SKINCOLOR_AZURE); + ST_DrawNightsOverlayNum(304<marescore, nightsnum, SKINCOLOR_AZURE); if (!stplyr->exiting #ifdef HAVE_BLUA @@ -1687,7 +1680,7 @@ static void ST_drawNiGHTSHUD(void) else numbersize = 48/2; - ST_DrawNightsOverlayNum((160 + numbersize)<weapondelay, del = 0, p = 16; + while (q) + { + if (q > p) + { + del += p; + q -= p; + q /= 2; + if (p > 1) + p /= 2; + } + else + { + del += q; + break; + } + } + V_DrawScaledPatch(6 + xoffs, y-2 - del/2, V_PERPLAYER|V_SNAPTOBOTTOM, curweapon); } static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, INT32 xoffs, INT32 y, patch_t *pat) @@ -1751,14 +1763,10 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I } V_DrawScaledPatch(8 + xoffs, y, V_PERPLAYER|V_SNAPTOBOTTOM|patflags, pat); - - //if (stplyr->powers[weapon] > 9) - V_DrawRightAlignedThinString(24 + xoffs, y + 8, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon])); - /*else - V_DrawRightAlignedString(24 + xoffs, y + 8, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon]));*/ + V_DrawRightAlignedThinString(24 + xoffs, y + 8, V_PERPLAYER|V_SNAPTOBOTTOM|txtflags, va("%d", stplyr->powers[weapon])); if (stplyr->currentweapon == wepflag) - V_DrawScaledPatch(6 + xoffs, y-2, V_PERPLAYER|V_SNAPTOBOTTOM, curweapon); + ST_drawWeaponSelect(xoffs, y); } else if (stplyr->ringweapons & rwflag) V_DrawScaledPatch(8 + xoffs, y, V_PERPLAYER|V_SNAPTOBOTTOM|V_TRANSLUCENT, pat); @@ -1778,13 +1786,16 @@ static void ST_drawMatchHUD(void) { if (stplyr->powers[pw_infinityring]) ST_drawWeaponRing(pw_infinityring, 0, 0, offset, y, infinityring); - else if (stplyr->rings > 0) - V_DrawScaledPatch(8 + offset, y, V_PERPLAYER|V_SNAPTOBOTTOM, normring); else - V_DrawTranslucentPatch(8 + offset, y, V_PERPLAYER|V_SNAPTOBOTTOM|V_80TRANS, normring); + { + if (stplyr->rings > 0) + V_DrawScaledPatch(8 + offset, y, V_PERPLAYER|V_SNAPTOBOTTOM, normring); + else + V_DrawTranslucentPatch(8 + offset, y, V_PERPLAYER|V_SNAPTOBOTTOM|V_80TRANS, normring); - if (!stplyr->currentweapon) - V_DrawScaledPatch(6 + offset, y-2, V_PERPLAYER|V_SNAPTOBOTTOM, curweapon); + if (!stplyr->currentweapon) + ST_drawWeaponSelect(offset, y); + } offset += 20; ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, y, autoring); @@ -1801,38 +1812,145 @@ static void ST_drawMatchHUD(void) } } +static void ST_drawTextHUD(void) +{ + INT32 y = 176 - 16; // HUD_LIVES + boolean dof12 = false, dospecheader = false; + +#define textHUDdraw(str) \ +{\ + V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, str);\ + y -= 8;\ +} + + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) + { + if (leveltime < hidetime * TICRATE) + { + if (stplyr->pflags & PF_TAGIT) + { + textHUDdraw(M_GetText("Waiting for players to hide...")) + textHUDdraw(M_GetText("\x82""You are blindfolded!")) + } + else if (gametype == GT_HIDEANDSEEK) + textHUDdraw(M_GetText("Hide before time runs out!")) + else + textHUDdraw(M_GetText("Flee before you are hunted!")) + } + else if (gametype == GT_HIDEANDSEEK && !(stplyr->pflags & PF_TAGIT)) + { + textHUDdraw(M_GetText("You cannot move while hiding.")) + dof12 = true; + } + } + + if (!stplyr->spectator && stplyr->exiting && cv_playersforexit.value && gametype == GT_COOP) + { + INT32 i, total = 0, exiting = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + if (players[i].lives <= 0) + continue; + + total++; + if (players[i].exiting) + exiting++; + } + + if (cv_playersforexit.value != 4) + { + total *= cv_playersforexit.value; + if (total & 3) + total += 4; // round up + total /= 4; + } + + if (exiting < total) + { + total -= exiting; + textHUDdraw(va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))) + dof12 = true; + } + } + else if (gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) + dof12 = true; + else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text. + { + INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; + + if (respawntime > 0 && !stplyr->spectator) + textHUDdraw(va(M_GetText("Respawn in %d..."), respawntime)) + else + textHUDdraw(M_GetText("\x82""JUMP:""\x80 Respawn")) + } + else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE)) + { + if (G_IsSpecialStage(gamemap) && useNightsSS) + textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) + else if (gametype == GT_COOP) + { + if (stplyr->lives <= 0 + && cv_cooplives.value == 2 + && (netgame || multiplayer)) + { + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (&players[i] == stplyr) + continue; + + if (players[i].lives > 1) + break; + } + + if (i != MAXPLAYERS) + textHUDdraw(M_GetText("You'll steal a life on respawn...")) + else + textHUDdraw(M_GetText("Wait to respawn...")) + } + else + textHUDdraw(M_GetText("Wait to respawn...")) + } + else + textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) + + textHUDdraw(M_GetText("\x82""SPIN:""\x80 Sink")) + textHUDdraw(M_GetText("\x82""JUMP:""\x80 Float")) + + dof12 = true; + dospecheader = true; + } + + if (!splitscreen && dof12) + textHUDdraw(M_GetText("\x82""F12:""\x80 Switch view")) + + if (circuitmap) + { + if (stplyr->exiting) + textHUDdraw(M_GetText("\x82""FINISHED!")) + else + textHUDdraw(va("Lap:""\x82 %u/%d", stplyr->laps+1, cv_numlaps.value)) + } + + if (dospecheader) + textHUDdraw(M_GetText("\x86""Spectator mode:")) + +#undef textHUDdraw + +} + static inline void ST_drawRaceHUD(void) { if (leveltime > TICRATE && leveltime <= 5*TICRATE) ST_drawRaceNum(4*TICRATE - leveltime); } -static void ST_drawTagHUD(void) -{ - char pstext[33] = ""; - - // Figure out what we're going to print. - if (leveltime < hidetime * TICRATE) //during the hide time, the seeker and hiders have different messages on their HUD. - { - if (stplyr->pflags & PF_TAGIT) - sprintf(pstext, "%s", M_GetText("Waiting for players to hide...")); - else if (gametype == GT_HIDEANDSEEK) //hide and seek. - sprintf(pstext, "%s", M_GetText("Hide before time runs out!")); - else //default - sprintf(pstext, "%s", M_GetText("Flee before you are hunted!")); - } - else if (gametype == GT_HIDEANDSEEK && !(stplyr->pflags & PF_TAGIT)) - { - sprintf(pstext, "%s", M_GetText("You cannot move while hiding.")); - if (!splitscreen) - V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); - } - - // Print the stuff. - if (pstext[0]) - V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, pstext); -} - static void ST_drawTeamHUD(void) { patch_t *p; @@ -2157,9 +2275,6 @@ static void ST_overlayDrawer(void) // Race HUD Stuff if (gametype == GT_RACE || gametype == GT_COMPETITION) ST_drawRaceHUD(); - // Tag HUD Stuff - else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) - ST_drawTagHUD(); // Special Stage HUD if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayer]) @@ -2207,103 +2322,12 @@ static void ST_overlayDrawer(void) ) ST_drawLevelTitle(); - if (!hu_showscores && (netgame || multiplayer) && displayplayer == consoleplayer) - { - if (!stplyr->spectator && stplyr->exiting && cv_playersforexit.value && gametype == GT_COOP) - { - INT32 i, total = 0, exiting = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - if (players[i].lives <= 0) - continue; - - total++; - if (players[i].exiting) - exiting++; - } - - if (cv_playersforexit.value != 4) - { - total *= cv_playersforexit.value; - if (total & 3) - total += 4; // round up - total /= 4; - } - - if (exiting < total) - { - total -= exiting; - V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))); - if (!splitscreen) - { - V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); - } - } - } - else if (!splitscreen && gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) - V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); - else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text. - { - INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; - if (respawntime > 0 && !stplyr->spectator) - V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, va(M_GetText("Respawn in %d..."), respawntime)); - else - V_DrawThinString(16, 176 - 16, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""JUMP:""\x80 Respawn")); - } - else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE) + if (!hu_showscores && (netgame || multiplayer) #ifdef HAVE_BLUA && LUA_HudEnabled(hud_textspectator) #endif - ) - { - INT32 y = 176 - 16; // HUD_LIVES - if (G_IsSpecialStage(gamemap) && useNightsSS) - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_YELLOWMAP, M_GetText("Wait for the stage to end...")); - else if (gametype == GT_COOP) - { - if (stplyr->lives <= 0 - && cv_cooplives.value == 2 - && (netgame || multiplayer)) - { - INT32 i; - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - if (&players[i] == stplyr) - continue; - - if (players[i].lives > 1) - break; - } - - if (i != MAXPLAYERS) - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("You'll steal a life on respawn...")); - else - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Wait to respawn...")); - } - else - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Wait to respawn...")); - } - else - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""FIRE:""\x80 Enter game")); - y -= 8; - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""SPIN:""\x80 Sink")); - y -= 8; - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""JUMP:""\x80 Float")); - y -= 8; - if (!splitscreen) - { - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("\x82""F12:""\x80 Switch view")); - y -= 8; - } - V_DrawThinString(16, y, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_GRAYMAP, M_GetText("Spectator mode:")); - } - } + ) + ST_drawTextHUD(); if (modeattacking) ST_drawInput(); @@ -2353,13 +2377,11 @@ void ST_Drawer(void) { stplyr = &players[displayplayer]; V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31|V_PERPLAYER); - V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_YELLOWMAP, M_GetText("You are blindfolded!")); } else if (splitscreen && players[secondarydisplayplayer].pflags & PF_TAGIT) { stplyr = &players[secondarydisplayplayer]; V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31|V_PERPLAYER); - V_DrawThinString(16, 176 - 24, V_PERPLAYER|V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_YELLOWMAP, M_GetText("You are blindfolded!")); } } From f3aa02e26dad0ce1178925284f65cc8eb7b6e4f3 Mon Sep 17 00:00:00 2001 From: Sryder Date: Fri, 30 Mar 2018 18:13:52 +0100 Subject: [PATCH 084/212] Start with lightnum on sector lightlevel --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a0ea9b47a..16587e5db 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1092,7 +1092,7 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, INT32 solid, i; lightlist_t * list = sector->lightlist; const UINT8 alpha = Surf->FlatColor.s.alpha; - FUINT lightnum; + FUINT lightnum = sector->lightlevel; extracolormap_t *colormap = NULL; realtop = top = wallVerts[3].y; From 0aaae501d379ee8526d190634e8af02ce4e8d1e8 Mon Sep 17 00:00:00 2001 From: Sryder Date: Fri, 30 Mar 2018 18:53:23 +0100 Subject: [PATCH 085/212] Warnings must die --- src/f_finale.c | 2 +- src/hardware/hw_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index cd699b6cb..958bef0f6 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -234,7 +234,7 @@ static void F_SkyScroll(INT32 scrollspeed) else if (rendermode != render_none) { // if only software rendering could be this simple and retarded INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - INT32 x, y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz; + INT32 y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz; scrolled = animtimer * dupz; for (x = 0; x < vid.width; x += pw) { diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 16587e5db..becd1b1c2 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5055,7 +5055,7 @@ static void HWR_CreateDrawNodes(void) // -------------------------------------------------------------------------- #ifdef SORTING // added the stransform so they can be switched as drawing happenes so MD2s and sprites are sorted correctly with each other -static void HWR_DrawSprites() +static void HWR_DrawSprites(void) { if (gr_visspritecount > 0) { From d9b5155e6ea4110199a440415cf9f41234b7b07c Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 30 Mar 2018 21:49:15 +0100 Subject: [PATCH 086/212] * Make Tokens appear in competition. * Tweak thrown ring colours. * Make Armageddon shield loop properly. * Tweak drowning numbers to be consistent between third and first person. --- src/dehacked.c | 32 +++++++++++++++++ src/g_game.c | 4 +-- src/info.c | 96 +++++++++++++++++++++++++++++++++----------------- src/info.h | 32 +++++++++++++++++ src/p_inter.c | 26 +++++++------- src/p_mobj.c | 2 +- src/p_user.c | 27 +++++++------- src/st_stuff.c | 33 ++++++++--------- 8 files changed, 172 insertions(+), 80 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 3726cb381..a7ba72a6c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5015,6 +5015,22 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ARMF14", "S_ARMF15", "S_ARMF16", + "S_ARMF17", + "S_ARMF18", + "S_ARMF19", + "S_ARMF20", + "S_ARMF21", + "S_ARMF22", + "S_ARMF23", + "S_ARMF24", + "S_ARMF25", + "S_ARMF26", + "S_ARMF27", + "S_ARMF28", + "S_ARMF29", + "S_ARMF30", + "S_ARMF31", + "S_ARMF32", "S_ARMB1", "S_ARMB2", @@ -5032,6 +5048,22 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ARMB14", "S_ARMB15", "S_ARMB16", + "S_ARMB17", + "S_ARMB18", + "S_ARMB19", + "S_ARMB20", + "S_ARMB21", + "S_ARMB22", + "S_ARMB23", + "S_ARMB24", + "S_ARMB25", + "S_ARMB26", + "S_ARMB27", + "S_ARMB28", + "S_ARMB29", + "S_ARMB30", + "S_ARMB31", + "S_ARMB32", "S_WIND1", "S_WIND2", diff --git a/src/g_game.c b/src/g_game.c index 984b1ec40..509ccf0ab 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -133,8 +133,8 @@ boolean useNightsSS = false; UINT8 skincolor_redteam = SKINCOLOR_RED; UINT8 skincolor_blueteam = SKINCOLOR_BLUE; -UINT8 skincolor_redring = SKINCOLOR_RED; -UINT8 skincolor_bluering = SKINCOLOR_AZURE; +UINT8 skincolor_redring = SKINCOLOR_SALMON; +UINT8 skincolor_bluering = SKINCOLOR_CORNFLOWER; tic_t countdowntimer = 0; boolean countdowntimeup = false; diff --git a/src/info.c b/src/info.c index 58a2ba8f4..5f46744bd 100644 --- a/src/info.c +++ b/src/info.c @@ -2215,39 +2215,71 @@ state_t states[NUMSTATES] = {SPR_ARMA, FF_TRANS40|14, 2, {NULL}, 0, 0, S_ARMA16}, // S_ARMA15 {SPR_ARMA, FF_TRANS40|15, 2, {NULL}, 0, 0, S_ARMA1 }, // S_ARMA16 - {SPR_ARMF, FF_FULLBRIGHT , 3, {NULL}, 0, 0, S_ARMF2 }, // S_ARMF1 - {SPR_ARMF, FF_FULLBRIGHT| 1, 3, {NULL}, 0, 0, S_ARMF3 }, // S_ARMF2 - {SPR_ARMF, FF_FULLBRIGHT| 2, 3, {NULL}, 0, 0, S_ARMF4 }, // S_ARMF3 - {SPR_ARMF, FF_FULLBRIGHT| 3, 3, {NULL}, 0, 0, S_ARMF5 }, // S_ARMF4 - {SPR_ARMF, FF_FULLBRIGHT| 4, 3, {NULL}, 0, 0, S_ARMF6 }, // S_ARMF5 - {SPR_ARMF, FF_FULLBRIGHT| 5, 3, {NULL}, 0, 0, S_ARMF7 }, // S_ARMF6 - {SPR_ARMF, FF_FULLBRIGHT| 6, 3, {NULL}, 0, 0, S_ARMF8 }, // S_ARMF7 - {SPR_ARMF, FF_FULLBRIGHT| 7, 3, {NULL}, 0, 0, S_ARMF9 }, // S_ARMF8 - {SPR_ARMF, FF_FULLBRIGHT| 8, 3, {NULL}, 0, 0, S_ARMF10}, // S_ARMF9 - {SPR_ARMF, FF_FULLBRIGHT| 9, 3, {NULL}, 0, 0, S_ARMF11}, // S_ARMF10 - {SPR_ARMF, FF_FULLBRIGHT|10, 3, {NULL}, 0, 0, S_ARMF12}, // S_ARMF11 - {SPR_ARMF, FF_FULLBRIGHT|11, 3, {NULL}, 0, 0, S_ARMF13}, // S_ARMF12 - {SPR_ARMF, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ARMF14}, // S_ARMF13 - {SPR_ARMF, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ARMF15}, // S_ARMF14 - {SPR_ARMF, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ARMF16}, // S_ARMF15 - {SPR_ARMF, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ARMF1 }, // S_ARMF16 + {SPR_ARMF, FF_FULLBRIGHT , 2, {NULL}, 0, 0, S_ARMF2 }, // S_ARMF1 + {SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF3 }, // S_ARMF2 + {SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF4 }, // S_ARMF3 + {SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF5 }, // S_ARMF4 + {SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF6 }, // S_ARMF5 + {SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF7 }, // S_ARMF6 + {SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF8 }, // S_ARMF7 + {SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF9 }, // S_ARMF8 + {SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF10}, // S_ARMF9 + {SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF11}, // S_ARMF10 + {SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF12}, // S_ARMF11 + {SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF13}, // S_ARMF12 + {SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF14}, // S_ARMF13 + {SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF15}, // S_ARMF14 + {SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF16}, // S_ARMF15 + {SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF17}, // S_ARMF16 + {SPR_ARMB, FF_FULLBRIGHT , 2, {NULL}, 0, 0, S_ARMF18}, // S_ARMF17 + {SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 0, 0, S_ARMF19}, // S_ARMF18 + {SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 0, 0, S_ARMF20}, // S_ARMF19 + {SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 0, 0, S_ARMF21}, // S_ARMF20 + {SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 0, 0, S_ARMF22}, // S_ARMF21 + {SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 0, 0, S_ARMF23}, // S_ARMF22 + {SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 0, 0, S_ARMF24}, // S_ARMF23 + {SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 0, 0, S_ARMF25}, // S_ARMF24 + {SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 0, 0, S_ARMF26}, // S_ARMF25 + {SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 0, 0, S_ARMF27}, // S_ARMF26 + {SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_ARMF28}, // S_ARMF27 + {SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_ARMF29}, // S_ARMF28 + {SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_ARMF30}, // S_ARMF29 + {SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_ARMF31}, // S_ARMF30 + {SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_ARMF32}, // S_ARMF31 + {SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_ARMF1 }, // S_ARMF32 - {SPR_ARMB, FF_FULLBRIGHT| 0, 3, {NULL}, 1, 0, S_ARMB2 }, // S_ARMB1 - {SPR_ARMB, FF_FULLBRIGHT| 1, 3, {NULL}, 1, 0, S_ARMB3 }, // S_ARMB2 - {SPR_ARMB, FF_FULLBRIGHT| 2, 3, {NULL}, 1, 0, S_ARMB4 }, // S_ARMB3 - {SPR_ARMB, FF_FULLBRIGHT| 3, 3, {NULL}, 1, 0, S_ARMB5 }, // S_ARMB4 - {SPR_ARMB, FF_FULLBRIGHT| 4, 3, {NULL}, 1, 0, S_ARMB6 }, // S_ARMB5 - {SPR_ARMB, FF_FULLBRIGHT| 5, 3, {NULL}, 1, 0, S_ARMB7 }, // S_ARMB6 - {SPR_ARMB, FF_FULLBRIGHT| 6, 3, {NULL}, 1, 0, S_ARMB8 }, // S_ARMB7 - {SPR_ARMB, FF_FULLBRIGHT| 7, 3, {NULL}, 1, 0, S_ARMB9 }, // S_ARMB8 - {SPR_ARMB, FF_FULLBRIGHT| 8, 3, {NULL}, 1, 0, S_ARMB10}, // S_ARMB9 - {SPR_ARMB, FF_FULLBRIGHT| 9, 3, {NULL}, 1, 0, S_ARMB11}, // S_ARMB10 - {SPR_ARMB, FF_FULLBRIGHT|10, 3, {NULL}, 1, 0, S_ARMB12}, // S_ARMB11 - {SPR_ARMB, FF_FULLBRIGHT|11, 3, {NULL}, 1, 0, S_ARMB13}, // S_ARMB12 - {SPR_ARMB, FF_FULLBRIGHT|12, 3, {NULL}, 1, 0, S_ARMB14}, // S_ARMB13 - {SPR_ARMB, FF_FULLBRIGHT|13, 3, {NULL}, 1, 0, S_ARMB15}, // S_ARMB14 - {SPR_ARMB, FF_FULLBRIGHT|14, 3, {NULL}, 1, 0, S_ARMB16}, // S_ARMB15 - {SPR_ARMB, FF_FULLBRIGHT|15, 3, {NULL}, 1, 0, S_ARMB1 }, // S_ARMB16 + {SPR_ARMB, FF_FULLBRIGHT , 2, {NULL}, 1, 0, S_ARMB2 }, // S_ARMB1 + {SPR_ARMB, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB3 }, // S_ARMB2 + {SPR_ARMB, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB4 }, // S_ARMB3 + {SPR_ARMB, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB5 }, // S_ARMB4 + {SPR_ARMB, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB6 }, // S_ARMB5 + {SPR_ARMB, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB7 }, // S_ARMB6 + {SPR_ARMB, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB8 }, // S_ARMB7 + {SPR_ARMB, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB9 }, // S_ARMB8 + {SPR_ARMB, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB10}, // S_ARMB9 + {SPR_ARMB, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB11}, // S_ARMB10 + {SPR_ARMB, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB12}, // S_ARMB11 + {SPR_ARMB, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB13}, // S_ARMB12 + {SPR_ARMB, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB14}, // S_ARMB13 + {SPR_ARMB, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB15}, // S_ARMB14 + {SPR_ARMB, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB16}, // S_ARMB15 + {SPR_ARMB, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB17}, // S_ARMB16 + {SPR_ARMF, FF_FULLBRIGHT , 2, {NULL}, 1, 0, S_ARMB18}, // S_ARMB17 + {SPR_ARMF, FF_FULLBRIGHT| 1, 2, {NULL}, 1, 0, S_ARMB19}, // S_ARMB18 + {SPR_ARMF, FF_FULLBRIGHT| 2, 2, {NULL}, 1, 0, S_ARMB20}, // S_ARMB19 + {SPR_ARMF, FF_FULLBRIGHT| 3, 2, {NULL}, 1, 0, S_ARMB21}, // S_ARMB20 + {SPR_ARMF, FF_FULLBRIGHT| 4, 2, {NULL}, 1, 0, S_ARMB22}, // S_ARMB21 + {SPR_ARMF, FF_FULLBRIGHT| 5, 2, {NULL}, 1, 0, S_ARMB23}, // S_ARMB22 + {SPR_ARMF, FF_FULLBRIGHT| 6, 2, {NULL}, 1, 0, S_ARMB24}, // S_ARMB23 + {SPR_ARMF, FF_FULLBRIGHT| 7, 2, {NULL}, 1, 0, S_ARMB25}, // S_ARMB24 + {SPR_ARMF, FF_FULLBRIGHT| 8, 2, {NULL}, 1, 0, S_ARMB26}, // S_ARMB25 + {SPR_ARMF, FF_FULLBRIGHT| 9, 2, {NULL}, 1, 0, S_ARMB27}, // S_ARMB26 + {SPR_ARMF, FF_FULLBRIGHT|10, 2, {NULL}, 1, 0, S_ARMB28}, // S_ARMB27 + {SPR_ARMF, FF_FULLBRIGHT|11, 2, {NULL}, 1, 0, S_ARMB29}, // S_ARMB28 + {SPR_ARMF, FF_FULLBRIGHT|12, 2, {NULL}, 1, 0, S_ARMB30}, // S_ARMB29 + {SPR_ARMF, FF_FULLBRIGHT|13, 2, {NULL}, 1, 0, S_ARMB31}, // S_ARMB30 + {SPR_ARMF, FF_FULLBRIGHT|14, 2, {NULL}, 1, 0, S_ARMB32}, // S_ARMB31 + {SPR_ARMF, FF_FULLBRIGHT|15, 2, {NULL}, 1, 0, S_ARMB1 }, // S_ARMB32 {SPR_WIND, FF_TRANS70 , 2, {NULL}, 0, 0, S_WIND2}, // S_WIND1 {SPR_WIND, FF_TRANS70|1, 2, {NULL}, 0, 0, S_WIND3}, // S_WIND2 diff --git a/src/info.h b/src/info.h index f9052b5da..d0e75e2e8 100644 --- a/src/info.h +++ b/src/info.h @@ -2330,6 +2330,22 @@ typedef enum state S_ARMF14, S_ARMF15, S_ARMF16, + S_ARMF17, + S_ARMF18, + S_ARMF19, + S_ARMF20, + S_ARMF21, + S_ARMF22, + S_ARMF23, + S_ARMF24, + S_ARMF25, + S_ARMF26, + S_ARMF27, + S_ARMF28, + S_ARMF29, + S_ARMF30, + S_ARMF31, + S_ARMF32, S_ARMB1, S_ARMB2, @@ -2347,6 +2363,22 @@ typedef enum state S_ARMB14, S_ARMB15, S_ARMB16, + S_ARMB17, + S_ARMB18, + S_ARMB19, + S_ARMB20, + S_ARMB21, + S_ARMB22, + S_ARMB23, + S_ARMB24, + S_ARMB25, + S_ARMB26, + S_ARMB27, + S_ARMB28, + S_ARMB29, + S_ARMB30, + S_ARMB31, + S_ARMB32, S_WIND1, S_WIND2, diff --git a/src/p_inter.c b/src/p_inter.c index 833a9ba52..c57d348fc 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -577,25 +577,27 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_TOKEN: if (player->bot) return; - tokenlist += special->health; P_AddPlayerScore(player, 1000); - if (!modeattacking) // score only there... + if (gametype != GT_COOP || modeattacking) // score only? + break; + + tokenlist += special->health; + + if (ALL7EMERALDS(emeralds)) // Got all 7 { - if (ALL7EMERALDS(emeralds)) // Got all 7 + if (!(netgame || multiplayer)) { - if (!(netgame || multiplayer)) - { - player->continues += 1; - players->gotcontinue = true; - if (P_IsLocalPlayer(player)) - S_StartSound(NULL, sfx_s3kac); - } + player->continues += 1; + players->gotcontinue = true; + if (P_IsLocalPlayer(player)) + S_StartSound(NULL, sfx_s3kac); } - else - token++; } + else + token++; + break; // Emerald Hunt diff --git a/src/p_mobj.c b/src/p_mobj.c index 8695d57e4..64756c55a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9539,7 +9539,7 @@ void P_SpawnMapThing(mapthing_t *mthing) // They're likely facets of the level's design and therefore required to progress. } - if (i == MT_TOKEN && (gametype != GT_COOP || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++))) + if (i == MT_TOKEN && ((gametype != GT_COOP && gametype != GT_COMPETITION) || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++))) return; // you already got this token, or there are too many, or the gametype's not right // Objectplace landing point diff --git a/src/p_user.c b/src/p_user.c index b8634afa8..b3a8bcf4b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2336,12 +2336,17 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player) { tic_t timeleft = (player->powers[pw_spacetime]) ? player->powers[pw_spacetime] : player->powers[pw_underwater]; - if ((timeleft == 11*TICRATE + 1) // 5 - || (timeleft == 9*TICRATE + 1) // 4 - || (timeleft == 7*TICRATE + 1) // 3 - || (timeleft == 5*TICRATE + 1) // 2 - || (timeleft == 3*TICRATE + 1) // 1 - || (timeleft == 1*TICRATE + 1) // 0 + if (player->exiting) + player->powers[pw_underwater] = player->powers[pw_spacetime] = 0; + + timeleft--; // The original code was all n*TICRATE + 1, so let's remove 1 tic for simplicity + + if ((timeleft == 11*TICRATE) // 5 + || (timeleft == 9*TICRATE) // 4 + || (timeleft == 7*TICRATE) // 3 + || (timeleft == 5*TICRATE) // 2 + || (timeleft == 3*TICRATE) // 1 + || (timeleft == 1*TICRATE) // 0 ) { fixed_t height = (player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->z - FixedMul(8*FRACUNIT + mobjinfo[MT_DROWNNUMBERS].height, FixedMul(player->mo->scale, player->shieldscale)) @@ -2349,7 +2354,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player) mobj_t *numbermobj = P_SpawnMobj(player->mo->x, player->mo->y, height, MT_DROWNNUMBERS); - timeleft /= (2*TICRATE); // To be strictly accurate it'd need to be (((timeleft - 1)/TICRATE) - 1)/2, but integer division rounds down for us + timeleft /= (2*TICRATE); // To be strictly accurate it'd need to be ((timeleft/TICRATE) - 1)/2, but integer division rounds down for us if (player->charflags & SF_MACHINE) { @@ -2408,14 +2413,6 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player) S_ChangeMusicInternal("_drown", false); } } - - if (player->exiting) - { - if (player->powers[pw_underwater] > 1) - player->powers[pw_underwater] = 0; - - player->powers[pw_spacetime] = 0; - } } // diff --git a/src/st_stuff.c b/src/st_stuff.c index 3ae212bc1..6a909580d 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1251,7 +1251,6 @@ static void ST_drawFirstPersonHUD(void) { patch_t *p = NULL; UINT32 airtime; - UINT32 frame = 0; spriteframe_t *sprframe; // If both air timers are active, use the air timer with the least time left if (stplyr->powers[pw_underwater] && stplyr->powers[pw_spacetime]) @@ -1259,34 +1258,32 @@ static void ST_drawFirstPersonHUD(void) else // Use whichever one is active otherwise airtime = (stplyr->powers[pw_spacetime]) ? stplyr->powers[pw_spacetime] : stplyr->powers[pw_underwater]; - if (!airtime) + if (airtime < 1) return; // No air timers are active, nothing would be drawn anyway airtime--; // The original code was all n*TICRATE + 1, so let's remove 1 tic for simplicity if (airtime > 11*TICRATE) return; // Not time to draw any drown numbers yet - // Choose which frame to use based on time left - if (airtime <= 11*TICRATE && airtime >= 10*TICRATE) - frame = 5; - else if (airtime <= 9*TICRATE && airtime >= 8*TICRATE) - frame = 4; - else if (airtime <= 7*TICRATE && airtime >= 6*TICRATE) - frame = 3; - else if (airtime <= 5*TICRATE && airtime >= 4*TICRATE) - frame = 2; - else if (airtime <= 3*TICRATE && airtime >= 2*TICRATE) - frame = 1; - else if (airtime <= 1*TICRATE && airtime > 0) - frame = 0; - else + + if (!((airtime > 10*TICRATE - 5) + || (airtime <= 9*TICRATE && airtime > 8*TICRATE - 5) + || (airtime <= 7*TICRATE && airtime > 6*TICRATE - 5) + || (airtime <= 5*TICRATE && airtime > 4*TICRATE - 5) + || (airtime <= 3*TICRATE && airtime > 2*TICRATE - 5) + || (airtime <= 1*TICRATE))) return; // Don't draw anything between numbers + if (!((airtime % 10) < 5)) + return; // Keep in line with the flashing thing from third person. + + airtime /= (2*TICRATE); // To be strictly accurate it'd need to be ((airtime/TICRATE) - 1)/2, but integer division rounds down for us + if (stplyr->charflags & SF_MACHINE) - frame += 6; // Robots use different drown numbers + airtime += 6; // Robots use different drown numbers // Get the front angle patch for the frame - sprframe = &sprites[SPR_DRWN].spriteframes[frame]; + sprframe = &sprites[SPR_DRWN].spriteframes[airtime]; p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); // Display the countdown drown numbers! From 0fbebcaa08e5a64e457f84a2e748d065ffc9cdc0 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 30 Mar 2018 22:03:14 +0100 Subject: [PATCH 087/212] Make special stage tallies do the token noise if you cash in a token! --- src/y_inter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index 7ac28018b..c86dee758 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -825,7 +825,7 @@ void Y_Ticker(void) { tallydonetic = intertic; endtic = intertic + 3*TICRATE; // 3 second pause after end of tally - S_StartSound(NULL, sfx_chchng); // cha-ching! + S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching! // Update when done with tally if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && !demoplayback) @@ -870,7 +870,7 @@ void Y_Ticker(void) if ((intertic - tallydonetic) > (3*TICRATE)/2) { endtic = intertic + 4*TICRATE; // 4 second pause after end of tally - S_StartSound(NULL, sfx_s3kac); // cha-ching! + S_StartSound(NULL, sfx_s3kac); // bingly-bingly-bing! } return; } @@ -890,7 +890,7 @@ void Y_Ticker(void) if (!(data.spec.continues & 0x80)) // don't set endtic yet! endtic = intertic + 4*TICRATE; // 4 second pause after end of tally - S_StartSound(NULL, sfx_chchng); // cha-ching! + S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching! // Update when done with tally if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && !demoplayback) From 6f2de824fb015d71940e9c4d12b321b30bcb63b2 Mon Sep 17 00:00:00 2001 From: Sryder Date: Fri, 30 Mar 2018 23:12:44 +0100 Subject: [PATCH 088/212] Uncomment HWR_CorrectSWTricks but set gr_correcttricks to be off by default I wasn't aware of the cvar, this should do for now since I don't believe any maps use these software tricks, probably an old leftover from DOOM. --- src/hardware/hw_main.c | 2 +- src/p_setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index becd1b1c2..81021ef7f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -117,7 +117,7 @@ consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL, grfiltermode_c consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, CV_anisotropic_ONChange, 0, NULL, NULL, 0, 0, NULL}; //static consvar_t cv_grzbuffer = {"gr_zbuffer", "On", 0, CV_OnOff}; -consvar_t cv_grcorrecttricks = {"gr_correcttricks", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static void CV_FogDensity_ONChange(void) diff --git a/src/p_setup.c b/src/p_setup.c index e93cbed51..8e746457b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2718,7 +2718,7 @@ boolean P_SetupLevel(boolean skipprecip) HWR_ResetLights(); #endif // Correct missing sidedefs & deep water trick - //HWR_CorrectSWTricks(); + HWR_CorrectSWTricks(); HWR_CreatePlanePolygons((INT32)numnodes - 1); } #endif From 6d59551afdac6bf20c5add5f6a86c169c9db431f Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 1 Apr 2018 20:54:19 +0100 Subject: [PATCH 089/212] Mace optimisation! * Handle all chain objects as a hnext/hprev chain. * When removing mobjs with hnext/hprev, "repair the chain" (make the h links meet). * Fix hidden slings, which I accidentially broke when I revamped maces the first time. * Kill MF2_MACEROTATE. Not needed for anything anymore. * P_MaceRotate now available to Lua to make up for it. * Related: Made modifying hnext/hprev using Lua safer, so it keeps the reference counts in play. --- src/dehacked.c | 1 - src/info.c | 14 +-- src/lua_baselib.c | 14 +++ src/lua_mobjlib.c | 16 ++- src/p_enemy.c | 11 +- src/p_local.h | 2 + src/p_mobj.c | 260 +++++++++++++++++++++++++++++----------------- src/p_mobj.h | 2 - 8 files changed, 209 insertions(+), 111 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index c172549e1..ced71f079 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6515,7 +6515,6 @@ static const char *const MOBJFLAG2_LIST[] = { "AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH "LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) "SHIELD", // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) - "MACEROTATE", // Thinker calls P_MaceRotate around tracer NULL }; diff --git a/src/info.c b/src/info.c index acb12379a..f11d88af8 100644 --- a/src/info.c +++ b/src/info.c @@ -9011,7 +9011,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 10000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, @@ -9038,7 +9038,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 10000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, @@ -9065,7 +9065,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 10000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, @@ -9092,7 +9092,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 10000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, @@ -9119,7 +9119,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, @@ -9146,7 +9146,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 200, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, @@ -9173,7 +9173,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 200, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9d65a5832..4040e271d 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -776,6 +776,19 @@ static int lib_pCanRunOnWater(lua_State *L) return 1; } +static int lib_pMaceRotate(lua_State *L) +{ + mobj_t *center = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + INT32 baserot = luaL_checkinteger(L, 2); + INT32 baseprevrot = luaL_checkinteger(L, 3); + NOHUD + INLEVEL + if (!center) + return LUA_ErrInvalid(L, "mobj_t"); + P_MaceRotate(center, baserot, baseprevrot); + return 0; +} + // P_USER //////////// @@ -2526,6 +2539,7 @@ static luaL_Reg lib[] = { {"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide}, {"P_CheckSolidLava",lib_pCheckSolidLava}, {"P_CanRunOnWater",lib_pCanRunOnWater}, + {"P_MaceRotate",lib_pMaceRotate}, // p_user {"P_GetPlayerHeight",lib_pGetPlayerHeight}, diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index d384b75d1..1583bd3c4 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -530,10 +530,22 @@ static int mobj_set(lua_State *L) case mobj_bprev: return UNIMPLEMENTED; case mobj_hnext: - mo->hnext = luaL_checkudata(L, 3, META_MOBJ); + if (lua_isnil(L, 3)) + P_SetTarget(&mo->hnext, NULL); + else + { + mobj_t *hnext = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); + P_SetTarget(&mo->hnext, hnext); + } break; case mobj_hprev: - mo->hprev = luaL_checkudata(L, 3, META_MOBJ); + if (lua_isnil(L, 3)) + P_SetTarget(&mo->hprev, NULL); + else + { + mobj_t *hprev = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); + P_SetTarget(&mo->hprev, hprev); + } break; case mobj_type: // yeah sure, we'll let you change the mobj's type. { diff --git a/src/p_enemy.c b/src/p_enemy.c index 9acc8430e..a8ce7869c 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4917,6 +4917,7 @@ void A_SlingAppear(mobj_t *actor) boolean firsttime = true; UINT8 mlength = 4; mobj_t *spawnee; + mobj_t *hprev = actor; #ifdef HAVE_BLUA if (LUA_CallAction("A_SlingAppear", actor)) return; @@ -4927,7 +4928,6 @@ void A_SlingAppear(mobj_t *actor) P_SetThingPosition(actor); actor->lastlook = 128; actor->movecount = actor->lastlook; - actor->health = actor->angle>>ANGLETOFINESHIFT; actor->threshold = 0; actor->movefactor = actor->threshold; actor->friction = 128; @@ -4936,10 +4936,13 @@ void A_SlingAppear(mobj_t *actor) { spawnee = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLMACECHAIN); - P_SetTarget(&spawnee->target, actor); + P_SetTarget(&spawnee->tracer, actor); + P_SetTarget(&spawnee->hprev, hprev); + P_SetTarget(&hprev->hnext, spawnee); + hprev = spawnee; - spawnee->threshold = 0; - spawnee->reactiontime = mlength; + spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; + spawnee->movecount = mlength; if (firsttime) { diff --git a/src/p_local.h b/src/p_local.h index 54ae37ed2..49d3ed614 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -280,6 +280,8 @@ mobj_t *P_GetClosestAxis(mobj_t *source); boolean P_CanRunOnWater(player_t *player, ffloor_t *rover); +void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot); + void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration); #define PAL_WHITE 1 #define PAL_MIXUP 2 diff --git a/src/p_mobj.c b/src/p_mobj.c index 8695d57e4..2e78c098e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6176,98 +6176,149 @@ static void P_NightsItemChase(mobj_t *thing) // // P_MaceRotate -// Spins an object around its target, or, swings it from side to side. +// Spins a hnext-chain of objects around its centerpoint, side to side or periodically. // -static void P_MaceRotate(mobj_t *mobj) +void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) { - TVector v; + TVector unit, baseuo, unitoffset; TVector *res; - fixed_t radius, dist; + fixed_t radius, dist, wah; angle_t fa; - INT32 prevswing; - boolean donetwice = false; + //boolean donetwice = false; + boolean dosound = false; + mobj_t *mobj = center->hnext, *hnext = NULL; // Tracer was removed. - if (!mobj->health) + /*if (!mobj->health) return; else if (!mobj->tracer) { P_KillMobj(mobj, NULL, NULL, 0); return; - } + }*/ - mobj->momx = mobj->momy = mobj->momz = 0; + INT32 rot = (baserot &= FINEMASK); + INT32 prevrot = (baseprevrot &= FINEMASK); - prevswing = mobj->threshold; - mobj->threshold += mobj->tracer->lastlook; - mobj->threshold &= FINEMASK; + INT32 lastthreshold = FINEMASK; // needs to never be equal at start of loop + fixed_t lastfriction = INT32_MIN; // ditto; almost certainly never, but... - dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); + fixed_t movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = 0; - // Radius of the link's rotation. - radius = FixedMul(dist * mobj->movecount, mobj->tracer->scale) + mobj->tracer->extravalue1; + baseuo[3] = 0; -maceretry: - - fa = (FixedAngle(mobj->tracer->movefactor*FRACUNIT) >> ANGLETOFINESHIFT); - radius = FixedMul(FINECOSINE(fa), radius); - v[1] = -FixedMul(FINESINE(fa), radius) - + FixedMul(dist * mobj->movefactor, mobj->tracer->scale); - v[3] = FRACUNIT; - - // Swinging Chain. - if (mobj->tracer->flags2 & MF2_STRONGBOX) + while (mobj) { - fixed_t swingmagnitude = FixedMul(FINECOSINE(mobj->threshold), mobj->tracer->lastlook << FRACBITS); - prevswing = FINECOSINE(prevswing); + mobj->momx = mobj->momy = mobj->momz = 0; - if (!donetwice - && (mobj->flags2 & MF2_BOSSNOTRAP) // at the end of the chain and can play a sound - && ((prevswing > 0) != (swingmagnitude > 0))) // just passed its lowest point + if (mobj->threshold != lastthreshold + || mobj->friction != lastfriction) + { + rot = (baserot + mobj->threshold) & FINEMASK; + prevrot = (baseprevrot + mobj->threshold) & FINEMASK; + + fa = (FixedAngle(center->movefactor*FRACUNIT) >> ANGLETOFINESHIFT); // mpinch + radius = FINECOSINE(fa); + unit[1] = -FixedMul(FINESINE(fa), radius); + unit[3] = center->scale; + + // Swinging Chain. + if (center->flags2 & MF2_STRONGBOX) + { + fixed_t swingmag = FixedMul(FINECOSINE(rot), center->lastlook << FRACBITS); + fixed_t prevswingmag = FINECOSINE(prevrot); + + if ((prevswingmag > 0) != (swingmag > 0)) // just passed its lowest point + dosound = true; + //S_StartSound(mobj, mobj->info->activesound); + + fa = ((FixedAngle(swingmag) >> ANGLETOFINESHIFT) + mobj->friction) & FINEMASK; + + unit[0] = FixedMul(FINESINE(fa), -radius); + unit[2] = FixedMul(FINECOSINE(fa), -radius); + } + // Rotating Chain. + else + { + angle_t prevfa = (prevrot + mobj->friction) & FINEMASK; + fa = (rot + mobj->friction) & FINEMASK; + + if (!(prevfa > (FINEMASK/2)) && (fa > (FINEMASK/2))) // completed a full swing + dosound = true; + + unit[0] = FixedMul(FINECOSINE(fa), radius); + unit[2] = FixedMul(FINESINE(fa), radius); + } + + // Calculate the angle matrixes for the link. + res = VectorMatrixMultiply(unit, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT)); + M_Memcpy(&unit, res, sizeof(unit)); + res = VectorMatrixMultiply(unit, *RotateZMatrix(center->angle)); + M_Memcpy(&unit, res, sizeof(unit)); + } + + if (dosound && (mobj->flags2 & MF2_BOSSNOTRAP)) + { S_StartSound(mobj, mobj->info->activesound); + dosound = false; + } - fa = ((FixedAngle(swingmagnitude) >> ANGLETOFINESHIFT) + mobj->friction) & FINEMASK; + dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); - v[0] = FixedMul(FINESINE(fa), -radius); - v[2] = FixedMul(FINECOSINE(fa), -radius); - } - // Rotating Chain. - else - { - prevswing = (prevswing + mobj->friction) & FINEMASK; - fa = (mobj->threshold + mobj->friction) & FINEMASK; + if (dist*mobj->movefactor != movefac) + { + if (!baseuo[3]) + { + baseuo[1] = FRACUNIT; + baseuo[3] = center->scale; + baseuo[0] = baseuo[2] = 0; - if (!donetwice - && (mobj->flags2 & MF2_BOSSNOTRAP) // at the end of the chain and can play a sound - && (!(prevswing > (FINEMASK/2)) && (fa > (FINEMASK/2)))) // completed a full swing - S_StartSound(mobj, mobj->info->activesound); + res = VectorMatrixMultiply(baseuo, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT)); + M_Memcpy(&baseuo, res, sizeof(unit)); + res = VectorMatrixMultiply(baseuo, *RotateZMatrix(center->angle)); + M_Memcpy(&baseuo, res, sizeof(unit)); - v[0] = FixedMul(FINECOSINE(fa), radius); - v[2] = FixedMul(FINESINE(fa), radius); + lastthreshold = mobj->threshold; + lastfriction = mobj->friction; + } + + if (mobj->movefactor) + { + movefac = dist*mobj->movefactor; + unitoffset[0] = FixedMul(movefac, baseuo[0]); + unitoffset[1] = FixedMul(movefac, baseuo[1]); + unitoffset[2] = FixedMul(movefac, baseuo[2]); + } + else + movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = 0; + } + + //maceretry: + + hnext = mobj->hnext; // just in case the mobj is removed + + P_UnsetThingPosition(mobj); + + // Radius of the link's rotation. + wah = (dist * mobj->movecount) + center->extravalue1; + + // Add on the appropriate distances to the center's co-ordinates. + mobj->x = center->x + FixedMul(unit[0], wah) + unitoffset[0]; + mobj->y = center->y + FixedMul(unit[1], wah) + unitoffset[1]; + mobj->z = center->z + FixedMul(unit[2], wah) + unitoffset[2]; + + // Cut the height to align the link with the axis. + if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN) + mobj->z -= P_MobjFlip(mobj)*mobj->height/4; + else + mobj->z -= P_MobjFlip(mobj)*mobj->height/2; + + P_SetThingPosition(mobj); + + mobj = hnext; } - // Calculate the angle matrixes for the link. - res = VectorMatrixMultiply(v, *RotateXMatrix(mobj->tracer->threshold << ANGLETOFINESHIFT)); - M_Memcpy(&v, res, sizeof(v)); - res = VectorMatrixMultiply(v, *RotateZMatrix(mobj->tracer->health << ANGLETOFINESHIFT)); - M_Memcpy(&v, res, sizeof(v)); - - // Cut the height to align the link with the axis. - if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN) - v[2] -= P_MobjFlip(mobj)*mobj->height/4; - else - v[2] -= P_MobjFlip(mobj)*mobj->height/2; - - P_UnsetThingPosition(mobj); - - // Add on the appropriate distances to the center's co-ordinates. - mobj->x = mobj->tracer->x + v[0]; - mobj->y = mobj->tracer->y + v[1]; - mobj->z = mobj->tracer->z + v[2]; - - P_SetThingPosition(mobj); - - if (donetwice || P_MobjWasRemoved(mobj)) + /*if (donetwice || P_MobjWasRemoved(mobj)) return; if (mobj->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)) @@ -6293,7 +6344,7 @@ maceretry: radius = FixedMul(radius, dist); donetwice = true; dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); - goto maceretry; + goto maceretry;*/ } static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield) @@ -6664,13 +6715,6 @@ void P_MobjThinker(mobj_t *mobj) } } - if (mobj->flags2 & MF2_MACEROTATE) - { - P_MaceRotate(mobj); - if (P_MobjWasRemoved(mobj)) - return; - } - // Special thinker for scenery objects if (mobj->flags & MF_SCENERY) { @@ -6687,6 +6731,29 @@ void P_MobjThinker(mobj_t *mobj) switch (mobj->type) { + case MT_CHAINPOINT: + case MT_CHAINMACEPOINT: + if (leveltime & 1) + { + if (mobj->lastlook > mobj->movecount) + mobj->lastlook--; + /* + if (mobj->threshold > mobj->movefactor) + mobj->threshold -= FRACUNIT; + else if (mobj->threshold < mobj->movefactor) + mobj->threshold += FRACUNIT;*/ + } + /* FALLTHRU */ + case MT_MACEPOINT: + case MT_SPRINGBALLPOINT: + case MT_FIREBARPOINT: + case MT_CUSTOMMACEPOINT: + case MT_HIDDEN_SLING: + // The following was pretty good, but liked breaking whenever mobj->lastlook changed. + //P_MaceRotate(mobj, ((leveltime + 1) * mobj->lastlook), (leveltime * mobj->lastlook)); + P_MaceRotate(mobj, mobj->movedir + mobj->lastlook, mobj->movedir); + mobj->movedir = (mobj->movedir + mobj->lastlook) & FINEMASK; + break; case MT_HOOP: if (mobj->fuse > 1) P_MoveHoop(mobj); @@ -7337,19 +7404,6 @@ void P_MobjThinker(mobj_t *mobj) } } break; - case MT_CHAINPOINT: - case MT_CHAINMACEPOINT: - if (leveltime & 1) - { - if (mobj->lastlook > mobj->movecount) - mobj->lastlook--; -/* - if (mobj->threshold > mobj->movefactor) - mobj->threshold -= FRACUNIT; - else if (mobj->threshold < mobj->movefactor) - mobj->threshold += FRACUNIT;*/ - } - break; case MT_EGGCAPSULE: if (!mobj->reactiontime) { @@ -8615,6 +8669,13 @@ void P_RemoveMobj(mobj_t *mobj) // Remove any references to other mobjs. P_SetTarget(&mobj->target, P_SetTarget(&mobj->tracer, NULL)); + if (mobj->hnext) + P_SetTarget(&mobj->hnext->hprev, mobj->hprev); + if (mobj->hprev) + P_SetTarget(&mobj->hprev->hnext, mobj->hnext); + + P_SetTarget(&mobj->hnext, P_SetTarget(&mobj->hprev, NULL)); + // free block // DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error. if (mobj->flags & MF_NOTHINK && !mobj->thinker.next) @@ -9301,6 +9362,7 @@ void P_SpawnMapThing(mapthing_t *mthing) mobj_t *mobj; fixed_t x, y, z; subsector_t *ss; + boolean doangle = true; if (!mthing->type) return; // Ignore type-0 things as NOPs @@ -9710,7 +9772,7 @@ void P_SpawnMapThing(mapthing_t *mthing) angle_t mspokeangle; mobjtype_t chainlink, macetype, firsttype, linktype; boolean mdoall = true; - mobj_t *spawnee; + mobj_t *spawnee, *hprev; mobjflag_t mflagsapply; mobjflag2_t mflags2apply; mobjeflag_t meflagsapply; @@ -9748,7 +9810,7 @@ ML_EFFECT4 : Don't clip inside the ground mspeed = abs(lines[line].dy >> (FRACBITS - 4)); mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360; if ((mmaxspeed = sides[lines[line].sidenum[0]].rowoffset >> (FRACBITS - 4)) < mspeed) - mmaxspeed = mspeed << 1; + mmaxspeed = mspeed; mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360; myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360; @@ -9787,10 +9849,12 @@ ML_EFFECT4 : Don't clip inside the ground mobj->lastlook = mspeed; mobj->movecount = mobj->lastlook; - mobj->health = (FixedAngle(myaw*FRACUNIT)>>ANGLETOFINESHIFT); + mobj->angle = FixedAngle(myaw*FRACUNIT); + doangle = false; mobj->threshold = (FixedAngle(mpitch*FRACUNIT)>>ANGLETOFINESHIFT); mobj->friction = mmaxspeed; mobj->movefactor = mpinch; + mobj->movedir = 0; // Mobjtype selection switch(mobj->type) @@ -9857,7 +9921,7 @@ ML_EFFECT4 : Don't clip inside the ground mmin = mnumspokes; // Make the links the same type as the end - repeated below - if ((mobj->type != MT_CHAINPOINT) && ((lines[line].flags & ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or + if ((mobj->type != MT_CHAINPOINT) && (((lines[line].flags & ML_EFFECT2) == ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or { linktype = macetype; radiusfactor = 2; // Double the radius. @@ -9866,7 +9930,7 @@ ML_EFFECT4 : Don't clip inside the ground radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP|MF_NOCLIPHEIGHT)); - mflags2apply = (MF2_MACEROTATE|((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0)); + mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0); meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0); msound = ((firsttype == chainlink) ? 0 : (mwidth & 1)); @@ -9875,6 +9939,8 @@ ML_EFFECT4 : Don't clip inside the ground mphase = (FixedAngle(mphase*FRACUNIT)>>ANGLETOFINESHIFT); mroll = (FixedAngle(mroll*FRACUNIT)>>ANGLETOFINESHIFT); + hprev = mobj; + #define makemace(mobjtype, dist, moreflags2) P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\ P_SetTarget(&spawnee->tracer, mobj);\ spawnee->threshold = mphase;\ @@ -9884,7 +9950,10 @@ ML_EFFECT4 : Don't clip inside the ground spawnee->angle = myaw;\ spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ spawnee->flags2 |= (mflags2apply|moreflags2);\ - spawnee->eflags |= meflagsapply + spawnee->eflags |= meflagsapply;\ + P_SetTarget(&hprev->hnext, spawnee);\ + P_SetTarget(&spawnee->hprev, hprev);\ + hprev = spawnee domaceagain: mnumspokesset = mnumspokes; @@ -10264,7 +10333,8 @@ domaceagain: } } - mobj->angle = FixedAngle(mthing->angle*FRACUNIT); + if (doangle) + mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if ((mthing->options & MTF_AMBUSH) && (mthing->options & MTF_OBJECTSPECIAL) diff --git a/src/p_mobj.h b/src/p_mobj.h index c6e1bfbf2..ec25855d8 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -194,8 +194,6 @@ typedef enum MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) - MF2_MACEROTATE = 1<<30, // Thinker calls P_MaceRotate around tracer - // free: to and including 1<<31 } mobjflag2_t; typedef enum From 97ddb8881d5a5af40097f8f8480200c91262a60e Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 1 Apr 2018 22:05:59 +0100 Subject: [PATCH 090/212] * Remove ability to change speed of chains. * Fix ability to turn chains (still disabled by default, just at least want the option...) * Replace max speed setting with a "minimum chainlink distance" setting - if greater than zero, that many chains will not be spawned from the center outwards. Doesn't affect the head of the chain at all, since otherwise what's the point? :V --- src/p_mobj.c | 32 +++++++++----------------------- src/p_user.c | 13 +------------ 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 2e78c098e..17775b0ef 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6731,21 +6731,10 @@ void P_MobjThinker(mobj_t *mobj) switch (mobj->type) { - case MT_CHAINPOINT: - case MT_CHAINMACEPOINT: - if (leveltime & 1) - { - if (mobj->lastlook > mobj->movecount) - mobj->lastlook--; - /* - if (mobj->threshold > mobj->movefactor) - mobj->threshold -= FRACUNIT; - else if (mobj->threshold < mobj->movefactor) - mobj->threshold += FRACUNIT;*/ - } - /* FALLTHRU */ case MT_MACEPOINT: + case MT_CHAINMACEPOINT: case MT_SPRINGBALLPOINT: + case MT_CHAINPOINT: case MT_FIREBARPOINT: case MT_CUSTOMMACEPOINT: case MT_HIDDEN_SLING: @@ -9768,7 +9757,7 @@ void P_SpawnMapThing(mapthing_t *mthing) case MT_FIREBARPOINT: case MT_CUSTOMMACEPOINT: { - fixed_t mlength, mlengthset, mspeed, mphase, myaw, mpitch, mmaxspeed, mnumspokes, mnumspokesset, mpinch, mroll, mnumnospokes, mwidth, mmin, msound, radiusfactor; + fixed_t mlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mnumspokesset, mpinch, mroll, mnumnospokes, mwidth, mmin, msound, radiusfactor; angle_t mspokeangle; mobjtype_t chainlink, macetype, firsttype, linktype; boolean mdoall = true; @@ -9809,8 +9798,8 @@ ML_EFFECT4 : Don't clip inside the ground mlength = abs(lines[line].dx >> FRACBITS); mspeed = abs(lines[line].dy >> (FRACBITS - 4)); mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360; - if ((mmaxspeed = sides[lines[line].sidenum[0]].rowoffset >> (FRACBITS - 4)) < mspeed) - mmaxspeed = mspeed; + if ((mminlength = sides[lines[line].sidenum[0]].rowoffset>>FRACBITS) < 0) + mminlength = 0; mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360; myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360; @@ -9829,18 +9818,16 @@ ML_EFFECT4 : Don't clip inside the ground mpinch = mroll = mnumnospokes = mwidth = 0; CONS_Debug(DBG_GAMELOGIC, "Mace/Chain (mapthing #%s):\n" - "Length is %d\n" + "Length is %d (minus %d)\n" "Speed is %d\n" "Phase is %d\n" "Yaw is %d\n" "Pitch is %d\n" - "Max. speed is %d\n" - "No. of spokes is %d\n" + "No. of spokes is %d (%d antispokes)\n" "Pinch is %d\n" "Roll is %d\n" - "No. of antispokes is %d\n" "Width is %d\n", - sizeu1(mthingi), mlength, mspeed, mphase, myaw, mpitch, mmaxspeed, mnumspokes, mpinch, mroll, mnumnospokes, mwidth); + sizeu1(mthingi), mlength, mminlength, mspeed, mphase, myaw, mpitch, mnumspokes, mnumnospokes, mpinch, mroll, mwidth); if (mnumnospokes > 0 && (mnumnospokes < mnumspokes)) mnumnospokes = mnumspokes/mnumnospokes; @@ -9852,7 +9839,6 @@ ML_EFFECT4 : Don't clip inside the ground mobj->angle = FixedAngle(myaw*FRACUNIT); doangle = false; mobj->threshold = (FixedAngle(mpitch*FRACUNIT)>>ANGLETOFINESHIFT); - mobj->friction = mmaxspeed; mobj->movefactor = mpinch; mobj->movedir = 0; @@ -10011,7 +9997,7 @@ domaceagain: continue; // The rest of the links - while (mlengthset > 0) + while (mlengthset > mminlength) { spawnee = makemace(linktype, radiusfactor*(mlengthset--), 0); } } diff --git a/src/p_user.c b/src/p_user.c index f422e9b65..c0fd01000 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -10421,21 +10421,10 @@ void P_PlayerAfterThink(player_t *player) player->secondjump = 0; player->pflags &= ~PF_THOKKED; - if (cmd->forwardmove > 0) - { - if ((player->mo->tracer->tracer->lastlook += 2) > player->mo->tracer->tracer->friction) - player->mo->tracer->tracer->lastlook = player->mo->tracer->tracer->friction; - } - else if (cmd->forwardmove < 0) - { - if ((player->mo->tracer->tracer->lastlook -= 2) < player->mo->tracer->tracer->movecount) - player->mo->tracer->tracer->lastlook = player->mo->tracer->tracer->movecount; - } - if ((player->mo->tracer->tracer->flags & MF_SLIDEME) // Noclimb on chain parameters gives this && !(twodlevel || player->mo->flags2 & MF2_TWOD)) // why on earth would you want to turn them in 2D mode? { - player->mo->tracer->tracer->health += cmd->sidemove; + player->mo->tracer->tracer->angle += cmd->sidemove<mo->angle += cmd->sidemove< ANGLE_MAX if (!demoplayback || P_AnalogMove(player)) From 5ac70bbb7e286c1908ed5056af530940ef1c00d8 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 2 Apr 2018 01:08:31 +0100 Subject: [PATCH 091/212] * Fix multispoke mace/chainbars having problems. * Completely rework how mace/chainbars are spawned to reduce the number of matrix multiplications required EVEN FURTHER! * Reimplement the maceretry solidity stuff (effect 4). * Flip the mminlength stuff so that existing dev maps don't break badly. * Fix hacky chainbar grabbing. * Tweak height of tinychain a smidge. --- src/info.c | 2 +- src/p_inter.c | 4 +- src/p_mobj.c | 197 ++++++++++++++++++++++++++++---------------------- 3 files changed, 112 insertions(+), 91 deletions(-) diff --git a/src/info.c b/src/info.c index f11d88af8..673c18ac6 100644 --- a/src/info.c +++ b/src/info.c @@ -9195,7 +9195,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 24*FRACUNIT, // speed 24*FRACUNIT, // radius - 48*FRACUNIT, // height + 32*FRACUNIT, // height 0, // display offset 100, // mass 1, // damage diff --git a/src/p_inter.c b/src/p_inter.c index 4c9e231fe..82187f533 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1503,10 +1503,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->powers[pw_flashing]) return; - if (special->movefactor && special->tracer && (angle_t)special->tracer->health != ANGLE_90 && (angle_t)special->tracer->health != ANGLE_270) + if (special->movefactor && special->tracer && (angle_t)special->tracer->angle != ANGLE_90 && (angle_t)special->tracer->angle != ANGLE_270) { // I don't expect you to understand this, Mr Bond... angle_t ang = R_PointToAngle2(special->x, special->y, toucher->x, toucher->y) - special->tracer->threshold; - if ((special->movefactor > 0) == ((angle_t)special->tracer->health > ANGLE_90 && (angle_t)special->tracer->health < ANGLE_270)) + if ((special->movefactor > 0) == ((angle_t)special->tracer->angle > ANGLE_90 && (angle_t)special->tracer->angle < ANGLE_270)) ang += ANGLE_180; if (ang < ANGLE_180) return; // I expect you to die. diff --git a/src/p_mobj.c b/src/p_mobj.c index 17775b0ef..f98943d84 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6182,33 +6182,28 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) { TVector unit, baseuo, unitoffset; TVector *res; - fixed_t radius, dist, wah; + fixed_t radius, dist, mag, zstore; angle_t fa; - //boolean donetwice = false; + boolean donetwice = false; boolean dosound = false; mobj_t *mobj = center->hnext, *hnext = NULL; - // Tracer was removed. - /*if (!mobj->health) - return; - else if (!mobj->tracer) - { - P_KillMobj(mobj, NULL, NULL, 0); - return; - }*/ - INT32 rot = (baserot &= FINEMASK); INT32 prevrot = (baseprevrot &= FINEMASK); INT32 lastthreshold = FINEMASK; // needs to never be equal at start of loop fixed_t lastfriction = INT32_MIN; // ditto; almost certainly never, but... - fixed_t movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = 0; - - baseuo[3] = 0; + fixed_t movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = baseuo[3] = 0; while (mobj) { + if (!mobj->health) + { + mobj = mobj->hnext; + continue; + } + mobj->momx = mobj->momy = mobj->momz = 0; if (mobj->threshold != lastthreshold @@ -6255,6 +6250,9 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) M_Memcpy(&unit, res, sizeof(unit)); res = VectorMatrixMultiply(unit, *RotateZMatrix(center->angle)); M_Memcpy(&unit, res, sizeof(unit)); + + lastthreshold = mobj->threshold; + lastfriction = mobj->friction; } if (dosound && (mobj->flags2 & MF2_BOSSNOTRAP)) @@ -6277,9 +6275,6 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) M_Memcpy(&baseuo, res, sizeof(unit)); res = VectorMatrixMultiply(baseuo, *RotateZMatrix(center->angle)); M_Memcpy(&baseuo, res, sizeof(unit)); - - lastthreshold = mobj->threshold; - lastfriction = mobj->friction; } if (mobj->movefactor) @@ -6293,58 +6288,78 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = 0; } - //maceretry: - hnext = mobj->hnext; // just in case the mobj is removed + // Radius of the link's rotation. + mag = (dist * mobj->movecount) + mobj->extravalue1; + +maceretry: P_UnsetThingPosition(mobj); - // Radius of the link's rotation. - wah = (dist * mobj->movecount) + center->extravalue1; + mobj->x = center->x; + mobj->y = center->y; + mobj->z = center->z; // Add on the appropriate distances to the center's co-ordinates. - mobj->x = center->x + FixedMul(unit[0], wah) + unitoffset[0]; - mobj->y = center->y + FixedMul(unit[1], wah) + unitoffset[1]; - mobj->z = center->z + FixedMul(unit[2], wah) + unitoffset[2]; + if (mag) + { + zstore = FixedMul(unit[2], mag); + mobj->x += FixedMul(unit[0], mag); + mobj->y += FixedMul(unit[1], mag); + } + else + zstore = 0; + zstore += unitoffset[2]; + + mobj->x += unitoffset[0]; + mobj->y += unitoffset[1]; // Cut the height to align the link with the axis. if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN) - mobj->z -= P_MobjFlip(mobj)*mobj->height/4; + zstore -= P_MobjFlip(mobj)*mobj->height/4; else - mobj->z -= P_MobjFlip(mobj)*mobj->height/2; + zstore -= P_MobjFlip(mobj)*mobj->height/2; + + mobj->z += zstore; + +#if 0 // toaster's testing flashie! + if (!mobj->threshold && !mobj->friction && !(leveltime & TICRATE)) // I had a brainfart and the flashing isn't exactly what I expected it to be, but it's actually much more useful. + mobj->flags2 ^= MF2_DONTDRAW; +#endif P_SetThingPosition(mobj); + if (!mag || donetwice || P_MobjWasRemoved(mobj)) + goto cont; + + if (mobj->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)) + goto cont; + + if ((fa = ((mobj->tracer->threshold & (FINEMASK/2)) << ANGLETOFINESHIFT)) > ANGLE_45 && fa < ANGLE_135) // only move towards center when the motion is towards/away from the ground, rather than alongside it + goto cont; + + if (mobj->subsector->sector->ffloors) + P_AdjustMobjFloorZ_FFloors(mobj, mobj->subsector->sector, 2); + + // Variable reuse + if (mobj->floorz > mobj->z) + dist = (mobj->floorz - mobj->tracer->z); + else if (mobj->ceilingz < mobj->z) + dist = (mobj->ceilingz - mobj->tracer->z); + else + goto cont; + + if ((dist = FixedDiv(dist, zstore)) > FRACUNIT) + goto cont; + + mag = FixedMul(mag, dist); + donetwice = true; + dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); + goto maceretry; + +cont: mobj = hnext; } - - /*if (donetwice || P_MobjWasRemoved(mobj)) - return; - - if (mobj->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)) - return; - - if ((fa = ((mobj->tracer->threshold & (FINEMASK/2)) << ANGLETOFINESHIFT)) > ANGLE_45 && fa < ANGLE_135) // only move towards center when the motion is towards/away from the ground, rather than alongside it - return; - - if (mobj->subsector->sector->ffloors) - P_AdjustMobjFloorZ_FFloors(mobj, mobj->subsector->sector, 2); - - // Variable reuse - if (mobj->floorz > mobj->z) - dist = (mobj->floorz - mobj->tracer->z); - else if (mobj->ceilingz < mobj->z) - dist = (mobj->ceilingz - mobj->tracer->z); - else - return; - - if ((dist = FixedDiv(dist, v[2])) > FRACUNIT) - return; - - radius = FixedMul(radius, dist); - donetwice = true; - dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); - goto maceretry;*/ } static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield) @@ -9757,10 +9772,10 @@ void P_SpawnMapThing(mapthing_t *mthing) case MT_FIREBARPOINT: case MT_CUSTOMMACEPOINT: { - fixed_t mlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mnumspokesset, mpinch, mroll, mnumnospokes, mwidth, mmin, msound, radiusfactor; + fixed_t mlength, mlengthmax, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor; angle_t mspokeangle; mobjtype_t chainlink, macetype, firsttype, linktype; - boolean mdoall = true; + boolean mdoall = true, mdocenter; mobj_t *spawnee, *hprev; mobjflag_t mflagsapply; mobjflag2_t mflags2apply; @@ -9798,7 +9813,7 @@ ML_EFFECT4 : Don't clip inside the ground mlength = abs(lines[line].dx >> FRACBITS); mspeed = abs(lines[line].dy >> (FRACBITS - 4)); mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360; - if ((mminlength = sides[lines[line].sidenum[0]].rowoffset>>FRACBITS) < 0) + if ((mminlength = -sides[lines[line].sidenum[0]].rowoffset>>FRACBITS) < 0) mminlength = 0; mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360; myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360; @@ -9931,7 +9946,7 @@ ML_EFFECT4 : Don't clip inside the ground P_SetTarget(&spawnee->tracer, mobj);\ spawnee->threshold = mphase;\ spawnee->friction = mroll;\ - spawnee->movefactor = mwidth;\ + spawnee->movefactor = mwidthset;\ spawnee->movecount = dist;\ spawnee->angle = myaw;\ spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ @@ -9941,14 +9956,10 @@ ML_EFFECT4 : Don't clip inside the ground P_SetTarget(&spawnee->hprev, hprev);\ hprev = spawnee -domaceagain: - mnumspokesset = mnumspokes; - - if (mdoall && lines[line].flags & ML_EFFECT3) // Innermost mace/link - { spawnee = makemace(macetype, 0, MF2_AMBUSH); } + mdocenter = (lines[line].flags & ML_EFFECT3); // The actual spawning of spokes - while (mnumspokesset-- > 0) + while (mnumspokes-- > 0) { // Offsets if (lines[line].flags & ML_EFFECT1) // Swinging @@ -9956,13 +9967,13 @@ domaceagain: else // Spinning mphase = (mphase - mspokeangle) & FINEMASK; - if (mnumnospokes && !(mnumspokesset % mnumnospokes)) // Skipping a "missing" spoke + if (mnumnospokes && !(mnumspokes % mnumnospokes)) // Skipping a "missing" spoke { if (mobj->type != MT_CHAINMACEPOINT) continue; firsttype = linktype = chainlink; - mlengthset = 1 + (mlength - 1)*radiusfactor; + mlengthmax = 1 + (mlength - 1)*radiusfactor; radiusfactor = 1; } else @@ -9984,34 +9995,44 @@ domaceagain: firsttype = macetype; } - mlengthset = mlength; + mlengthmax = mlength; } - // Outermost mace/link - spawnee = makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); + mwidthset = mwidth; + mdoall = true; + while (1) + { + mlengthset = mlengthmax; - if (mspeed && (mwidth == msound) && !(mthing->options & MTF_OBJECTSPECIAL) && mnumspokesset <= mmin) // Can it make a sound? - spawnee->flags2 |= MF2_BOSSNOTRAP; + if (mdocenter) // Innermost mace/link + { + spawnee = makemace(macetype, 0, 0); + } - if (!mdoall || !linktype) - continue; + // Outermost mace/link + spawnee = makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); - // The rest of the links - while (mlengthset > mminlength) - { spawnee = makemace(linktype, radiusfactor*(mlengthset--), 0); } - } + if (mspeed && (mwidthset == msound) && !(mthing->options & MTF_OBJECTSPECIAL) && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; - if (mwidth > 0) - { - mwidth *= -1; - goto domaceagain; - } - else if (mwidth != 0) - { - if ((mwidth = -(mwidth + ((firsttype == chainlink) ? 1 : 2))) < 0) - break; - mdoall = false; - goto domaceagain; + if (mdoall && linktype) + { + // The rest of the links + while (mlengthset > mminlength) + { + spawnee = makemace(linktype, radiusfactor*(mlengthset--), 0); + } + } + + if (mwidthset > 0) + mwidthset *= -1; + else if (!mwidthset + || ((mwidthset = -(mwidthset + ((firsttype == chainlink) ? 1 : 2))) < 0)) + break; + else + mdocenter = mdoall = false; + + } } #undef makemace From 0102da824e462a344ef38c8a868bbe51a3eaea78 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 2 Apr 2018 01:20:32 +0100 Subject: [PATCH 092/212] Make the h-chain repairing safer. --- src/p_mobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index f98943d84..4e1356d61 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8673,9 +8673,9 @@ void P_RemoveMobj(mobj_t *mobj) // Remove any references to other mobjs. P_SetTarget(&mobj->target, P_SetTarget(&mobj->tracer, NULL)); - if (mobj->hnext) + if (mobj->hnext && !P_MobjWasRemoved(mobj->hnext)) P_SetTarget(&mobj->hnext->hprev, mobj->hprev); - if (mobj->hprev) + if (mobj->hprev && !P_MobjWasRemoved(mobj->hprev)) P_SetTarget(&mobj->hprev->hnext, mobj->hnext); P_SetTarget(&mobj->hnext, P_SetTarget(&mobj->hprev, NULL)); From 4051ae8915525d850b754ee12e3e6895ffdfa509 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 2 Apr 2018 21:36:12 +0100 Subject: [PATCH 093/212] * Revamp mace creation again to potentially serve as the foundation for further optimisation (and also not rely on a while (1) loop, which easily went wrong several times whilst I was making changes to it). * Fix minor typoes and other small tweaks in the P_MaceRotate function, which I'm probably about to rewrite again anyways... --- src/p_mobj.c | 123 +++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 59 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 4e1356d61..63d3aa666 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6184,8 +6184,7 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) TVector *res; fixed_t radius, dist, mag, zstore; angle_t fa; - boolean donetwice = false; - boolean dosound = false; + boolean donetwice, dosound = false; mobj_t *mobj = center->hnext, *hnext = NULL; INT32 rot = (baserot &= FINEMASK); @@ -6268,13 +6267,13 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) if (!baseuo[3]) { baseuo[1] = FRACUNIT; - baseuo[3] = center->scale; baseuo[0] = baseuo[2] = 0; + baseuo[3] = center->scale; res = VectorMatrixMultiply(baseuo, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT)); - M_Memcpy(&baseuo, res, sizeof(unit)); + M_Memcpy(&baseuo, res, sizeof(baseuo)); res = VectorMatrixMultiply(baseuo, *RotateZMatrix(center->angle)); - M_Memcpy(&baseuo, res, sizeof(unit)); + M_Memcpy(&baseuo, res, sizeof(baseuo)); } if (mobj->movefactor) @@ -6293,6 +6292,7 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) // Radius of the link's rotation. mag = (dist * mobj->movecount) + mobj->extravalue1; + donetwice = false; maceretry: P_UnsetThingPosition(mobj); @@ -6303,13 +6303,12 @@ maceretry: // Add on the appropriate distances to the center's co-ordinates. if (mag) { - zstore = FixedMul(unit[2], mag); mobj->x += FixedMul(unit[0], mag); mobj->y += FixedMul(unit[1], mag); + zstore = FixedMul(unit[2], mag) + unitoffset[2]; } else - zstore = 0; - zstore += unitoffset[2]; + zstore = unitoffset[2]; mobj->x += unitoffset[0]; mobj->y += unitoffset[1]; @@ -6323,7 +6322,7 @@ maceretry: mobj->z += zstore; #if 0 // toaster's testing flashie! - if (!mobj->threshold && !mobj->friction && !(leveltime & TICRATE)) // I had a brainfart and the flashing isn't exactly what I expected it to be, but it's actually much more useful. + if (!donetwice && mobj->movefactor != -5 && !(leveltime & TICRATE)) // I had a brainfart and the flashing isn't exactly what I expected it to be, but it's actually much more useful. mobj->flags2 ^= MF2_DONTDRAW; #endif @@ -9772,11 +9771,11 @@ void P_SpawnMapThing(mapthing_t *mthing) case MT_FIREBARPOINT: case MT_CUSTOMMACEPOINT: { - fixed_t mlength, mlengthmax, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor; + fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor; angle_t mspokeangle; mobjtype_t chainlink, macetype, firsttype, linktype; - boolean mdoall = true, mdocenter; - mobj_t *spawnee, *hprev; + boolean mdosound, mdocenter; + mobj_t *spawnee = NULL, *hprev = mobj; mobjflag_t mflagsapply; mobjflag2_t mflags2apply; mobjeflag_t meflagsapply; @@ -9815,6 +9814,8 @@ ML_EFFECT4 : Don't clip inside the ground mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360; if ((mminlength = -sides[lines[line].sidenum[0]].rowoffset>>FRACBITS) < 0) mminlength = 0; + else if (mminlength > mlength-1) + mminlength = mlength-1; mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360; myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360; @@ -9940,22 +9941,23 @@ ML_EFFECT4 : Don't clip inside the ground mphase = (FixedAngle(mphase*FRACUNIT)>>ANGLETOFINESHIFT); mroll = (FixedAngle(mroll*FRACUNIT)>>ANGLETOFINESHIFT); - hprev = mobj; - -#define makemace(mobjtype, dist, moreflags2) P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\ - P_SetTarget(&spawnee->tracer, mobj);\ - spawnee->threshold = mphase;\ - spawnee->friction = mroll;\ - spawnee->movefactor = mwidthset;\ - spawnee->movecount = dist;\ - spawnee->angle = myaw;\ - spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ - spawnee->flags2 |= (mflags2apply|moreflags2);\ - spawnee->eflags |= meflagsapply;\ - P_SetTarget(&hprev->hnext, spawnee);\ - P_SetTarget(&spawnee->hprev, hprev);\ - hprev = spawnee +#define makemace(mobjtype, dist, moreflags2) {\ + spawnee = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\ + P_SetTarget(&spawnee->tracer, mobj);\ + spawnee->threshold = mphase;\ + spawnee->friction = mroll;\ + spawnee->movefactor = mwidthset;\ + spawnee->movecount = dist;\ + spawnee->angle = myaw;\ + spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ + spawnee->flags2 |= (mflags2apply|moreflags2);\ + spawnee->eflags |= meflagsapply;\ + P_SetTarget(&hprev->hnext, spawnee);\ + P_SetTarget(&spawnee->hprev, hprev);\ + hprev = spawnee;\ +} + mdosound = (mspeed && !(mthing->options & MTF_OBJECTSPECIAL)); mdocenter = (lines[line].flags & ML_EFFECT3); // The actual spawning of spokes @@ -9973,7 +9975,7 @@ ML_EFFECT4 : Don't clip inside the ground continue; firsttype = linktype = chainlink; - mlengthmax = 1 + (mlength - 1)*radiusfactor; + mmaxlength = 1 + (mlength - 1)*radiusfactor; radiusfactor = 1; } else @@ -9995,43 +9997,46 @@ ML_EFFECT4 : Don't clip inside the ground firsttype = macetype; } - mlengthmax = mlength; + mmaxlength = mlength; } mwidthset = mwidth; - mdoall = true; - while (1) + //fixed_t base = 0; + mlengthset = mminlength; + + if (mdocenter) // Innermost mace/link + makemace(macetype, 0, 0); + + //base = mlengthset*((mobjinfo[macetype].speed) ? mobjinfo[macetype].speed : mobjinfo[MT_SMALLMACECHAIN].speed); + + while ((++mlengthset) < mmaxlength) + makemace(linktype, radiusfactor*mlengthset, 0); + + // Outermost mace/link + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + + if (!mwidth) { - mlengthset = mlengthmax; + if (mdosound && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; + } + else + { + while ((mwidthset -= ((firsttype == chainlink) ? 1 : 2)) > -mwidth) + { + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; + } + + // Outermost mace/link again! + makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); + + while (mlengthset > mminlength) + makemace(linktype, radiusfactor*(mlengthset--), 0); if (mdocenter) // Innermost mace/link - { - spawnee = makemace(macetype, 0, 0); - } - - // Outermost mace/link - spawnee = makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); - - if (mspeed && (mwidthset == msound) && !(mthing->options & MTF_OBJECTSPECIAL) && mnumspokes <= mmin) // Can it make a sound? - spawnee->flags2 |= MF2_BOSSNOTRAP; - - if (mdoall && linktype) - { - // The rest of the links - while (mlengthset > mminlength) - { - spawnee = makemace(linktype, radiusfactor*(mlengthset--), 0); - } - } - - if (mwidthset > 0) - mwidthset *= -1; - else if (!mwidthset - || ((mwidthset = -(mwidthset + ((firsttype == chainlink) ? 1 : 2))) < 0)) - break; - else - mdocenter = mdoall = false; - + makemace(macetype, 0, 0); } } From 156cc031ea22d59296644c7f5d2c836746ad0937 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 3 Apr 2018 01:10:10 +0100 Subject: [PATCH 094/212] * Optimise them even further... AGAIN! Using an offset-based system rather than a multiplication-based one... * Again, tweak the spawning code to take maximum advantage of these gains. * Fix potential crashes with MT_NULL mace/chain types supplied. * #ifdef out the height-clipping code. It needs more TLC than I can give it right now, and the existing behaviour is less obviously broken (sadly enough). * Fix chainmace points, which were apparently broken without anyone realising. --- src/p_mobj.c | 203 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 129 insertions(+), 74 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 63d3aa666..286357964 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6180,11 +6180,11 @@ static void P_NightsItemChase(mobj_t *thing) // void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) { - TVector unit, baseuo, unitoffset; + TVector unit_lengthways, unit_sideways, pos_lengthways, pos_sideways; TVector *res; - fixed_t radius, dist, mag, zstore; + fixed_t radius, dist, zstore; angle_t fa; - boolean donetwice, dosound = false; + boolean dosound = false; mobj_t *mobj = center->hnext, *hnext = NULL; INT32 rot = (baserot &= FINEMASK); @@ -6193,7 +6193,7 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) INT32 lastthreshold = FINEMASK; // needs to never be equal at start of loop fixed_t lastfriction = INT32_MIN; // ditto; almost certainly never, but... - fixed_t movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = baseuo[3] = 0; + dist = pos_sideways[0] = pos_sideways[1] = pos_sideways[2] = pos_sideways[3] = unit_sideways[3] = pos_lengthways[0] = pos_lengthways[1] = pos_lengthways[2] = pos_lengthways[3] = 0; while (mobj) { @@ -6211,10 +6211,15 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) rot = (baserot + mobj->threshold) & FINEMASK; prevrot = (baseprevrot + mobj->threshold) & FINEMASK; - fa = (FixedAngle(center->movefactor*FRACUNIT) >> ANGLETOFINESHIFT); // mpinch - radius = FINECOSINE(fa); - unit[1] = -FixedMul(FINESINE(fa), radius); - unit[3] = center->scale; + pos_lengthways[0] = pos_lengthways[1] = pos_lengthways[2] = pos_lengthways[3] = 0; + + dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); + dist = ((center->scale == FRACUNIT) ? dist : FixedMul(dist, center->scale)); + + fa = (FixedAngle(center->movefactor*FRACUNIT) >> ANGLETOFINESHIFT); + radius = FixedMul(dist, FINECOSINE(fa)); + unit_lengthways[1] = -FixedMul(dist, FINESINE(fa)); + unit_lengthways[3] = FRACUNIT; // Swinging Chain. if (center->flags2 & MF2_STRONGBOX) @@ -6224,12 +6229,11 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) if ((prevswingmag > 0) != (swingmag > 0)) // just passed its lowest point dosound = true; - //S_StartSound(mobj, mobj->info->activesound); fa = ((FixedAngle(swingmag) >> ANGLETOFINESHIFT) + mobj->friction) & FINEMASK; - unit[0] = FixedMul(FINESINE(fa), -radius); - unit[2] = FixedMul(FINECOSINE(fa), -radius); + unit_lengthways[0] = FixedMul(FINESINE(fa), -radius); + unit_lengthways[2] = FixedMul(FINECOSINE(fa), -radius); } // Rotating Chain. else @@ -6240,15 +6244,15 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) if (!(prevfa > (FINEMASK/2)) && (fa > (FINEMASK/2))) // completed a full swing dosound = true; - unit[0] = FixedMul(FINECOSINE(fa), radius); - unit[2] = FixedMul(FINESINE(fa), radius); + unit_lengthways[0] = FixedMul(FINECOSINE(fa), radius); + unit_lengthways[2] = FixedMul(FINESINE(fa), radius); } // Calculate the angle matrixes for the link. - res = VectorMatrixMultiply(unit, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT)); - M_Memcpy(&unit, res, sizeof(unit)); - res = VectorMatrixMultiply(unit, *RotateZMatrix(center->angle)); - M_Memcpy(&unit, res, sizeof(unit)); + res = VectorMatrixMultiply(unit_lengthways, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT)); + M_Memcpy(&unit_lengthways, res, sizeof(unit_lengthways)); + res = VectorMatrixMultiply(unit_lengthways, *RotateZMatrix(center->angle)); + M_Memcpy(&unit_lengthways, res, sizeof(unit_lengthways)); lastthreshold = mobj->threshold; lastfriction = mobj->friction; @@ -6260,40 +6264,65 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) dosound = false; } - dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); - - if (dist*mobj->movefactor != movefac) + if (pos_sideways[3] != mobj->movefactor) { - if (!baseuo[3]) + if (!unit_sideways[3]) { - baseuo[1] = FRACUNIT; - baseuo[0] = baseuo[2] = 0; - baseuo[3] = center->scale; + unit_sideways[1] = dist; + unit_sideways[0] = unit_sideways[2] = 0; + unit_sideways[3] = FRACUNIT; - res = VectorMatrixMultiply(baseuo, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT)); - M_Memcpy(&baseuo, res, sizeof(baseuo)); - res = VectorMatrixMultiply(baseuo, *RotateZMatrix(center->angle)); - M_Memcpy(&baseuo, res, sizeof(baseuo)); + res = VectorMatrixMultiply(unit_sideways, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT)); + M_Memcpy(&unit_sideways, res, sizeof(unit_sideways)); + res = VectorMatrixMultiply(unit_sideways, *RotateZMatrix(center->angle)); + M_Memcpy(&unit_sideways, res, sizeof(unit_sideways)); } - if (mobj->movefactor) + if (pos_sideways[3] > mobj->movefactor) { - movefac = dist*mobj->movefactor; - unitoffset[0] = FixedMul(movefac, baseuo[0]); - unitoffset[1] = FixedMul(movefac, baseuo[1]); - unitoffset[2] = FixedMul(movefac, baseuo[2]); + do + { + pos_sideways[0] -= unit_sideways[0]; + pos_sideways[1] -= unit_sideways[1]; + pos_sideways[2] -= unit_sideways[2]; + } + while ((--pos_sideways[3]) != mobj->movefactor); } else - movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = 0; + { + do + { + pos_sideways[0] += unit_sideways[0]; + pos_sideways[1] += unit_sideways[1]; + pos_sideways[2] += unit_sideways[2]; + } + while ((++pos_sideways[3]) != mobj->movefactor); + } } hnext = mobj->hnext; // just in case the mobj is removed - // Radius of the link's rotation. - mag = (dist * mobj->movecount) + mobj->extravalue1; + if (pos_lengthways[3] > mobj->movecount) + { + do + { + pos_lengthways[0] -= unit_lengthways[0]; + pos_lengthways[1] -= unit_lengthways[1]; + pos_lengthways[2] -= unit_lengthways[2]; + } + while ((--pos_lengthways[3]) != mobj->movecount); + } + else if (pos_lengthways[3] < mobj->movecount) + { + do + { + pos_lengthways[0] += unit_lengthways[0]; + pos_lengthways[1] += unit_lengthways[1]; + pos_lengthways[2] += unit_lengthways[2]; + } + while ((++pos_lengthways[3]) != mobj->movecount); + } - donetwice = false; -maceretry: P_UnsetThingPosition(mobj); mobj->x = center->x; @@ -6301,17 +6330,17 @@ maceretry: mobj->z = center->z; // Add on the appropriate distances to the center's co-ordinates. - if (mag) + if (pos_lengthways[3]) { - mobj->x += FixedMul(unit[0], mag); - mobj->y += FixedMul(unit[1], mag); - zstore = FixedMul(unit[2], mag) + unitoffset[2]; + mobj->x += pos_lengthways[0]; + mobj->y += pos_lengthways[1]; + zstore = pos_lengthways[2] + pos_sideways[2]; } else - zstore = unitoffset[2]; + zstore = pos_sideways[2]; - mobj->x += unitoffset[0]; - mobj->y += unitoffset[1]; + mobj->x += pos_sideways[0]; + mobj->y += pos_sideways[1]; // Cut the height to align the link with the axis. if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN) @@ -6322,41 +6351,40 @@ maceretry: mobj->z += zstore; #if 0 // toaster's testing flashie! - if (!donetwice && mobj->movefactor != -5 && !(leveltime & TICRATE)) // I had a brainfart and the flashing isn't exactly what I expected it to be, but it's actually much more useful. + if (!(mobj->movecount & 1) && !(leveltime & TICRATE)) // I had a brainfart and the flashing isn't exactly what I expected it to be, but it's actually much more useful. mobj->flags2 ^= MF2_DONTDRAW; #endif P_SetThingPosition(mobj); - if (!mag || donetwice || P_MobjWasRemoved(mobj)) +#if 0 // toaster's height-clipping dealie! + if (!pos_lengthways[3] || P_MobjWasRemoved(mobj) || (mobj->flags & MF_NOCLIPHEIGHT)) goto cont; - if (mobj->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)) - goto cont; - - if ((fa = ((mobj->tracer->threshold & (FINEMASK/2)) << ANGLETOFINESHIFT)) > ANGLE_45 && fa < ANGLE_135) // only move towards center when the motion is towards/away from the ground, rather than alongside it + if ((fa = ((center->threshold & (FINEMASK/2)) << ANGLETOFINESHIFT)) > ANGLE_45 && fa < ANGLE_135) // only move towards center when the motion is towards/away from the ground, rather than alongside it goto cont; if (mobj->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(mobj, mobj->subsector->sector, 2); - // Variable reuse if (mobj->floorz > mobj->z) - dist = (mobj->floorz - mobj->tracer->z); + zstore = (mobj->floorz - zstore); else if (mobj->ceilingz < mobj->z) - dist = (mobj->ceilingz - mobj->tracer->z); + zstore = (mobj->ceilingz - mobj->height - zstore); else goto cont; - if ((dist = FixedDiv(dist, zstore)) > FRACUNIT) - goto cont; + zstore = FixedDiv(zstore, dist); // Still needs work... scaling factor is wrong! - mag = FixedMul(mag, dist); - donetwice = true; - dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed); - goto maceretry; + P_UnsetThingPosition(mobj); + + mobj->x -= FixedMul(unit_lengthways[0], zstore); + mobj->y -= FixedMul(unit_lengthways[1], zstore); + + P_SetThingPosition(mobj); cont: +#endif mobj = hnext; } } @@ -9771,7 +9799,7 @@ void P_SpawnMapThing(mapthing_t *mthing) case MT_FIREBARPOINT: case MT_CUSTOMMACEPOINT: { - fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor; + fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor; angle_t mspokeangle; mobjtype_t chainlink, macetype, firsttype, linktype; boolean mdosound, mdocenter; @@ -9848,7 +9876,7 @@ ML_EFFECT4 : Don't clip inside the ground if (mnumnospokes > 0 && (mnumnospokes < mnumspokes)) mnumnospokes = mnumspokes/mnumnospokes; else - mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes - 1) : 0); + mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes) : 0); mobj->lastlook = mspeed; mobj->movecount = mobj->lastlook; @@ -9894,7 +9922,7 @@ ML_EFFECT4 : Don't clip inside the ground break; } - if (!macetype) + if (!macetype && !chainlink) break; if (mobj->type != MT_CHAINPOINT) @@ -9958,7 +9986,7 @@ ML_EFFECT4 : Don't clip inside the ground } mdosound = (mspeed && !(mthing->options & MTF_OBJECTSPECIAL)); - mdocenter = (lines[line].flags & ML_EFFECT3); + mdocenter = (macetype && (lines[line].flags & ML_EFFECT3)); // The actual spawning of spokes while (mnumspokes-- > 0) @@ -9999,6 +10027,7 @@ ML_EFFECT4 : Don't clip inside the ground mmaxlength = mlength; } + widthfactor = ((firsttype == chainlink) ? 1 : 2); mwidthset = mwidth; //fixed_t base = 0; @@ -10009,11 +10038,18 @@ ML_EFFECT4 : Don't clip inside the ground //base = mlengthset*((mobjinfo[macetype].speed) ? mobjinfo[macetype].speed : mobjinfo[MT_SMALLMACECHAIN].speed); - while ((++mlengthset) < mmaxlength) - makemace(linktype, radiusfactor*mlengthset, 0); + // Out from the center... + if (linktype) + { + while ((++mlengthset) < mmaxlength) + makemace(linktype, radiusfactor*mlengthset, 0); + } + else + mlengthset = mmaxlength; // Outermost mace/link - makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + if (firsttype) + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); if (!mwidth) { @@ -10022,18 +10058,37 @@ ML_EFFECT4 : Don't clip inside the ground } else { - while ((mwidthset -= ((firsttype == chainlink) ? 1 : 2)) > -mwidth) + // Across the bar! + if (!firsttype) + mwidthset = -mwidth; + else if (mwidth > 0) { - makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); - if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? - spawnee->flags2 |= MF2_BOSSNOTRAP; + while ((mwidthset -= widthfactor) > -mwidth) + { + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; + } } + else + { + while ((mwidthset += widthfactor) < -mwidth) + { + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; + } + } + mwidth = -mwidth; // Outermost mace/link again! - makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); + if (firsttype) + makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); - while (mlengthset > mminlength) - makemace(linktype, radiusfactor*(mlengthset--), 0); + // ...and then back into the center! + if (linktype) + while (mlengthset > mminlength) + makemace(linktype, radiusfactor*(mlengthset--), 0); if (mdocenter) // Innermost mace/link makemace(macetype, 0, 0); From 4f3f647f5b31266445307a470a3f771bfe567721 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 3 Apr 2018 01:46:42 +0100 Subject: [PATCH 095/212] A minor assortment of changes. --- src/p_inter.c | 6 +++--- src/p_mobj.c | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 82187f533..88fa7d57b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1503,10 +1503,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->powers[pw_flashing]) return; - if (special->movefactor && special->tracer && (angle_t)special->tracer->angle != ANGLE_90 && (angle_t)special->tracer->angle != ANGLE_270) + if (special->movefactor && special->tracer && special->tracer->angle != ANGLE_90 && special->tracer->angle != ANGLE_270) { // I don't expect you to understand this, Mr Bond... - angle_t ang = R_PointToAngle2(special->x, special->y, toucher->x, toucher->y) - special->tracer->threshold; - if ((special->movefactor > 0) == ((angle_t)special->tracer->angle > ANGLE_90 && (angle_t)special->tracer->angle < ANGLE_270)) + angle_t ang = R_PointToAngle2(special->x, special->y, toucher->x, toucher->y) - special->tracer->angle; + if ((special->movefactor > 0) == (special->tracer->angle > ANGLE_90 && special->tracer->angle < ANGLE_270)) ang += ANGLE_180; if (ang < ANGLE_180) return; // I expect you to die. diff --git a/src/p_mobj.c b/src/p_mobj.c index 286357964..3660f1e5e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9959,6 +9959,8 @@ ML_EFFECT4 : Don't clip inside the ground else radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); + widthfactor = ((firsttype == chainlink) ? 1 : 2); + mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP|MF_NOCLIPHEIGHT)); mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0); meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0); @@ -10004,7 +10006,7 @@ ML_EFFECT4 : Don't clip inside the ground firsttype = linktype = chainlink; mmaxlength = 1 + (mlength - 1)*radiusfactor; - radiusfactor = 1; + radiusfactor = widthfactor = 1; } else { @@ -10023,21 +10025,18 @@ ML_EFFECT4 : Don't clip inside the ground } firsttype = macetype; + widthfactor = 2; } mmaxlength = mlength; } - widthfactor = ((firsttype == chainlink) ? 1 : 2); mwidthset = mwidth; - //fixed_t base = 0; mlengthset = mminlength; if (mdocenter) // Innermost mace/link makemace(macetype, 0, 0); - //base = mlengthset*((mobjinfo[macetype].speed) ? mobjinfo[macetype].speed : mobjinfo[MT_SMALLMACECHAIN].speed); - // Out from the center... if (linktype) { From 759ea8cb4200e1c99e9450595965db23c798e8dc Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 3 Apr 2018 16:11:07 -0400 Subject: [PATCH 096/212] Indentation fixup --- src/d_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index ea24430ec..b8f24e4b6 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1230,7 +1230,9 @@ void D_SRB2Main(void) nomidimusic = nodigimusic = true; } else - CONS_Printf("S_Init(): Setting up sound.\n"); + { + CONS_Printf("S_Init(): Setting up sound.\n"); + } if (M_CheckParm("-nosound")) nosound = true; if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic @@ -1245,7 +1247,7 @@ void D_SRB2Main(void) I_StartupSound(); I_InitMusic(); S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value); - + CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); From 8bd91bd2f2772b4c4392b161f846fd3029eea09a Mon Sep 17 00:00:00 2001 From: Wolfy Date: Thu, 5 Apr 2018 03:23:27 -0500 Subject: [PATCH 097/212] THZ Hardcoding Feel free to reorganize as necessary. --- src/dehacked.c | 20 ++++++++++ src/info.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 22 +++++++++++ src/p_mobj.c | 11 ++++++ 4 files changed, 155 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index c172549e1..b2d3bff3a 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4700,6 +4700,23 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // THZ Plant "S_THZFLOWERA", "S_THZFLOWERB", + "S_YELLOWSPINFLOWER", + + // THZ Tree + "S_THZTREE", + "S_THZTREEBRANCH1", + "S_THZTREEBRANCH2", + "S_THZTREEBRANCH3", + "S_THZTREEBRANCH4", + "S_THZTREEBRANCH5", + "S_THZTREEBRANCH6", + "S_THZTREEBRANCH7", + "S_THZTREEBRANCH8", + "S_THZTREEBRANCH9", + "S_THZTREEBRANCH10", + "S_THZTREEBRANCH11", + "S_THZTREEBRANCH12", + "S_THZTREEBRANCH13", // THZ Alarm "S_ALARM1", @@ -6129,7 +6146,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Techno Hill Scenery "MT_THZFLOWER1", + "MT_THZTREE", + "MT_THZTREEBRANCH", "MT_THZFLOWER2", + "MT_YELLOWSPINFLOWER", "MT_ALARM", // Deep Sea Scenery diff --git a/src/info.c b/src/info.c index acb12379a..256d430ae 100644 --- a/src/info.c +++ b/src/info.c @@ -191,7 +191,9 @@ char sprnames[NUMSPRITES + 1][5] = // Techno Hill Scenery "THZP", // Techno Hill Zone Plant + "THZT", // THZ Tree "FWR5", // Another one + "FWR6", "ALRM", // THZ2 Alarm // Deep Sea Scenery @@ -1911,6 +1913,25 @@ state_t states[NUMSTATES] = {SPR_THZP, FF_ANIMATE, -1, {NULL}, 7, 4, S_NULL}, // S_THZFLOWERA {SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERB + {SPR_FWR6, FF_ANIMATE, 0, {NULL}, 19, 2, S_NULL}, // S_YELLOWSPINFLOWER + + // THZ Tree + {SPR_THZT, 0, -1, {NULL}, 0, 0, S_THZTREE}, // S_THZTREE + + // THZ Tree Branches + {SPR_THZT, 1|FF_PAPERSPRITE, 40, {NULL}, 0, 0, S_THZTREEBRANCH2}, // S_THZTREEBRANCH1 + {SPR_THZT, 2|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH3}, // S_THZTREEBRANCH2 + {SPR_THZT, 3|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH4}, // S_THZTREEBRANCH3 + {SPR_THZT, 4|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH5}, // S_THZTREEBRANCH4 + {SPR_THZT, 5|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH6}, // S_THZTREEBRANCH5 + {SPR_THZT, 6|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH7}, // S_THZTREEBRANCH6 + {SPR_THZT, 7|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH8}, // S_THZTREEBRANCH7 + {SPR_THZT, 8|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH9}, // S_THZTREEBRANCH8 + {SPR_THZT, 9|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH10}, // S_THZTREEBRANCH9 + {SPR_THZT, 10|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH11},// S_THZTREEBRANCH10 + {SPR_THZT, 11|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH12},// S_THZTREEBRANCH11 + {SPR_THZT, 12|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH13},// S_THZTREEBRANCH12 + {SPR_THZT, 13|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH1}, // S_THZTREEBRANCH13 // THZ Alarm {SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1 @@ -8583,6 +8604,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_THZTREE + 904, // doomednum + S_THZTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_THZTREEBRANCH + -1, // doomednum + S_THZTREEBRANCH1,// spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 1*FRACUNIT, // radius + 1*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_THZFLOWER2 902, // doomednum S_THZFLOWERB, // spawnstate @@ -8609,6 +8684,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, + + { // MT_YELLOWSPINFLOWER + 903, // doomednum + S_YELLOWSPINFLOWER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, { // MT_ALARM 901, // doomednum diff --git a/src/info.h b/src/info.h index 35a3f5f15..2d368094d 100644 --- a/src/info.h +++ b/src/info.h @@ -390,7 +390,9 @@ typedef enum sprite // Techno Hill Scenery SPR_THZP, // THZ1 Flower + SPR_THZT, // THZ Tree SPR_FWR5, // Another flower + SPR_FWR6, SPR_ALRM, // THZ2 Alarm // Deep Sea Scenery @@ -2019,6 +2021,23 @@ typedef enum state // THZ Plant S_THZFLOWERA, S_THZFLOWERB, + S_YELLOWSPINFLOWER, + + // THZ Tree + S_THZTREE, + S_THZTREEBRANCH1, + S_THZTREEBRANCH2, + S_THZTREEBRANCH3, + S_THZTREEBRANCH4, + S_THZTREEBRANCH5, + S_THZTREEBRANCH6, + S_THZTREEBRANCH7, + S_THZTREEBRANCH8, + S_THZTREEBRANCH9, + S_THZTREEBRANCH10, + S_THZTREEBRANCH11, + S_THZTREEBRANCH12, + S_THZTREEBRANCH13, // THZ Alarm S_ALARM1, @@ -3468,7 +3487,10 @@ typedef enum mobj_type // Techno Hill Scenery MT_THZFLOWER1, + MT_THZTREE, + MT_THZTREEBRANCH, MT_THZFLOWER2, + MT_YELLOWSPINFLOWER, MT_ALARM, // Deep Sea Scenery diff --git a/src/p_mobj.c b/src/p_mobj.c index 8695d57e4..cfc43cda2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8433,6 +8433,17 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BLUETEAMRING: mobj->color = skincolor_blueteam; break; + case MT_THZTREE: + { + mobj_t *branch1 = P_SpawnMobj(mobj->x+FRACUNIT, mobj->y, mobj->z, MT_THZTREEBRANCH); + mobj_t *branch2 = P_SpawnMobj(mobj->x, mobj->y+FRACUNIT, mobj->z, MT_THZTREEBRANCH); + mobj_t *branch3 = P_SpawnMobj(mobj->x-FRACUNIT, mobj->y, mobj->z, MT_THZTREEBRANCH); + + branch1->angle = mobj->angle + ANGLE_22h; + branch2->angle = mobj->angle + ANGLE_157h; + branch3->angle = mobj->angle + ANGLE_270; + } + break; case MT_RING: case MT_COIN: case MT_BLUEBALL: From ca8e14d5e9137e3fb838731c98d96025a9f3426b Mon Sep 17 00:00:00 2001 From: Wolfy Date: Thu, 5 Apr 2018 12:49:39 -0500 Subject: [PATCH 098/212] Revert "THZ Hardcoding" This reverts commit 8bd91bd2f2772b4c4392b161f846fd3029eea09a. Note to self: read through the fucking merge requests --- src/dehacked.c | 20 ---------- src/info.c | 102 ------------------------------------------------- src/info.h | 22 ----------- src/p_mobj.c | 11 ------ 4 files changed, 155 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b2d3bff3a..c172549e1 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4700,23 +4700,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // THZ Plant "S_THZFLOWERA", "S_THZFLOWERB", - "S_YELLOWSPINFLOWER", - - // THZ Tree - "S_THZTREE", - "S_THZTREEBRANCH1", - "S_THZTREEBRANCH2", - "S_THZTREEBRANCH3", - "S_THZTREEBRANCH4", - "S_THZTREEBRANCH5", - "S_THZTREEBRANCH6", - "S_THZTREEBRANCH7", - "S_THZTREEBRANCH8", - "S_THZTREEBRANCH9", - "S_THZTREEBRANCH10", - "S_THZTREEBRANCH11", - "S_THZTREEBRANCH12", - "S_THZTREEBRANCH13", // THZ Alarm "S_ALARM1", @@ -6146,10 +6129,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Techno Hill Scenery "MT_THZFLOWER1", - "MT_THZTREE", - "MT_THZTREEBRANCH", "MT_THZFLOWER2", - "MT_YELLOWSPINFLOWER", "MT_ALARM", // Deep Sea Scenery diff --git a/src/info.c b/src/info.c index 256d430ae..acb12379a 100644 --- a/src/info.c +++ b/src/info.c @@ -191,9 +191,7 @@ char sprnames[NUMSPRITES + 1][5] = // Techno Hill Scenery "THZP", // Techno Hill Zone Plant - "THZT", // THZ Tree "FWR5", // Another one - "FWR6", "ALRM", // THZ2 Alarm // Deep Sea Scenery @@ -1913,25 +1911,6 @@ state_t states[NUMSTATES] = {SPR_THZP, FF_ANIMATE, -1, {NULL}, 7, 4, S_NULL}, // S_THZFLOWERA {SPR_FWR5, FF_ANIMATE, -1, {NULL}, 19, 2, S_NULL}, // S_THZFLOWERB - {SPR_FWR6, FF_ANIMATE, 0, {NULL}, 19, 2, S_NULL}, // S_YELLOWSPINFLOWER - - // THZ Tree - {SPR_THZT, 0, -1, {NULL}, 0, 0, S_THZTREE}, // S_THZTREE - - // THZ Tree Branches - {SPR_THZT, 1|FF_PAPERSPRITE, 40, {NULL}, 0, 0, S_THZTREEBRANCH2}, // S_THZTREEBRANCH1 - {SPR_THZT, 2|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH3}, // S_THZTREEBRANCH2 - {SPR_THZT, 3|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH4}, // S_THZTREEBRANCH3 - {SPR_THZT, 4|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH5}, // S_THZTREEBRANCH4 - {SPR_THZT, 5|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH6}, // S_THZTREEBRANCH5 - {SPR_THZT, 6|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH7}, // S_THZTREEBRANCH6 - {SPR_THZT, 7|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH8}, // S_THZTREEBRANCH7 - {SPR_THZT, 8|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH9}, // S_THZTREEBRANCH8 - {SPR_THZT, 9|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH10}, // S_THZTREEBRANCH9 - {SPR_THZT, 10|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH11},// S_THZTREEBRANCH10 - {SPR_THZT, 11|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH12},// S_THZTREEBRANCH11 - {SPR_THZT, 12|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH13},// S_THZTREEBRANCH12 - {SPR_THZT, 13|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_THZTREEBRANCH1}, // S_THZTREEBRANCH13 // THZ Alarm {SPR_ALRM, FF_FULLBRIGHT, 35, {A_Scream}, 0, 0, S_ALARM1}, // S_ALARM1 @@ -8604,60 +8583,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_THZTREE - 904, // doomednum - S_THZTREE, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // 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 - 8, // speed - 16*FRACUNIT, // radius - 64*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_SCENERY, // flags - S_NULL // raisestate - }, - - { // MT_THZTREEBRANCH - -1, // doomednum - S_THZTREEBRANCH1,// spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // 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 - 8, // speed - 1*FRACUNIT, // radius - 1*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_SCENERY, // flags - S_NULL // raisestate - }, - { // MT_THZFLOWER2 902, // doomednum S_THZFLOWERB, // spawnstate @@ -8684,33 +8609,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, - - { // MT_YELLOWSPINFLOWER - 903, // doomednum - S_YELLOWSPINFLOWER, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // 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 - 8, // speed - 16*FRACUNIT, // radius - 64*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags - S_NULL // raisestate - }, { // MT_ALARM 901, // doomednum diff --git a/src/info.h b/src/info.h index 2d368094d..35a3f5f15 100644 --- a/src/info.h +++ b/src/info.h @@ -390,9 +390,7 @@ typedef enum sprite // Techno Hill Scenery SPR_THZP, // THZ1 Flower - SPR_THZT, // THZ Tree SPR_FWR5, // Another flower - SPR_FWR6, SPR_ALRM, // THZ2 Alarm // Deep Sea Scenery @@ -2021,23 +2019,6 @@ typedef enum state // THZ Plant S_THZFLOWERA, S_THZFLOWERB, - S_YELLOWSPINFLOWER, - - // THZ Tree - S_THZTREE, - S_THZTREEBRANCH1, - S_THZTREEBRANCH2, - S_THZTREEBRANCH3, - S_THZTREEBRANCH4, - S_THZTREEBRANCH5, - S_THZTREEBRANCH6, - S_THZTREEBRANCH7, - S_THZTREEBRANCH8, - S_THZTREEBRANCH9, - S_THZTREEBRANCH10, - S_THZTREEBRANCH11, - S_THZTREEBRANCH12, - S_THZTREEBRANCH13, // THZ Alarm S_ALARM1, @@ -3487,10 +3468,7 @@ typedef enum mobj_type // Techno Hill Scenery MT_THZFLOWER1, - MT_THZTREE, - MT_THZTREEBRANCH, MT_THZFLOWER2, - MT_YELLOWSPINFLOWER, MT_ALARM, // Deep Sea Scenery diff --git a/src/p_mobj.c b/src/p_mobj.c index cfc43cda2..8695d57e4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8433,17 +8433,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BLUETEAMRING: mobj->color = skincolor_blueteam; break; - case MT_THZTREE: - { - mobj_t *branch1 = P_SpawnMobj(mobj->x+FRACUNIT, mobj->y, mobj->z, MT_THZTREEBRANCH); - mobj_t *branch2 = P_SpawnMobj(mobj->x, mobj->y+FRACUNIT, mobj->z, MT_THZTREEBRANCH); - mobj_t *branch3 = P_SpawnMobj(mobj->x-FRACUNIT, mobj->y, mobj->z, MT_THZTREEBRANCH); - - branch1->angle = mobj->angle + ANGLE_22h; - branch2->angle = mobj->angle + ANGLE_157h; - branch3->angle = mobj->angle + ANGLE_270; - } - break; case MT_RING: case MT_COIN: case MT_BLUEBALL: From 15903c6271e8c215a73ef3baa78015704b2ef3cf Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 6 Apr 2018 14:42:49 +0100 Subject: [PATCH 099/212] * Correct V_PERPLAYER's screen-centered (no snapto flags on a given axis) behaviour. * Fix that one comment Digiku mentioned. ;P * Make extra lives/100 ring rewards consistent between lives being relevant and lives being infinite/not present, which was a problem this branch made evident when Race ended up getting the infinite lives symbol! --- src/p_enemy.c | 9 +---- src/p_user.c | 44 +++++++++++++++++---- src/st_stuff.c | 2 +- src/v_video.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ src/y_inter.c | 11 +++--- 5 files changed, 145 insertions(+), 23 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 9acc8430e..331202cbe 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3243,14 +3243,7 @@ void A_ExtraLife(mobj_t *actor) return; } - // In shooter gametypes, give the player 100 rings instead of an extra life. - if (gametype != GT_COOP && gametype != GT_COMPETITION) - { - P_GivePlayerRings(player, 100); - P_PlayLivesJingle(player); - } - else - P_GiveCoopLives(player, 1, true); + P_GiveCoopLives(player, 1, true); } // Function: A_GiveShield diff --git a/src/p_user.c b/src/p_user.c index b3a8bcf4b..9fb9d4262 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -909,8 +909,12 @@ void P_ResetPlayer(player_t *player) // Gives rings to the player, and does any special things required. // Call this function when you want to increment the player's health. // + void P_GivePlayerRings(player_t *player, INT32 num_rings) { + if (!player) + return; + if (player->bot) player = &players[consoleplayer]; @@ -929,7 +933,7 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) player->rings = 0; // Now extra life bonuses are handled here instead of in P_MovePlayer, since why not? - if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives()) + if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives() && player->lives != 0x7f) { INT32 gainlives = 0; @@ -941,7 +945,12 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) if (gainlives) { - P_GivePlayerLives(player, gainlives); + player->lives += gainlives; + if (player->lives > 99) + player->lives = 99; + else if (player->lives < 1) + player->lives = 1; + P_PlayLivesJingle(player); } } @@ -955,7 +964,30 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) // void P_GivePlayerLives(player_t *player, INT32 numlives) { - if (player->lives == 0x7f) return; + if (!player) + return; + + if (player->bot) + player = &players[consoleplayer]; + + if (gamestate == GS_LEVEL) + { + if (player->lives == 0x7f || (gametype != GT_COOP && gametype != GT_COMPETITION)) + { + P_GivePlayerRings(player, 100*numlives); + return; + } + + if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) + { + UINT8 prevlives = player->lives; + P_GivePlayerRings(player, 100*numlives); + if (player->lives - prevlives >= numlives) + return; + + numlives = (numlives + prevlives - player->lives); + } + } player->lives += numlives; @@ -1159,11 +1191,7 @@ void P_PlayLivesJingle(player_t *player) if (player && !P_IsLocalPlayer(player)) return; - if ((player && player->lives == 0x7f) - || (!player && &players[consoleplayer] && players[consoleplayer].lives == 0x7f) - || (gametype == GT_COOP && (netgame || multiplayer) && cv_cooplives.value == 0)) - S_StartSound(NULL, sfx_lose); - else if (use1upSound) + if (use1upSound) S_StartSound(NULL, sfx_oneup); else if (mariomode) S_StartSound(NULL, sfx_marioa); diff --git a/src/st_stuff.c b/src/st_stuff.c index 6a909580d..ab78595b4 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -776,7 +776,7 @@ static void ST_drawLivesArea(void) } else { - livescount = ((cv_cooplives.value == 0) ? 0x7f : stplyr->lives); + livescount = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0x7f : stplyr->lives); notgreyedout = true; } diff --git a/src/v_video.c b/src/v_video.c index d23e5f4f5..685cd053f 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -542,6 +542,8 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t fixed_t pwidth; // patch width fixed_t offx = 0; // x offset + UINT8 perplayershuffle = 0; + if (rendermode == render_none) return; @@ -639,19 +641,37 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t colfrac <<= 1; x >>= 1; if (stplyr == &players[displayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } else if (stplyr == &players[secondarydisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; x += adjustx; scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; } else if (stplyr == &players[thirddisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; y += adjusty; scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; } else //if (stplyr == &players[fourthdisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; x += adjustx; y += adjusty; scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT; @@ -662,9 +682,15 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t // 2 players { if (stplyr == &players[displayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle = 1; scrn &= ~V_SNAPTOBOTTOM; + } else //if (stplyr == &players[secondarydisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle = 2; y += adjusty; scrn &= ~V_SNAPTOTOP; } @@ -710,6 +736,10 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t x += (vid.width - (BASEVIDWIDTH * dupx)); else if (!(scrn & V_SNAPTOLEFT)) x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + if (perplayershuffle & 4) + x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4; + else if (perplayershuffle & 8) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 4; } if (vid.height != BASEVIDHEIGHT * dupy) { @@ -718,6 +748,10 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t y += (vid.height - (BASEVIDHEIGHT * dupy)); else if (!(scrn & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + if (perplayershuffle & 1) + y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4; + else if (perplayershuffle & 2) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4; } } @@ -792,6 +826,8 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ UINT8 *desttop, *dest; const UINT8 *source, *deststop; + UINT8 perplayershuffle = 0; + if (rendermode == render_none) return; @@ -852,21 +888,39 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ sx >>= 1; w >>= 1; if (stplyr == &players[displayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } else if (stplyr == &players[secondarydisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; x += adjustx; sx += adjustx; scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; } else if (stplyr == &players[thirddisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; y += adjusty; sy += adjusty; scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; } else //if (stplyr == &players[fourthdisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; x += adjustx; sx += adjustx; y += adjusty; @@ -879,9 +933,15 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ // 2 players { if (stplyr == &players[displayplayer]) + { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; scrn &= ~V_SNAPTOBOTTOM; + } else //if (stplyr == &players[secondarydisplayplayer]) { + if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; y += adjusty; sy += adjusty; scrn &= ~V_SNAPTOTOP; @@ -927,6 +987,10 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ x += (vid.width - (BASEVIDWIDTH * dupx)); else if (!(scrn & V_SNAPTOLEFT)) x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + if (perplayershuffle & 4) + x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4; + else if (perplayershuffle & 8) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 4; } if (vid.height != BASEVIDHEIGHT * dupy) { @@ -935,6 +999,10 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ y += (vid.height - (BASEVIDHEIGHT * dupy)); else if (!(scrn & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + if (perplayershuffle & 1) + y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4; + else if (perplayershuffle & 2) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4; } } @@ -1081,6 +1149,8 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) UINT8 *dest; const UINT8 *deststop; + UINT8 perplayershuffle = 0; + if (rendermode == render_none) return; @@ -1104,19 +1174,37 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) w >>= 1; x >>= 1; if (stplyr == &players[displayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } else if (stplyr == &players[secondarydisplayplayer]) { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; x += adjustx; c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; } else if (stplyr == &players[thirddisplayplayer]) { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; y += adjusty; c &= ~V_SNAPTOTOP|V_SNAPTORIGHT; } else //if (stplyr == &players[fourthdisplayplayer]) { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; x += adjustx; y += adjusty; c &= ~V_SNAPTOTOP|V_SNAPTOLEFT; @@ -1127,9 +1215,15 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) // 2 players { if (stplyr == &players[displayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; c &= ~V_SNAPTOBOTTOM; + } else //if (stplyr == &players[secondarydisplayplayer]) { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; y += adjusty; c &= ~V_SNAPTOTOP; } @@ -1160,6 +1254,10 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) x += (vid.width - (BASEVIDWIDTH * dupx)); else if (!(c & V_SNAPTOLEFT)) x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + if (perplayershuffle & 4) + x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4; + else if (perplayershuffle & 8) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 4; } if (vid.height != BASEVIDHEIGHT * dupy) { @@ -1168,6 +1266,10 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) y += (vid.height - (BASEVIDHEIGHT * dupy)); else if (!(c & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + if (perplayershuffle & 1) + y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4; + else if (perplayershuffle & 2) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4; } } diff --git a/src/y_inter.c b/src/y_inter.c index c86dee758..ed9cc4185 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -858,7 +858,7 @@ void Y_Ticker(void) tallydonetic = -1; } - if (intertic < 2*TICRATE) // one second pause before tally begins + if (intertic < 2*TICRATE) // TWO second pause before tally begins, thank you mazmazz return; for (i = 0; i < MAXPLAYERS; i++) @@ -1822,13 +1822,13 @@ static void Y_AwardCoopBonuses(void) players[i].score = MAXSCORE; } - ptlives = (!ultimatemode && !modeattacking) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0; + ptlives = (!ultimatemode && !modeattacking && players[i].lives != 0x7f) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0; if (ptlives) P_GivePlayerLives(&players[i], ptlives); if (i == consoleplayer) { - data.coop.gotlife = ptlives; + data.coop.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives); M_Memcpy(&data.coop.bonuses, &localbonuses, sizeof(data.coop.bonuses)); } } @@ -1866,16 +1866,15 @@ static void Y_AwardSpecialStageBonus(void) players[i].score = MAXSCORE; // grant extra lives right away since tally is faked - ptlives = (!ultimatemode && !modeattacking) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0; + ptlives = (!ultimatemode && !modeattacking && players[i].lives != 0x7f) ? max((players[i].score/50000) - (oldscore/50000), 0) : 0; if (ptlives) P_GivePlayerLives(&players[i], ptlives); if (i == consoleplayer) { + data.spec.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives); M_Memcpy(&data.spec.bonus, &localbonus, sizeof(data.spec.bonus)); - data.spec.gotlife = ptlives; - // Continues related data.spec.continues = min(players[i].continues, 8); if (players[i].gotcontinue) From 3f427d0161a79cfecb447269c873bb66bcd81e76 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 6 Apr 2018 18:40:08 +0100 Subject: [PATCH 100/212] * Improve devmode text. * Make sure showfps never covers anything relevant to the base game. * Tweak spectator text for raising/lowering. * Minor code-smell squishes. --- src/d_netcmd.c | 2 +- src/m_menu.c | 2 +- src/screen.c | 8 +- src/st_stuff.c | 197 ++++++++++++++++++++++++++++++++----------------- 4 files changed, 137 insertions(+), 72 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index cc641b8b0..e01178155 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -313,7 +313,7 @@ static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Centiseconds"} consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-person only"}, {2, "Always"}, {0, NULL}}; -consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display +consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/m_menu.c b/src/m_menu.c index 4857df104..f10c6b653 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1188,7 +1188,7 @@ static menuitem_t OP_VideoOptionsMenu[] = #endif {IT_HEADER, NULL, "Color Profile", NULL, 30}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Brightness (F11)", &cv_globalgamma, 36}, + {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Brightness (F11)", &cv_globalgamma,36}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Saturation", &cv_globalsaturation, 41}, {IT_SUBMENU|IT_STRING, NULL, "Advanced Settings...", &OP_ColorOptionsDef, 46}, diff --git a/src/screen.c b/src/screen.c index 5b16992c7..cd97b62fa 100644 --- a/src/screen.c +++ b/src/screen.c @@ -414,7 +414,7 @@ void SCR_DisplayTicRate(void) tic_t ontic = I_GetTime(); tic_t totaltics = 0; INT32 ticcntcolor = 0; - INT32 offs = (cv_debug ? 8 : 0); + const INT32 h = vid.height-(8*vid.dupy); for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i) fpsgraph[i % TICRATE] = false; @@ -428,9 +428,9 @@ void SCR_DisplayTicRate(void) if (totaltics <= TICRATE/2) ticcntcolor = V_REDMAP; else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP; - V_DrawString(vid.width-((24+(6*offs))*vid.dupx), vid.height-((16-offs)*vid.dupy), - V_YELLOWMAP|V_NOSCALESTART, "FPS"); - V_DrawString(vid.width-(40*vid.dupx), vid.height-(8*vid.dupy), + V_DrawString(vid.width-(72*vid.dupx), h, + V_YELLOWMAP|V_NOSCALESTART, "FPS:"); + V_DrawString(vid.width-(40*vid.dupx), h, ticcntcolor|V_NOSCALESTART, va("%02d/%02u", totaltics, TICRATE)); lasttic = ontic; diff --git a/src/st_stuff.c b/src/st_stuff.c index ab78595b4..3b07d375e 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -453,80 +453,145 @@ static void ST_DrawNightsOverlayNum(fixed_t x /* right border */, fixed_t y, fix // Devmode information static void ST_drawDebugInfo(void) { - INT32 height = 192; + INT32 height = 0; if (!(stplyr->mo && cv_debug)) return; - if (cv_ticrate.value) - height -= 12; +#define VFLAGS V_MONOSPACE|V_SNAPTOTOP|V_SNAPTORIGHT -#define dist 4 -#define VFLAGS V_MONOSPACE|V_SNAPTOBOTTOM|V_SNAPTORIGHT - - if (cv_debug & DBG_BASIC) + if (vid.dupx == 1) { - const fixed_t d = AngleFixed(stplyr->mo->angle); - V_DrawRightAlignedString(320, height - 24, VFLAGS, va("X: %6d", stplyr->mo->x>>FRACBITS)); - V_DrawRightAlignedString(320, height - 16, VFLAGS, va("Y: %6d", stplyr->mo->y>>FRACBITS)); - V_DrawRightAlignedString(320, height - 8, VFLAGS, va("Z: %6d", stplyr->mo->z>>FRACBITS)); - V_DrawRightAlignedString(320, height, VFLAGS, va("A: %6d", FixedInt(d))); + if (cv_debug & DBG_BASIC) + { + const fixed_t d = AngleFixed(stplyr->mo->angle); + V_DrawRightAlignedString(320, 0, VFLAGS, va("X: %6d", stplyr->mo->x>>FRACBITS)); + V_DrawRightAlignedString(320, 8, VFLAGS, va("Y: %6d", stplyr->mo->y>>FRACBITS)); + V_DrawRightAlignedString(320, 16, VFLAGS, va("Z: %6d", stplyr->mo->z>>FRACBITS)); + V_DrawRightAlignedString(320, 24, VFLAGS, va("A: %6d", FixedInt(d))); - height -= (32+dist); + height += 4*9; + } + + if (cv_debug & (DBG_MEMORY|DBG_RANDOMIZER|DBG_DETAILED)) + { + V_DrawRightAlignedThinString(320, height, VFLAGS|V_REDMAP, "INFO NOT AVAILABLE"); + V_DrawRightAlignedThinString(320, 8+height, VFLAGS|V_REDMAP, "AT THIS RESOLUTION"); + } + } + else + { +#define h 4 +#define dist 2 +#define V_DrawDebugLine(str) V_DrawRightAlignedSmallString(320, height, VFLAGS, str);\ + height += h + + if (cv_debug & DBG_MEMORY) + { + V_DrawDebugLine(va("Heap: %8sKB", sizeu1(Z_TotalUsage()>>10))); + + height += dist; + } + + if (cv_debug & DBG_RANDOMIZER) // randomizer testing + { + fixed_t peekres = P_RandomPeek(); + peekres *= 10000; // Change from fixed point + peekres >>= FRACBITS; // to displayable decimal + + V_DrawDebugLine(va("Init: %08x", P_GetInitSeed())); + V_DrawDebugLine(va("Seed: %08x", P_GetRandSeed())); + V_DrawDebugLine(va("== : .%04d", peekres)); + + height += dist; + } + + if (cv_debug & DBG_DETAILED) + { +#define V_DrawDebugFlag(f, str) V_DrawRightAlignedSmallString(w, height, VFLAGS|f, str);\ + w -= 9 + const fixed_t d = AngleFixed(stplyr->drawangle); + INT32 w = 320; + + V_DrawDebugLine(va("SHIELD: %5x", stplyr->powers[pw_shield])); + V_DrawDebugLine(va("SCALE: %5d%%", (stplyr->mo->scale*100)>>FRACBITS)); + V_DrawDebugLine(va("CARRY: %5x", stplyr->powers[pw_carry])); + V_DrawDebugLine(va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime])); + V_DrawDebugLine(va("ABILITY: %3d, %3d", stplyr->charability, stplyr->charability2)); + V_DrawDebugLine(va("ACTIONSPD: %5d", stplyr->actionspd>>FRACBITS)); + V_DrawDebugLine(va("PEEL: %3d", stplyr->dashmode)); + V_DrawDebugLine(va("SCOREADD: %3d", stplyr->scoreadd)); + + // Flags + V_DrawDebugFlag(((stplyr->pflags & PF_SHIELDABILITY) ? V_GREENMAP : V_REDMAP), "SH"); + V_DrawDebugFlag(((stplyr->pflags & PF_THOKKED) ? V_GREENMAP : V_REDMAP), "TH"); + V_DrawDebugFlag(((stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP), "ST"); + V_DrawDebugFlag(((stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP), "SP"); + V_DrawDebugFlag(((stplyr->pflags & PF_NOJUMPDAMAGE) ? V_GREENMAP : V_REDMAP), "ND"); + V_DrawDebugFlag(((stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP), "JD"); + V_DrawDebugFlag(((stplyr->pflags & PF_STARTJUMP) ? V_GREENMAP : V_REDMAP), "SJ"); + V_DrawDebugFlag(0, "PF/SF:"); + height += h; + w = 320; + V_DrawDebugFlag(((stplyr->pflags & PF_INVIS) ? V_GREENMAP : V_REDMAP), "*I"); + V_DrawDebugFlag(((stplyr->pflags & PF_NOCLIP) ? V_GREENMAP : V_REDMAP), "*C"); + V_DrawDebugFlag(((stplyr->pflags & PF_GODMODE) ? V_GREENMAP : V_REDMAP), "*G"); + V_DrawDebugFlag(((stplyr->charflags & SF_SUPER) ? V_GREENMAP : V_REDMAP), "SU"); + V_DrawDebugFlag(((stplyr->pflags & PF_APPLYAUTOBRAKE) ? V_GREENMAP : V_REDMAP), "AA"); + V_DrawDebugFlag(((stplyr->pflags & PF_SLIDING) ? V_GREENMAP : V_REDMAP), "SL"); + V_DrawDebugFlag(((stplyr->pflags & PF_BOUNCING) ? V_GREENMAP : V_REDMAP), "BO"); + V_DrawDebugFlag(((stplyr->pflags & PF_GLIDING) ? V_GREENMAP : V_REDMAP), "GL"); + height += h; + + V_DrawDebugLine(va("CEILINGZ: %6d", stplyr->mo->ceilingz>>FRACBITS)); + V_DrawDebugLine(va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS)); + + V_DrawDebugLine(va("CMOMX: %6d", stplyr->cmomx>>FRACBITS)); + V_DrawDebugLine(va("CMOMY: %6d", stplyr->cmomy>>FRACBITS)); + V_DrawDebugLine(va("PMOMZ: %6d", stplyr->mo->pmomz>>FRACBITS)); + + w = 320; + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_APPLYPMOMZ) ? V_GREENMAP : V_REDMAP), "AP"); + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_SPRUNG) ? V_GREENMAP : V_REDMAP), "SP"); + //V_DrawDebugFlag(((stplyr->mo->eflags & MFE_PUSHED) ? V_GREENMAP : V_REDMAP), "PU"); -- not relevant to players + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_GOOWATER) ? V_GREENMAP : V_REDMAP), "GW"); + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_VERTICALFLIP) ? V_GREENMAP : V_REDMAP), "VF"); + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_JUSTSTEPPEDDOWN) ? V_GREENMAP : V_REDMAP), "JS"); + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_UNDERWATER) ? V_GREENMAP : V_REDMAP), "UW"); + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_TOUCHWATER) ? V_GREENMAP : V_REDMAP), "TW"); + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_JUSTHITFLOOR) ? V_GREENMAP : V_REDMAP), "JH"); + V_DrawDebugFlag(((stplyr->mo->eflags & MFE_ONGROUND) ? V_GREENMAP : V_REDMAP), "OG"); + V_DrawDebugFlag(0, "MFE:"); + height += h; + + V_DrawDebugLine(va("MOMX: %6d", stplyr->rmomx>>FRACBITS)); + V_DrawDebugLine(va("MOMY: %6d", stplyr->rmomy>>FRACBITS)); + V_DrawDebugLine(va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS)); + + V_DrawDebugLine(va("SPEED: %6d", stplyr->speed>>FRACBITS)); + + V_DrawDebugLine(va("DRAWANGLE: %6d", FixedInt(d))); + + height += dist; +#undef V_DrawDebugFlag + } + + if (cv_debug & DBG_BASIC) + { + const fixed_t d = AngleFixed(stplyr->mo->angle); + V_DrawDebugLine(va("X: %6d", stplyr->mo->x>>FRACBITS)); + V_DrawDebugLine(va("Y: %6d", stplyr->mo->y>>FRACBITS)); + V_DrawDebugLine(va("Z: %6d", stplyr->mo->z>>FRACBITS)); + V_DrawDebugLine(va("A: %6d", FixedInt(d))); + + //height += dist; + } } - if (cv_debug & DBG_DETAILED) - { - V_DrawRightAlignedString(320, height - 104, VFLAGS, va("SHIELD: %5x", stplyr->powers[pw_shield])); - V_DrawRightAlignedString(320, height - 96, VFLAGS, va("SCALE: %5d%%", (stplyr->mo->scale*100)/FRACUNIT)); - V_DrawRightAlignedString(320, height - 88, VFLAGS, va("CARRY: %5x", stplyr->powers[pw_carry])); - V_DrawRightAlignedString(320, height - 80, VFLAGS, va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime])); - - // Flags - V_DrawRightAlignedString(304-92, height - 72, VFLAGS, "PF:"); - V_DrawString(304-90, height - 72, VFLAGS|((stplyr->pflags & PF_STARTJUMP) ? V_GREENMAP : V_REDMAP), "SJ"); - V_DrawString(304-72, height - 72, VFLAGS|((stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP), "JD"); - V_DrawString(304-54, height - 72, VFLAGS|((stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP), "SP"); - V_DrawString(304-36, height - 72, VFLAGS|((stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP), "ST"); - V_DrawString(304-18, height - 72, VFLAGS|((stplyr->pflags & PF_THOKKED) ? V_GREENMAP : V_REDMAP), "TH"); - V_DrawString(304, height - 72, VFLAGS|((stplyr->pflags & PF_SHIELDABILITY) ? V_GREENMAP : V_REDMAP), "SH"); - - V_DrawRightAlignedString(320, height - 64, VFLAGS, va("CEILZ: %6d", stplyr->mo->ceilingz>>FRACBITS)); - V_DrawRightAlignedString(320, height - 56, VFLAGS, va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS)); - - V_DrawRightAlignedString(320, height - 48, VFLAGS, va("CNVX: %6d", stplyr->cmomx>>FRACBITS)); - V_DrawRightAlignedString(320, height - 40, VFLAGS, va("CNVY: %6d", stplyr->cmomy>>FRACBITS)); - V_DrawRightAlignedString(320, height - 32, VFLAGS, va("PLTZ: %6d", stplyr->mo->pmomz>>FRACBITS)); - - V_DrawRightAlignedString(320, height - 24, VFLAGS, va("MOMX: %6d", stplyr->rmomx>>FRACBITS)); - V_DrawRightAlignedString(320, height - 16, VFLAGS, va("MOMY: %6d", stplyr->rmomy>>FRACBITS)); - V_DrawRightAlignedString(320, height - 8, VFLAGS, va("MOMZ: %6d", stplyr->mo->momz>>FRACBITS)); - - V_DrawRightAlignedString(320, height, VFLAGS, va("SPEED: %6d", stplyr->speed>>FRACBITS)); - - height -= (112+dist); - } - - if (cv_debug & DBG_RANDOMIZER) // randomizer testing - { - fixed_t peekres = P_RandomPeek(); - peekres *= 10000; // Change from fixed point - peekres >>= FRACBITS; // to displayable decimal - - V_DrawRightAlignedString(320, height - 16, VFLAGS, va("Init: %08x", P_GetInitSeed())); - V_DrawRightAlignedString(320, height - 8, VFLAGS, va("Seed: %08x", P_GetRandSeed())); - V_DrawRightAlignedString(320, height, VFLAGS, va("== : .%04d", peekres)); - - height -= (24+dist); - } - - if (cv_debug & DBG_MEMORY) - { - V_DrawRightAlignedString(320, height, VFLAGS, va("Heap: %7sKB", sizeu1(Z_TotalUsage()>>10))); - } - -#undef VFLAGS +#undef V_DrawDebugLine #undef dist +#undef h +#undef VFLAGS } static void ST_drawScore(void) @@ -1917,8 +1982,8 @@ static void ST_drawTextHUD(void) else textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) - textHUDdraw(M_GetText("\x82""SPIN:""\x80 Sink")) - textHUDdraw(M_GetText("\x82""JUMP:""\x80 Float")) + textHUDdraw(M_GetText("\x82""SPIN:""\x80 Lower")) + textHUDdraw(M_GetText("\x82""JUMP:""\x80 Rise")) dof12 = true; dospecheader = true; From 790e334d19692498466ca2ce30fdd1cc8fc817fa Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 7 Apr 2018 23:10:34 +0100 Subject: [PATCH 101/212] comment goof --- src/p_mobj.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.h b/src/p_mobj.h index ec25855d8..f6ebd3cad 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -194,6 +194,7 @@ typedef enum MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) + // free: to and including 1<<31 } mobjflag2_t; typedef enum From 375c3c584e412e52f57b94f5f991d8735f7e87da Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 8 Apr 2018 13:03:40 +0100 Subject: [PATCH 102/212] =?UTF-8?q?[13:01]=20toaster:=20hey=20[13:01]=20to?= =?UTF-8?q?aster:=20would=20anyone=20object=20if=20i=20pushed=20this=20to?= =?UTF-8?q?=20master=20[13:02]=20toaster:=20so=20my=20changes=20to=20devmo?= =?UTF-8?q?de=20don't=20fuck=20with=20gifs,=20for=20example=20https://cdn.?= =?UTF-8?q?discordapp.com/attachments/428262628893261828/43250092077377126?= =?UTF-8?q?4/srb20575.gif=20[13:02]=20NEV3R:=20=C2=AF\=5F(=E3=83=84)=5F/?= =?UTF-8?q?=C2=AF=20[13:02]=20toaster:=20ok=20i'll=20just=20do=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/st_stuff.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 3b07d375e..a513a028c 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -27,6 +27,8 @@ #include "i_system.h" #include "m_menu.h" #include "m_cheat.h" +#include "m_misc.h" // moviemode +#include "m_anigif.h" // cv_gif_downscale #include "p_setup.h" // NiGHTS grading //random index @@ -460,7 +462,7 @@ static void ST_drawDebugInfo(void) #define VFLAGS V_MONOSPACE|V_SNAPTOTOP|V_SNAPTORIGHT - if (vid.dupx == 1) + if ((moviemode == MM_GIF && cv_gif_downscale.value) || vid.dupx == 1) { if (cv_debug & DBG_BASIC) { From 3fb12cf337dd02bf559b2c7986978d7d56a68d61 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 15 Apr 2018 19:59:57 +0100 Subject: [PATCH 103/212] Don't use CV_StealthSetValue on cv_itemfinder if running the game in dedicated mode --- src/g_game.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index d3c55e0cc..bcae69fda 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3588,7 +3588,8 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean unlocktriggers = 0; // clear itemfinder, just in case - CV_StealthSetValue(&cv_itemfinder, 0); + if (!dedicated) // except in dedicated servers, where it is not registered and can actually I_Error debug builds + CV_StealthSetValue(&cv_itemfinder, 0); } // internal game map From 9cdf87404e3a2e2a0acc6b7861e90c9426f30dd3 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 15 Apr 2018 22:00:31 +0100 Subject: [PATCH 104/212] Rewrote findfile to store whether any of the three paths searched had a bad MD5 rather than just simply being not there. This means that, if the three paths are not the same, you should be able to tell if at least one of them has a file that just had a bad MD5. Most relevant for Linux peeps I expect. Note: Untested as of writing --- src/d_netfil.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/d_netfil.c b/src/d_netfil.c index 172624ad2..6742cfe28 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -990,19 +990,41 @@ filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum) return FS_FOUND; // will never happen, but makes the compiler shut up } +// Rewritten by Monster Iestyn to be less stupid +// Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned +// (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore) filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath) { - filestatus_t homecheck = filesearch(filename, srb2home, wantedmd5sum, false, 10); - if (homecheck == FS_FOUND) - return filesearch(filename, srb2home, wantedmd5sum, completepath, 10); + filestatus_t homecheck; // store result of last file search + boolean badmd5 = false; // store whether md5 was bad from either of the first two searches (if nothing was found in the third) - homecheck = filesearch(filename, srb2path, wantedmd5sum, false, 10); - if (homecheck == FS_FOUND) - return filesearch(filename, srb2path, wantedmd5sum, completepath, 10); + // first, check SRB2's "home" directory + homecheck = filesearch(filename, srb2home, wantedmd5sum, completepath, 10); + if (homecheck == FS_FOUND) // we found the file, so return that we have :) + return FS_FOUND; + else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5 + badmd5 = true; + // if not found at all, just move on without doing anything + + // next, check SRB2's "path" directory + homecheck = filesearch(filename, srb2path, wantedmd5sum, completepath, 10); + + if (homecheck == FS_FOUND) // we found the file, so return that we have :) + return FS_FOUND; + else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5 + badmd5 = true; + // if not found at all, just move on without doing anything + + // finally check "." directory #ifdef _arch_dreamcast - return filesearch(filename, "/cd", wantedmd5sum, completepath, 10); + homecheck = filesearch(filename, "/cd", wantedmd5sum, completepath, 10); #else - return filesearch(filename, ".", wantedmd5sum, completepath, 10); + homecheck = filesearch(filename, ".", wantedmd5sum, completepath, 10); #endif + + if (homecheck != FS_NOTFOUND) // if not found this time, fall back on the below return statement + return homecheck; // otherwise return the result we got + + return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found } From 1eb84f57c5f9035349b7df8f31dc5cb03795df7d Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 26 Apr 2018 20:18:51 +0100 Subject: [PATCH 105/212] * Billiards mines! With support for both above and below water, replacing both the below-and-above-water old mines at once. * Explosion executors. * Minor refactor of P_KillMobj. --- src/dehacked.c | 30 +++--- src/hardware/hw_light.c | 1 + src/info.c | 125 ++++++++++++------------ src/info.h | 31 +++--- src/p_enemy.c | 89 ++++++++++++++++- src/p_inter.c | 207 +++++++++++++++------------------------- src/p_map.c | 25 +++++ src/p_mobj.c | 40 ++------ src/sounds.c | 2 +- 9 files changed, 291 insertions(+), 259 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 83e3177ff..e5bafabad 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1811,6 +1811,8 @@ static actionpointer_t actionpointers[] = {{A_FadeOverlay}, "A_FADEOVERLAY"}, {{A_Boss5Jump}, "A_BOSS5JUMP"}, {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, + {{A_MineExplode}, "A_MINEEXPLODE"}, + {{A_MineRange}, "A_MINERANGE"}, {{NULL}, "NONE"}, @@ -4504,14 +4506,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_STARPOST_ENDSPIN", // Big floating mine - "S_BIGMINE1", - "S_BIGMINE2", - "S_BIGMINE3", - "S_BIGMINE4", - "S_BIGMINE5", - "S_BIGMINE6", - "S_BIGMINE7", - "S_BIGMINE8", + "S_BIGMINE_IDLE", + "S_BIGMINE_ALERT1", + "S_BIGMINE_ALERT2", + "S_BIGMINE_ALERT3", + "S_BIGMINE_SET1", + "S_BIGMINE_SET2", + "S_BIGMINE_SET3", + "S_BIGMINE_BLAST1", + "S_BIGMINE_BLAST2", + "S_BIGMINE_BLAST3", + "S_BIGMINE_BLAST4", + "S_BIGMINE_BLAST5", // Cannon Launcher "S_CANNONLAUNCHER1", @@ -4780,12 +4786,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_LIGHTBEAM10", "S_LIGHTBEAM11", "S_LIGHTBEAM12", - "S_LIGHTBEAM13", - "S_LIGHTBEAM14", - "S_LIGHTBEAM15", - "S_LIGHTBEAM16", - "S_LIGHTBEAM17", - "S_LIGHTBEAM18", // CEZ Chain "S_CEZCHAIN", @@ -6111,7 +6111,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_WALLSPIKEBASE", "MT_STARPOST", "MT_BIGMINE", - "MT_BIGAIRMINE", + "MT_BLASTEXECUTOR", "MT_CANNONLAUNCHER", // Monitor miscellany diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 267666749..0496e6423 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -246,6 +246,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_WSPB &lspr[NOLIGHT], // SPR_STPT &lspr[NOLIGHT], // SPR_BMNE + &lspr[REDBALL_L], // SPR_BMNB // Monitor Boxes &lspr[NOLIGHT], // SPR_MSTV diff --git a/src/info.c b/src/info.c index 9fe41090a..1805c555b 100644 --- a/src/info.c +++ b/src/info.c @@ -134,6 +134,7 @@ char sprnames[NUMSPRITES + 1][5] = "WSPB", // Wall spike base "STPT", // Starpost "BMNE", // Big floating mine + "BMNB", // Monitor Boxes "MSTV", // MiSc TV sprites @@ -1717,14 +1718,18 @@ state_t states[NUMSTATES] = {SPR_STPT, FF_ANIMATE|15, 2, {NULL}, 1, 1, S_STARPOST_FLASH}, // S_STARPOST_ENDSPIN // Big floating mine - {SPR_BMNE, 0, 5, {NULL}, 0, 0, S_BIGMINE2}, // S_BIGMINE1 - {SPR_BMNE, 1, 5, {NULL}, 0, 0, S_BIGMINE3}, // S_BIGMINE2 - {SPR_BMNE, 2, 5, {NULL}, 0, 0, S_BIGMINE4}, // S_BIGMINE3 - {SPR_BMNE, 3, 5, {NULL}, 0, 0, S_BIGMINE5}, // S_BIGMINE4 - {SPR_BMNE, 4, 5, {NULL}, 0, 0, S_BIGMINE6}, // S_BIGMINE5 - {SPR_BMNE, 5, 5, {NULL}, 0, 0, S_BIGMINE7}, // S_BIGMINE6 - {SPR_BMNE, 6, 5, {NULL}, 0, 0, S_BIGMINE8}, // S_BIGMINE7 - {SPR_BMNE, 7, 5, {NULL}, 0, 0, S_BIGMINE1}, // S_BIGMINE8 + {SPR_BMNE, 0, 2, {A_Look}, ((224<z++; // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. - actor->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(actor->angle >> ANGLETOFINESHIFT)); - actor->momy = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINESINE(actor->angle >> ANGLETOFINESHIFT)); + fixedHypotenuse = FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)); // variable reuse + actor->momx = FixedMul(fixedHypotenuse, FINECOSINE(actor->angle >> ANGLETOFINESHIFT)); + actor->momy = FixedMul(fixedHypotenuse, FINESINE(actor->angle >> ANGLETOFINESHIFT)); // Then the vertical axis. No angle-correction needed here. actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT)); // I hope that's all that's needed, ugh @@ -10630,6 +10633,9 @@ void A_Boss5Jump(mobj_t *actor) // void A_LightBeamReset(mobj_t *actor) { + // INT32 locvar1 = var1; + // INT32 locvar2 = var2; + #ifdef HAVE_BLUA if (LUA_CallAction("A_LightBeamReset", actor)) return; @@ -10651,3 +10657,82 @@ void A_LightBeamReset(mobj_t *actor) actor->z = actor->spawnpoint->z*FRACUNIT + P_SignedRandom()*FRACUNIT/2; P_SetThingPosition(actor); } + +// Function: A_MineExplode +// Description: Handles the explosion of a DSZ mine. +// +// var1 = unused +// var2 = unused +// +void A_MineExplode(mobj_t *actor) +{ + // INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MineExplode", actor)) + return; +#endif + + A_Scream(actor); + actor->flags = MF_NOGRAVITY|MF_NOCLIP; + + quake.epicenter = NULL; + quake.radius = 512*FRACUNIT; + quake.intensity = 8*FRACUNIT; + quake.time = TICRATE/3; + + P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT); + P_MobjCheckWater(actor); + + { +#define dist 64 + UINT8 i; + mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE); + S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e)); + P_SpawnMobj(actor->x, actor->y, actor->z, type); + for (i = 0; i < 16; i++) + { + mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT, + actor->y+P_RandomRange(-dist, dist)*FRACUNIT, + actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT, + type); + fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z; + fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx)); + b->momx = FixedDiv(dx, dm)*3; + b->momy = FixedDiv(dy, dm)*3; + b->momz = FixedDiv(dz, dm)*3; + if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop)) + b->flags &= ~MF_NOGRAVITY; + } +#undef dist + + if (actor->watertop != INT32_MAX) + P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH); + } +} + +// Function: A_MineRange +// Description: If the target gets too close, change the state to meleestate. +// +// var1 = Distance to alert at +// var2 = unused +// +void A_MineRange(mobj_t *actor) +{ + fixed_t dm; + INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MineRange", actor)) + return; +#endif + + if (!actor->target) + return; + + dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x)); + if ((dm>>FRACBITS) < locvar1) + P_SetMobjState(actor, actor->info->meleestate); +} diff --git a/src/p_inter.c b/src/p_inter.c index 7892e0bcf..5de8b7fd3 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -412,7 +412,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) //////////////////////////////////////////////////////// /////ENEMIES!!////////////////////////////////////////// //////////////////////////////////////////////////////// - if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) + if (special->type == MT_BIGMINE) + { + special->momx = toucher->momx/3; + special->momy = toucher->momy/3; + special->momz = toucher->momz/3; + toucher->momx /= -8; + toucher->momy /= -8; + toucher->momz /= -8; + special->flags &= ~MF_SPECIAL; + if (special->info->activesound) + S_StartSound(special, special->info->activesound); + P_SetTarget(&special->tracer, toucher); + player->homing = 0; + return; + } + else if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) || player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce) && toucher->z < special->z + special->height && toucher->z + toucher->height > special->z && !(player->powers[pw_shield] & SH_PROTECTSPIKE)) @@ -1529,14 +1544,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Can't jump first frame player->pflags |= PF_JUMPSTASIS; - return; - case MT_BIGMINE: - case MT_BIGAIRMINE: - // Spawn explosion! - P_SpawnMobj(special->x, special->y, special->z, special->info->mass); - P_RadiusAttack(special, special, special->info->damage); - S_StartSound(special, special->info->deathsound); - P_SetMobjState(special, special->info->deathstate); return; case MT_SPECIALSPIKEBALL: if (!useNightsSS && G_IsSpecialStage(gamemap)) // Only for old special stages @@ -2349,78 +2356,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (source && target && target->player && source->player) P_PlayVictorySound(source); // Killer laughs at you. LAUGHS! BWAHAHAHA! -#ifdef OLDANIMALSPAWNING - // Drop stuff. - // This determines the kind of object spawned - // during the death frame of a thing. - if (!mariomode // Don't show birds, etc. in Mario Mode Tails 12-23-2001 - && target->flags & MF_ENEMY) - { - mobjtype_t item; - INT32 prandom; - - switch (target->type) - { - case MT_REDCRAWLA: - case MT_GOLDBUZZ: - case MT_SKIM: - case MT_UNIDUS: - item = MT_FLICKY_02/*MT_BUNNY*/; - break; - - case MT_BLUECRAWLA: - case MT_JETTBOMBER: - case MT_GFZFISH: - item = MT_FLICKY_01/*MT_BIRD*/; - break; - - case MT_JETTGUNNER: - case MT_CRAWLACOMMANDER: - case MT_REDBUZZ: - case MT_DETON: - item = MT_FLICKY_12/*MT_MOUSE*/; - break; - - case MT_GSNAPPER: - case MT_EGGGUARD: - case MT_SPRINGSHELL: - item = MT_FLICKY_11/*MT_COW*/; - break; - - case MT_MINUS: - case MT_VULTURE: - case MT_POINTY: - case MT_YELLOWSHELL: - item = MT_FLICKY_03/*MT_CHICKEN*/; - break; - - case MT_AQUABUZZ: - item = MT_FLICKY_01/*MT_REDBIRD*/; - break; - - default: - if (target->info->doomednum) - prandom = target->info->doomednum%5; // "Random" animal for new enemies. - else - prandom = P_RandomKey(5); // No placable object, just use a random number. - - switch(prandom) - { - default: item = MT_FLICKY_02/*MT_BUNNY*/; break; - case 1: item = MT_FLICKY_01/*MT_BIRD*/; break; - case 2: item = MT_FLICKY_12/*MT_MOUSE*/; break; - case 3: item = MT_FLICKY_11/*MT_COW*/; break; - case 4: item = MT_FLICKY_03/*MT_CHICKEN*/; break; - } - break; - } - - mo = P_SpawnMobj(target->x, target->y, target->z + (target->height / 2) - FixedMul(mobjinfo[item].height / 2, target->scale), item); - mo->destscale = target->scale; - P_SetScale(mo, mo->destscale); - } - else -#endif // Other death animation effects switch(target->type) { @@ -2434,6 +2369,64 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->fuse = target->info->damage; break; + case MT_AQUABUZZ: + if (inflictor && inflictor->player // did a player kill you? Spawn relative to the player so they're bound to get it + && P_AproxDistance(inflictor->x - target->x, inflictor->y - target->y) <= inflictor->radius + target->radius + FixedMul(8*FRACUNIT, inflictor->scale) // close enough? + && inflictor->z <= target->z + target->height + FixedMul(8*FRACUNIT, inflictor->scale) + && inflictor->z + inflictor->height >= target->z - FixedMul(8*FRACUNIT, inflictor->scale)) + mo = P_SpawnMobj(inflictor->x + inflictor->momx, inflictor->y + inflictor->momy, inflictor->z + (inflictor->height / 2) + inflictor->momz, MT_EXTRALARGEBUBBLE); + else + mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE); + mo->destscale = target->scale; + P_SetScale(mo, mo->destscale); + break; + + case MT_YELLOWSHELL: + P_SpawnMobjFromMobj(target, 0, 0, 0, MT_YELLOWSPRING); + break; + + case MT_EGGMOBILE3: + { + thinker_t *th; + UINT32 i = 0; // to check how many clones we've removed + + // scan the thinkers to make sure all the old pinch dummies are gone on death + // this can happen if the boss was hurt earlier than expected + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo = (mobj_t *)th; + if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target) + { + P_RemoveMobj(mo); + i++; + } + if (i == 2) // we've already removed 2 of these, let's stop now + break; + } + } + break; + + case MT_BIGMINE: + if (inflictor) + { + fixed_t dx = target->x - inflictor->x, dy = target->y - inflictor->y, dz = target->z - inflictor->z; + fixed_t dm = FixedHypot(dz, FixedHypot(dy, dx)); + target->momx = FixedDiv(FixedDiv(dx, dm), dm)*512; + target->momy = FixedDiv(FixedDiv(dy, dm), dm)*512; + target->momz = FixedDiv(FixedDiv(dz, dm), dm)*512; + } + if (source) + P_SetTarget(&target->tracer, source); + break; + + case MT_BLASTEXECUTOR: + if (target->spawnpoint) + P_LinedefExecute(target->spawnpoint->angle, (source ? source : inflictor), target->subsector->sector); + break; + case MT_EGGTRAP: // Time for birdies! Yaaaaaaaay! target->fuse = TICRATE*2; @@ -2467,57 +2460,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget break; } - // Enemy drops that ALWAYS occur regardless of mode - if (target->type == MT_AQUABUZZ) // Additionally spawns breathable bubble for players to get - { - if (inflictor && inflictor->player // did a player kill you? Spawn relative to the player so he's bound to get it - && P_AproxDistance(inflictor->x - target->x, inflictor->y - target->y) <= inflictor->radius + target->radius + FixedMul(8*FRACUNIT, inflictor->scale) // close enough? - && inflictor->z <= target->z + target->height + FixedMul(8*FRACUNIT, inflictor->scale) - && inflictor->z + inflictor->height >= target->z - FixedMul(8*FRACUNIT, inflictor->scale)) - mo = P_SpawnMobj(inflictor->x + inflictor->momx, inflictor->y + inflictor->momy, inflictor->z + (inflictor->height / 2) + inflictor->momz, MT_EXTRALARGEBUBBLE); - else - mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE); - mo->destscale = target->scale; - P_SetScale(mo, mo->destscale); - } - else if (target->type == MT_YELLOWSHELL) // Spawns a spring that falls to the ground - { - mobjtype_t spawnspring = MT_YELLOWSPRING; - fixed_t spawnheight = target->z; - if (!(target->eflags & MFE_VERTICALFLIP)) - spawnheight += target->height; - - mo = P_SpawnMobj(target->x, target->y, spawnheight, spawnspring); - mo->destscale = target->scale; - P_SetScale(mo, mo->destscale); - - if (target->flags2 & MF2_OBJECTFLIP) - mo->flags2 |= MF2_OBJECTFLIP; - } - - if (target->type == MT_EGGMOBILE3) - { - thinker_t *th; - UINT32 i = 0; // to check how many clones we've removed - - // scan the thinkers to make sure all the old pinch dummies are gone on death - // this can happen if the boss was hurt earlier than expected - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo = (mobj_t *)th; - if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target) - { - P_RemoveMobj(mo); - i++; - } - if (i == 2) // we've already removed 2 of these, let's stop now - break; - } - } - + // Final state setting - do something instead of P_SetMobjState; if (target->type == MT_SPIKE && target->info->deathstate != S_NULL) { const angle_t ang = ((inflictor) ? inflictor->angle : 0) + ANGLE_90; diff --git a/src/p_map.c b/src/p_map.c index 6d1760596..3715e765b 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -622,6 +622,31 @@ static boolean PIT_CheckThing(mobj_t *thing) } #endif + // Billiards mines! + if (thing->type == MT_BIGMINE && tmthing->type == MT_BIGMINE) + { + if (!tmthing->momx && !tmthing->momy) + return true; + if ((statenum_t)(thing->state-states) != thing->info->spawnstate) + return true; + if (thing->z > tmthing->z + tmthing->height) + return true; // overhead + if (thing->z + thing->height < tmthing->z) + return true; // underneath + + thing->momx = tmthing->momx/3; + thing->momy = tmthing->momy/3; + thing->momz = tmthing->momz/3; + tmthing->momx /= -8; + tmthing->momy /= -8; + tmthing->momz /= -8; + if (thing->info->activesound) + S_StartSound(thing, thing->info->activesound); + P_SetMobjState(thing, thing->info->meleestate); + P_SetTarget(&thing->tracer, tmthing->tracer); + return true; + } + // When solid spikes move, assume they just popped up and teleport things on top of them to hurt. if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 185a48340..45e1434d2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7379,9 +7379,7 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_AQUABUZZ: - P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn - /* FALLTHRU */ - case MT_BIGAIRMINE: + mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn { if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16) @@ -7406,34 +7404,11 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_BIGMINE: - { - if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 - && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16) - { - P_MobjCheckWater(mobj); - - // Home in on the target. - P_HomingAttack(mobj, mobj->tracer); - - // Don't let it go out of water - if (mobj->z + mobj->height > mobj->watertop) - mobj->z = mobj->watertop - mobj->height; - - if (mobj->z < mobj->floorz) - mobj->z = mobj->floorz; - - if (leveltime % mobj->info->painchance == 0) - S_StartSound(mobj, mobj->info->activesound); - } - else - { - // Try to find a player - P_LookForPlayers(mobj, true, true, mobj->radius * 16); - mobj->momx >>= 1; - mobj->momy >>= 1; - mobj->momz >>= 1; - } - } + mobj->extravalue1 += 3; + mobj->extravalue1 %= 360; + P_UnsetThingPosition(mobj); + mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); + P_SetThingPosition(mobj); break; case MT_EGGCAPSULE: if (!mobj->reactiontime) @@ -8496,6 +8471,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } break; } + case MT_BIGMINE: + mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; + break; case MT_EGGMOBILE2: // Special condition for the 2nd boss. mobj->watertop = mobj->info->speed; diff --git a/src/sounds.c b/src/sounds.c index 293ce381d..3a7219c6d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -310,7 +310,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k54", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Firing"}, // MetalSonic shot fire {"s3k55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"}, {"s3k56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy landing"}, - {"s3k57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Splash"}, + {"s3k57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, {"s3k58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"}, {"s3k59", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"}, {"s3k5a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, From 5cc1befcad77fbd558eea99851a0b00422a2feef Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 28 Apr 2018 15:13:44 +0100 Subject: [PATCH 106/212] * Haunted Heights! Smashing spikeball, Cacolantern, Spinbobert and Hangster, along with the Spider and Bat flickies and general decoration/ambience stuff. * MF_PAIN and MF_MISSILE now support setting damagetype via their Mass parameter. The two existing conflicts - the fuse setting for the grenade weapon ring and the Cybrakdemon napalm bomb - had these moved to other free parameters. * A_ConnectToGround is EXTREMELY useful for palmtrees and stuff. * Some other, relatively hacky A_ functions. * (Unrelated) Remove the need for a "Mario block mode" for the token by making it natively compatible. * Spikes and their time-offsetting via that Lua script sphere made. Also allow for wallspikes to do it via their angle/360. --- src/dehacked.c | 210 ++++++++- src/doomdata.h | 3 + src/hardware/hw_light.c | 18 + src/info.c | 982 +++++++++++++++++++++++++++++++++++----- src/info.h | 193 +++++++- src/p_enemy.c | 149 +++++- src/p_floor.c | 2 +- src/p_inter.c | 7 + src/p_local.h | 1 + src/p_map.c | 21 +- src/p_mobj.c | 122 ++++- src/p_user.c | 2 +- src/sounds.c | 18 +- src/sounds.h | 8 + 14 files changed, 1589 insertions(+), 147 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index e5bafabad..e3aee6654 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -853,25 +853,27 @@ static const struct { const char *name; const mobjtype_t type; } FLICKYTYPES[] = { - {"BLUEBIRD", MT_FLICKY_01}, - {"RABBIT", MT_FLICKY_02}, - {"CHICKEN", MT_FLICKY_03}, - {"SEAL", MT_FLICKY_04}, - {"PIG", MT_FLICKY_05}, - {"CHIPMUNK", MT_FLICKY_06}, - {"PENGUIN", MT_FLICKY_07}, - {"FISH", MT_FLICKY_08}, - {"RAM", MT_FLICKY_09}, - {"PUFFIN", MT_FLICKY_10}, - {"COW", MT_FLICKY_11}, - {"RAT", MT_FLICKY_12}, - {"BEAR", MT_FLICKY_13}, - {"DOVE", MT_FLICKY_14}, - {"CAT", MT_FLICKY_15}, - {"CANARY", MT_FLICKY_16}, + {"BLUEBIRD", MT_FLICKY_01}, // Flicky (Flicky) + {"RABBIT", MT_FLICKY_02}, // Pocky (1) + {"CHICKEN", MT_FLICKY_03}, // Cucky (1) + {"SEAL", MT_FLICKY_04}, // Rocky (1) + {"PIG", MT_FLICKY_05}, // Picky (1) + {"CHIPMUNK", MT_FLICKY_06}, // Ricky (1) + {"PENGUIN", MT_FLICKY_07}, // Pecky (1) + {"FISH", MT_FLICKY_08}, // Nicky (CD) + {"RAM", MT_FLICKY_09}, // Flocky (CD) + {"PUFFIN", MT_FLICKY_10}, // Wicky (CD) + {"COW", MT_FLICKY_11}, // Macky (SRB2) + {"RAT", MT_FLICKY_12}, // Micky (2) + {"BEAR", MT_FLICKY_13}, // Becky (2) + {"DOVE", MT_FLICKY_14}, // Docky (CD) + {"CAT", MT_FLICKY_15}, // Nyannyan (Flicky) + {"CANARY", MT_FLICKY_16}, // Lucky (CD) {"a", 0}, // End of normal flickies - a lower case character so will never fastcmp valid with uppercase tmp - //{"FLICKER", MT_FLICKER}, - {"SEED", MT_SEED}, + //{"FLICKER", MT_FLICKER}, // Flacky (SRB2) + {"SPIDER", MT_SECRETFLICKY_01}, // Sticky (SRB2) + {"BAT", MT_SECRETFLICKY_02}, // Backy (SRB2) + {"SEED", MT_SEED}, // Seed (CD) {NULL, 0} }; @@ -1813,6 +1815,9 @@ static actionpointer_t actionpointers[] = {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, {{A_MineExplode}, "A_MINEEXPLODE"}, {{A_MineRange}, "A_MINERANGE"}, + {{A_ConnectToGround}, "A_CONNECTTOGROUND"}, + {{A_SpawnParticleRelative},"A_SPAWNPARTICLERELATIVE"}, + {{A_MultiShotDist}, "A_MULTISHOTDIST"}, {{NULL}, "NONE"}, @@ -4968,6 +4973,51 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_XMASBERRYBUSH", "S_XMASBUSH", + // Halloween Scenery + // Pumpkins + "S_JACKO1", + "S_JACKO1OVERLAY_1", + "S_JACKO1OVERLAY_2", + "S_JACKO1OVERLAY_3", + "S_JACKO1OVERLAY_4", + "S_JACKO2", + "S_JACKO2OVERLAY_1", + "S_JACKO2OVERLAY_2", + "S_JACKO2OVERLAY_3", + "S_JACKO2OVERLAY_4", + "S_JACKO3", + "S_JACKO3OVERLAY_1", + "S_JACKO3OVERLAY_2", + "S_JACKO3OVERLAY_3", + "S_JACKO3OVERLAY_4", + // Dr Seuss Trees + "S_HHZTREE_TOP", + "S_HHZTREE_TRUNK", + "S_HHZTREE_LEAF", + // Mushroom + "S_HHZSHROOM_1", + "S_HHZSHROOM_2", + "S_HHZSHROOM_3", + "S_HHZSHROOM_4", + "S_HHZSHROOM_5", + "S_HHZSHROOM_6", + "S_HHZSHROOM_7", + "S_HHZSHROOM_8", + "S_HHZSHROOM_9", + "S_HHZSHROOM_10", + "S_HHZSHROOM_11", + "S_HHZSHROOM_12", + "S_HHZSHROOM_13", + "S_HHZSHROOM_14", + "S_HHZSHROOM_15", + "S_HHZSHROOM_16", + // Misc + "S_HHZGRASS", + "S_HHZTENT1", + "S_HHZTENT2", + "S_HHZSTALAGMITE_TALL", + "S_HHZSTALAGMITE_SHORT", + // Botanic Serenity's loads of scenery states "S_BSZTALLFLOWER_RED", "S_BSZTALLFLOWER_PURPLE", @@ -5407,6 +5457,19 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLICKY_16_FLAP2", "S_FLICKY_16_FLAP3", + // Spider + "S_SECRETFLICKY_01_OUT", + "S_SECRETFLICKY_01_AIM", + "S_SECRETFLICKY_01_HOP", + "S_SECRETFLICKY_01_UP", + "S_SECRETFLICKY_01_DOWN", + + // Bat + "S_SECRETFLICKY_02_OUT", + "S_SECRETFLICKY_02_FLAP1", + "S_SECRETFLICKY_02_FLAP2", + "S_SECRETFLICKY_02_FLAP3", + "S_YELLOWSPRING", "S_YELLOWSPRING2", "S_YELLOWSPRING3", @@ -5903,6 +5966,85 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_NIGHTOPIANHELPER8", "S_NIGHTOPIANHELPER9", + // Secret badniks and hazards, shhhh + "S_SMASHSPIKE_FLOAT", + "S_SMASHSPIKE_EASE1", + "S_SMASHSPIKE_EASE2", + "S_SMASHSPIKE_FALL", + "S_SMASHSPIKE_STOMP1", + "S_SMASHSPIKE_STOMP2", + "S_SMASHSPIKE_RISE1", + "S_SMASHSPIKE_RISE2", + + "S_HHZDUST1", + "S_HHZDUST2", + "S_HHZDUST3", + "S_HHZDUST4", + + "S_CACO_LOOK", + "S_CACO_WAKE1", + "S_CACO_WAKE2", + "S_CACO_WAKE3", + "S_CACO_WAKE4", + "S_CACO_ROAR", + "S_CACO_CHASE", + "S_CACO_CHASE_REPEAT", + "S_CACO_RANDOM", + "S_CACO_PREPARE_SOUND", + "S_CACO_PREPARE1", + "S_CACO_PREPARE2", + "S_CACO_PREPARE3", + "S_CACO_SHOOT_SOUND", + "S_CACO_SHOOT1", + "S_CACO_SHOOT2", + "S_CACO_CLOSE", + "S_CACO_DIE_FLAGS", + "S_CACO_DIE_GIB1", + "S_CACO_DIE_GIB2", + "S_CACO_DIE_SCREAM", + "S_CACO_DIE_SHATTER", + "S_CACO_DIE_FALL", + "S_CACOSHARD_RANDOMIZE", + "S_CACOSHARD1_1", + "S_CACOSHARD1_2", + "S_CACOSHARD2_1", + "S_CACOSHARD2_2", + "S_CACOFIRE1", + "S_CACOFIRE2", + "S_CACOFIRE3", + "S_CACOFIRE_EXPLODE1", + "S_CACOFIRE_EXPLODE2", + "S_CACOFIRE_EXPLODE3", + "S_CACOFIRE_EXPLODE4", + + "S_SPINBOBERT_MOVE_FLIPUP", + "S_SPINBOBERT_MOVE_UP", + "S_SPINBOBERT_MOVE_FLIPDOWN", + "S_SPINBOBERT_MOVE_DOWN", + "S_SPINBOBERT_FIRE_MOVE", + "S_SPINBOBERT_FIRE_GHOST", + "S_SPINBOBERT_FIRE_TRAIL1", + "S_SPINBOBERT_FIRE_TRAIL2", + "S_SPINBOBERT_FIRE_TRAIL3", + + "S_HANGSTER_LOOK", + "S_HANGSTER_SWOOP1", + "S_HANGSTER_SWOOP2", + "S_HANGSTER_ARC1", + "S_HANGSTER_ARC2", + "S_HANGSTER_ARC3", + "S_HANGSTER_FLY1", + "S_HANGSTER_FLY2", + "S_HANGSTER_FLY3", + "S_HANGSTER_FLY4", + "S_HANGSTER_FLYREPEAT", + "S_HANGSTER_ARCUP1", + "S_HANGSTER_ARCUP2", + "S_HANGSTER_ARCUP3", + "S_HANGSTER_RETURN1", + "S_HANGSTER_RETURN2", + "S_HANGSTER_RETURN3", + "S_CRUMBLE1", "S_CRUMBLE2", @@ -6309,6 +6451,22 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_XMASBERRYBUSH", "MT_XMASBUSH", + // Halloween Scenery + // Pumpkins + "MT_JACKO1", + "MT_JACKO2", + "MT_JACKO3", + // Dr Seuss Trees + "MT_HHZTREE_TOP", + "MT_HHZTREE_PART", + // Misc + "MT_HHZSHROOM", + "MT_HHZGRASS", + "MT_HHZTENTACLE1", + "MT_HHZTENTACLE2", + "MT_HHZSTALAGMITE_TALL", + "MT_HHZSTALAGMITE_SHORT", + // Botanic Serenity "MT_BSZTALLFLOWER_RED", "MT_BSZTALLFLOWER_PURPLE", @@ -6394,6 +6552,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_FLICKY_14", // Dove "MT_FLICKY_15", // Cat "MT_FLICKY_16", // Canary + "MT_SECRETFLICKY_01", // Spider + "MT_SECRETFLICKY_02", // Bat + "MT_SEED", // Environmental Effects "MT_RAIN", // Rain @@ -6406,7 +6567,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_WATERZAP", "MT_SPINDUST", // Spindash dust "MT_TFOG", - "MT_SEED", "MT_PARTICLE", "MT_PARTICLEGEN", // For fans, etc. @@ -6429,6 +6589,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_AWATERH", // Ambient Water Sound 8 "MT_RANDOMAMBIENT", "MT_RANDOMAMBIENT2", + "MT_MACHINEAMBIENCE", "MT_CORK", @@ -6496,6 +6657,17 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_EGGCAPSULE", "MT_NIGHTOPIANHELPER", // the actual helper object that orbits you + // Secret badniks and hazards, shhhh + "MT_SMASHINGSPIKEBALL", + "MT_HHZDUST", + "MT_CACOLANTERN", + "MT_CACOSHARD", + "MT_CACOFIRE", + "MT_SPINBOBERT", + "MT_SPINBOBERT_FIRE1", + "MT_SPINBOBERT_FIRE2", + "MT_HANGSTER", + // Utility Objects "MT_TELEPORTMAN", "MT_ALTVIEWMAN", diff --git a/src/doomdata.h b/src/doomdata.h index c0586fd65..5ee39c5a8 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -46,6 +46,9 @@ enum ML_BLOCKMAP, // LUT, motion clipping, walls/grid element }; +// Extra flag for objects. +#define MTF_EXTRA 1 + // Reverse gravity flag for objects. #define MTF_OBJECTFLIP 2 diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 0496e6423..9397eaec2 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -349,6 +349,12 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_XMS4 &lspr[NOLIGHT], // SPR_XMS5 + // Halloween Scenery + &lspr[RINGLIGHT_L], // SPR_PUMK + &lspr[NOLIGHT], // SPR_HHPL + &lspr[NOLIGHT], // SPR_SHRM + &lspr[NOLIGHT], // SPR_HHZM + // Botanic Serenity Scenery &lspr[NOLIGHT], // SPR_BSZ1 &lspr[NOLIGHT], // SPR_BSZ2 @@ -399,6 +405,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_FL14 &lspr[NOLIGHT], // SPR_FL15 &lspr[NOLIGHT], // SPR_FL16 + &lspr[NOLIGHT], // SPR_FS01 + &lspr[NOLIGHT], // SPR_FS02 // Springs &lspr[NOLIGHT], // SPR_SPRY @@ -480,6 +488,16 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_NPRU &lspr[NOLIGHT], // SPR_CAPS + // Secret badniks and hazards, shhhh + &lspr[NOLIGHT], // SPR_FMCE", + &lspr[NOLIGHT], // SPR_HMCE", + &lspr[NOLIGHT], // SPR_CACO", + &lspr[BLUEBALL_L], // SPR_BAL2", + &lspr[NOLIGHT], // SPR_SBOB", + &lspr[BLUEBALL_L], // SPR_SBFL", + &lspr[BLUEBALL_L], // SPR_SBSK", + &lspr[NOLIGHT], // SPR_BATT", + // Debris &lspr[RINGSPARK_L], // SPR_SPRK &lspr[NOLIGHT], // SPR_BOM1 diff --git a/src/info.c b/src/info.c index 1805c555b..cd1705a51 100644 --- a/src/info.c +++ b/src/info.c @@ -16,6 +16,7 @@ #include "doomstat.h" #include "sounds.h" #include "p_mobj.h" +#include "p_local.h" // DMG_ constants #include "m_misc.h" #include "z_zone.h" #include "d_player.h" @@ -242,6 +243,12 @@ char sprnames[NUMSPRITES + 1][5] = "XMS4", // Lamppost "XMS5", // Hanging Star + // Halloween Scenery + "PUMK", // Pumpkins + "HHPL", // Dr Seuss Trees + "SHRM", // Mushroom + "HHZM", // Misc + // Botanic Serenity Scenery "BSZ1", // Tall flowers "BSZ2", // Medium flowers @@ -292,6 +299,8 @@ char sprnames[NUMSPRITES + 1][5] = "FL14", // Dove "FL15", // Cat "FL16", // Canary + "FS01", // Spider + "FS02", // Bat // Springs "SPRY", // yellow spring @@ -373,6 +382,16 @@ char sprnames[NUMSPRITES + 1][5] = "NPRU", // Nights Powerups "CAPS", // Capsule thingy for NiGHTS + // Secret badniks and hazards, shhhh + "FMCE", + "HMCE", + "CACO", + "BAL2", + "SBOB", + "SBFL", + "SBSK", + "HBAT", + // Debris "SPRK", // spark "BOM1", // Robot Explosion @@ -2183,8 +2202,53 @@ state_t states[NUMSTATES] = {SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST2 {SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HANGSTAR // Xmas GFZ bushes - {SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BERRYBUSH - {SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BUSH + {SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBERRYBUSH + {SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBUSH + + // Halloween Scenery + // Pumpkins + {SPR_PUMK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO1 + {SPR_PUMK, 3|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_2}, // S_JACKO1OVERLAY_1 + {SPR_PUMK, 4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_3}, // S_JACKO1OVERLAY_2 + {SPR_PUMK, 5|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_4}, // S_JACKO1OVERLAY_3 + {SPR_PUMK, 4|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO1OVERLAY_1}, // S_JACKO1OVERLAY_4 + {SPR_PUMK, 1, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO2 + {SPR_PUMK, 6|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_2}, // S_JACKO2OVERLAY_1 + {SPR_PUMK, 7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_3}, // S_JACKO2OVERLAY_2 + {SPR_PUMK, 8|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_4}, // S_JACKO2OVERLAY_3 + {SPR_PUMK, 7|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO2OVERLAY_1}, // S_JACKO2OVERLAY_4 + {SPR_PUMK, 2, -1, {NULL}, 0, 0, S_NULL}, // S_JACKO3 + {SPR_PUMK, 9|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_2}, // S_JACKO3OVERLAY_1 + {SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_3}, // S_JACKO3OVERLAY_2 + {SPR_PUMK, 11|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_4}, // S_JACKO3OVERLAY_3 + {SPR_PUMK, 10|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_JACKO3OVERLAY_1}, // S_JACKO3OVERLAY_4 + // Dr Seuss Trees + {SPR_HHPL, 2, -1, {A_ConnectToGround}, MT_HHZTREE_PART, 0, S_NULL}, // S_HHZTREE_TOP, + {SPR_HHPL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTREE_TRUNK, + {SPR_HHPL, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTREE_LEAF, + // Mushroom + {SPR_SHRM, 4, 3, {NULL}, 0, 0, S_HHZSHROOM_2}, // S_HHZSHROOM_1, + {SPR_SHRM, 3, 3, {NULL}, 0, 0, S_HHZSHROOM_3}, // S_HHZSHROOM_2, + {SPR_SHRM, 2, 2, {NULL}, 0, 0, S_HHZSHROOM_4}, // S_HHZSHROOM_3, + {SPR_SHRM, 1, 1, {NULL}, 0, 0, S_HHZSHROOM_5}, // S_HHZSHROOM_4, + {SPR_SHRM, 0, 1, {NULL}, 0, 0, S_HHZSHROOM_6}, // S_HHZSHROOM_5, + {SPR_SHRM, 1, 4, {NULL}, 0, 0, S_HHZSHROOM_7}, // S_HHZSHROOM_6, + {SPR_SHRM, 2, 2, {NULL}, 0, 0, S_HHZSHROOM_8}, // S_HHZSHROOM_7, + {SPR_SHRM, 3, 3, {NULL}, 0, 0, S_HHZSHROOM_9}, // S_HHZSHROOM_8, + {SPR_SHRM, 4, 3, {NULL}, 0, 0, S_HHZSHROOM_10}, // S_HHZSHROOM_9, + {SPR_SHRM, 3, 3, {NULL}, 0, 0, S_HHZSHROOM_11}, // S_HHZSHROOM_10, + {SPR_SHRM, 5, 2, {NULL}, 0, 0, S_HHZSHROOM_12}, // S_HHZSHROOM_11, + {SPR_SHRM, 6, 1, {NULL}, 0, 0, S_HHZSHROOM_13}, // S_HHZSHROOM_12, + {SPR_SHRM, 7, 1, {NULL}, 0, 0, S_HHZSHROOM_14}, // S_HHZSHROOM_13, + {SPR_SHRM, 6, 4, {NULL}, 0, 0, S_HHZSHROOM_15}, // S_HHZSHROOM_14, + {SPR_SHRM, 5, 2, {NULL}, 0, 0, S_HHZSHROOM_16}, // S_HHZSHROOM_15, + {SPR_SHRM, 3, 3, {NULL}, 0, 0, S_HHZSHROOM_1}, // S_HHZSHROOM_16, + // Misc + {SPR_HHZM, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HHZGRASS, + {SPR_HHZM, 1, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTENT1, + {SPR_HHZM, 2, -1, {NULL}, 0, 0, S_NULL}, // S_HHZTENT2, + {SPR_HHZM, 4, -1, {NULL}, 0, 0, S_NULL}, // S_HHZSTALAGMITE_TALL, + {SPR_HHZM, 5, -1, {NULL}, 0, 0, S_NULL}, // S_HHZSTALAGMITE_SHORT, // Loads of Botanic Serenity bullshit {SPR_BSZ1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_RED @@ -2232,9 +2296,9 @@ state_t states[NUMSTATES] = {SPR_BSZ8, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHRUB {SPR_BSZ8, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLOVER {SPR_BSZ8, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BIG_PALMTREE_TRUNK - {SPR_BSZ8, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BIG_PALMTREE_TOP + {SPR_BSZ8, 3, -1, {A_ConnectToGround}, MT_BIG_PALMTREE_TRUNK, 0, S_NULL}, // S_BIG_PALMTREE_TOP {SPR_BSZ8, 4, -1, {NULL}, 0, 0, S_NULL}, // S_PALMTREE_TRUNK - {SPR_BSZ8, 5, -1, {NULL}, 0, 0, S_NULL}, // S_PALMTREE_TOP + {SPR_BSZ8, 5, -1, {A_ConnectToGround}, MT_PALMTREE_TRUNK, 0, S_NULL}, // S_PALMTREE_TOP // Disco ball {SPR_DBAL, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_DBALL2}, // S_DBALL1 @@ -2604,10 +2668,10 @@ state_t states[NUMSTATES] = {SPR_FL12, 3, 3, {A_FlickyHop}, 1, 12*FRACUNIT, S_FLICKY_12_AIM}, // S_FLICKY_12_RUN3 // Bear - {SPR_FL13, 0, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, 0, S_FLICKY_13_OUT}, // S_FLICKY_13_OUT - {SPR_FL13, 1, 1, {A_FlickyAim}, ANG30, 32*FRACUNIT, S_FLICKY_13_HOP}, // S_FLICKY_13_AIM - {SPR_FL13, 1, 1, {A_FlickyHop}, 5*FRACUNIT, 3*FRACUNIT, S_FLICKY_13_UP}, // S_FLICKY_13_HOP - {SPR_FL13, 2, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, S_FLICKY_13_DOWN, S_FLICKY_13_UP}, // S_FLICKY_13_UP + {SPR_FL13, 0, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, 0, S_FLICKY_13_OUT}, // S_FLICKY_13_OUT + {SPR_FL13, 1, 1, {A_FlickyAim}, ANG30, 32*FRACUNIT, S_FLICKY_13_HOP}, // S_FLICKY_13_AIM + {SPR_FL13, 1, 1, {A_FlickyHop}, 5*FRACUNIT, 3*FRACUNIT, S_FLICKY_13_UP}, // S_FLICKY_13_HOP + {SPR_FL13, 2, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, S_FLICKY_13_DOWN, S_FLICKY_13_UP}, // S_FLICKY_13_UP {SPR_FL13, 3, 2, {A_FlickyCheck}, S_FLICKY_13_AIM, 0, S_FLICKY_13_DOWN}, // S_FLICKY_13_DOWN // Dove @@ -2629,6 +2693,19 @@ state_t states[NUMSTATES] = {SPR_FL16, 2, 3, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP2 {SPR_FL16, 3, 3, {A_FlickyHeightCheck}, S_FLICKY_16_FLAP1, 0, S_FLICKY_16_FLAP3}, // S_FLICKY_16_FLAP3 + // Spider + {SPR_FS01, 0, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, 0, S_SECRETFLICKY_01_OUT}, // S_SECRETFLICKY_01_OUT + {SPR_FS01, 1, 1, {A_FlickyAim}, ANG30, 32*FRACUNIT, S_SECRETFLICKY_01_HOP}, // S_SECRETFLICKY_01_AIM + {SPR_FS01, 1, 1, {A_FlickyFlounder}, 2*FRACUNIT, 6*FRACUNIT, S_SECRETFLICKY_01_UP}, // S_SECRETFLICKY_01_HOP + {SPR_FS01, 2, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, S_SECRETFLICKY_01_DOWN, S_SECRETFLICKY_01_UP}, // S_SECRETFLICKY_01_UP + {SPR_FS01, 3, 2, {A_FlickyCheck}, S_SECRETFLICKY_01_AIM, 0, S_SECRETFLICKY_01_DOWN}, // S_SECRETFLICKY_01_DOWN + + // Bat + {SPR_FS02, 0, 2, {A_FlickyHeightCheck}, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_FLAP1, S_SECRETFLICKY_02_OUT}, // S_SECRETFLICKY_02_OUT + {SPR_FS02, 1, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP2}, // S_SECRETFLICKY_02_FLAP1 + {SPR_FS02, 2, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP3}, // S_SECRETFLICKY_02_FLAP2 + {SPR_FS02, 3, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP1}, // S_SECRETFLICKY_02_FLAP3 + // Yellow Spring {SPR_SPRY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWSPRING {SPR_SPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWSPRING3}, // S_YELLOWSPRING2 @@ -3179,7 +3256,87 @@ state_t states[NUMSTATES] = {SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER9}, // S_NIGHTOPIANHELPER8 {SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1}, // S_NIGHTOPIANHELPER9 - {SPR_NULL, 0, 35, {NULL}, 0, 0, S_CRUMBLE2}, // S_CRUMBLE1 + // Secret badniks and hazards, shhhh + {SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1}, // S_SMASHSPIKE_FLOAT + {SPR_FMCE, 0, 4, {A_ZThrust}, 4, (1<<16)|1, S_SMASHSPIKE_EASE2}, // S_SMASHSPIKE_EASE1 + {SPR_FMCE, 0, 4, {A_ZThrust}, 0, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_EASE1 + {SPR_FMCE, 0, 2, {A_ZThrust}, -6, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_FALL + {SPR_FMCE, 1, 2, {A_MultiShotDist}, (MT_HHZDUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1 + {SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1}, // S_SMASHSPIKE_STOMP2 + {SPR_FMCE, 1, 2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE1 + {SPR_FMCE, 0, 2, {A_ZThrust}, 6, (1<<16)|1, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE2 + + {SPR_DUST, FF_TRANS40, 4, {NULL}, 0, 0, S_HHZDUST2}, // S_HHZDUST1 + {SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_HHZDUST3}, // S_HHZDUST2 + {SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_HHZDUST4}, // S_HHZDUST3 + {SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL}, // S_HHZDUST4 + + {SPR_CACO, 0, 5, {A_Look}, (1100<<16)|1, 0, S_CACO_LOOK}, // S_CACO_LOOK + {SPR_CACO, 1, 0, {A_MultiShotDist}, (MT_HHZDUST<<16)|7, -48, S_CACO_WAKE2}, // S_CACO_WAKE1 + {SPR_CACO, 1, 10, {A_ZThrust}, 4, (1<<16)|1, S_CACO_WAKE3}, // S_CACO_WAKE2 + {SPR_CACO, 2, 8, {A_ZThrust}, 2, (1<<16)|1, S_CACO_WAKE4}, // S_CACO_WAKE3 + {SPR_CACO, 2, 4, {A_ZThrust}, 0, (1<<16)|1, S_CACO_ROAR}, // S_CACO_WAKE4 + {SPR_CACO, 2, 10, {A_PlayActiveSound}, 0, 0, S_CACO_CHASE}, // S_CACO_ROAR + {SPR_CACO, 2, 5, {A_JetChase}, 0, 0, S_CACO_CHASE_REPEAT}, // S_CACO_CHASE + {SPR_CACO, 2, 0, {A_Repeat}, 5, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_CHASE_REPEAT + {SPR_CACO, 2, 0, {A_RandomState}, S_CACO_PREPARE_SOUND, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_RANDOM + {SPR_CACO, 2, 8, {A_PlaySound}, sfx_s3k95, 0, S_CACO_PREPARE1}, // S_CACO_PREPARE_SOUND + {SPR_CACO, 3, 8, {NULL}, 0, 0, S_CACO_PREPARE2}, // S_CACO_PREPARE1 + {SPR_CACO, 4|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_PREPARE3}, // S_CACO_PREPARE2 + {SPR_CACO, 5|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_SHOOT_SOUND}, // S_CACO_PREPARE3 + {SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_PlaySound}, sfx_s3k4e, 1, S_CACO_SHOOT1}, // S_CACO_SHOOT_SOUND + {SPR_CACO, 4|FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_CACOFIRE_EXPLODE1, S_CACO_SHOOT2}, // S_CACO_SHOOT1 + {SPR_CACO, 4|FF_FULLBRIGHT, 6, {A_FireShot}, MT_CACOFIRE, -24, S_CACO_CLOSE}, // S_CACO_SHOOT2 + {SPR_CACO, 3, 15, {NULL}, 0, 0, S_CACO_CHASE}, // S_CACO_CLOSE + {SPR_CACO, 10, 0, {A_SetObjectFlags}, MF_NOBLOCKMAP, 0, S_CACO_DIE_GIB1}, // S_CACO_DIE_FLAGS + {SPR_CACO, 10, 0, {A_NapalmScatter}, (7<<16)|MT_CACOSHARD, (30<<16)|20, S_CACO_DIE_GIB2}, // S_CACO_DIE_GIB1 + {SPR_CACO, 10, 0, {A_NapalmScatter}, (10<<16)|MT_CACOSHARD, (24<<16)|32, S_CACO_DIE_SCREAM}, // S_CACO_DIE_GIB2 + {SPR_CACO, 10, 0, {A_Scream}, 0, 0, S_CACO_DIE_SHATTER}, // S_CACO_DIE_SCREAM + {SPR_CACO, 10, 0, {A_PlaySound}, sfx_pumpkn, 1, S_CACO_DIE_FALL}, // S_CACO_DIE_SHATTER + {SPR_CACO, 10, 250, {A_FlickySpawn}, (1<<16), 0, S_NULL}, // S_CACO_DIE_FALL + + {SPR_CACO, 6, 0, {A_RandomState}, S_CACOSHARD1_1, S_CACOSHARD2_1, S_NULL}, // S_CACOSHARD_RANDOMIZE + {SPR_CACO, 6, 3, {NULL}, 0, 0, S_CACOSHARD1_2}, // S_CACOSHARD1_1 + {SPR_CACO, 7, 3, {NULL}, 0, 0, S_CACOSHARD1_1}, // S_CACOSHARD1_2 + {SPR_CACO, 8, 3, {NULL}, 0, 0, S_CACOSHARD2_2}, // S_CACOSHARD2_1 + {SPR_CACO, 9, 3, {NULL}, 0, 0, S_CACOSHARD2_1}, // S_CACOSHARD2_2 + {SPR_BAL2, FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE2}, // S_CACOFIRE1 + {SPR_BAL2, 1|FF_FULLBRIGHT, 2, {A_GhostMe}, 0, 0, S_CACOFIRE3}, // S_CACOFIRE2 + {SPR_BAL2, FF_FULLBRIGHT, 0, {A_PlayActiveSound}, 0, 0, S_CACOFIRE1}, // S_CACOFIRE3 + {SPR_BAL2, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE2}, // S_CACOFIRE_EXPLODE1 + {SPR_BAL2, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE3}, // S_CACOFIRE_EXPLODE2 + {SPR_BAL2, 4|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_CACOFIRE_EXPLODE4}, // S_CACOFIRE_EXPLODE3 + {SPR_BAL2, 5|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_CACOFIRE_EXPLODE4 + + {SPR_SBOB, 1, 10, {A_ZThrust}, -2, (1<<16)|1, S_SPINBOBERT_MOVE_UP}, // S_SPINBOBERT_MOVE_FLIPUP + {SPR_SBOB, 0, 45, {A_ZThrust}, 4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPDOWN}, // S_SPINBOBERT_MOVE_UP + {SPR_SBOB, 1, 10, {A_ZThrust}, 2, (1<<16)|1, S_SPINBOBERT_MOVE_DOWN}, // S_SPINBOBERT_MOVE_FLIPDOWN + {SPR_SBOB, 2, 45, {A_ZThrust}, -4, (1<<16)|1, S_SPINBOBERT_MOVE_FLIPUP}, // S_SPINBOBERT_MOVE_DOWN + {SPR_SBSK, FF_FULLBRIGHT, 1, {A_RotateSpikeBall}, 0, 0, S_SPINBOBERT_FIRE_GHOST}, // S_SPINBOBERT_FIRE_MOVE + {SPR_SBSK, FF_FULLBRIGHT, 0, {A_SpawnParticleRelative}, 0, S_SPINBOBERT_FIRE_TRAIL1, S_SPINBOBERT_FIRE_MOVE}, // S_SPINBOBERT_FIRE_GHOST + {SPR_SBFL, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL2}, // S_SPINBOBERT_FIRE_TRAIL1 + {SPR_SBFL, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINBOBERT_FIRE_TRAIL3}, // S_SPINBOBERT_FIRE_TRAIL2 + {SPR_SBFL, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_SPINBOBERT_FIRE_TRAIL3 + + {SPR_HBAT, 0, 5, {A_Look}, (900<<16)|1, 0, S_HANGSTER_LOOK}, // S_HANGSTER_LOOK + {SPR_HBAT, 1, 0, {A_MultiShotDist}, (MT_HHZDUST<<16)|10, -34, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP1 + {SPR_HBAT, 1, 2, {A_ZThrust}, -8, (1<<16)|1, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP2 + {SPR_HBAT, 1, 6, {A_ZThrust}, -5, (1<<16), S_HANGSTER_ARC2}, // S_HANGSTER_ARC1 + {SPR_HBAT, 1, 5, {A_ZThrust}, -2, (1<<16), S_HANGSTER_ARC3}, // S_HANGSTER_ARC2 + {SPR_HBAT, 1, 1, {A_ZThrust}, 0, (1<<16), S_HANGSTER_FLY1}, // S_HANGSTER_ARC3 + {SPR_HBAT, 1, 4, {A_Thrust}, 6, 1, S_HANGSTER_FLY2}, // S_HANGSTER_FLY1 + {SPR_HBAT, 2, 1, {A_PlaySound}, sfx_s3k52, 1, S_HANGSTER_FLY3}, // S_HANGSTER_FLY2 + {SPR_HBAT, 3, 4, {A_Thrust}, 6, 1, S_HANGSTER_FLY4}, // S_HANGSTER_FLY3 + {SPR_HBAT, 2, 1, {A_Thrust}, 6, 1, S_HANGSTER_FLYREPEAT}, // S_HANGSTER_FLY4 + {SPR_HBAT, 2, 0, {A_Repeat}, 12, S_HANGSTER_FLY1, S_HANGSTER_ARCUP1}, // S_HANGSTER_FLYREPEAT + {SPR_HBAT, 1, 5, {A_ZThrust}, 2, (1<<16), S_HANGSTER_ARCUP2}, // S_HANGSTER_ARCUP1 + {SPR_HBAT, 1, 6, {A_ZThrust}, 5, (1<<16), S_HANGSTER_ARCUP3}, // S_HANGSTER_ARCUP2 + {SPR_HBAT, 1, 1, {A_ZThrust}, 0, (1<<16), S_HANGSTER_RETURN1}, // S_HANGSTER_ARCUP3 + {SPR_HBAT, 1, 1, {A_ZThrust}, 8, (1<<16), S_HANGSTER_RETURN2}, // S_HANGSTER_RETURN1 + {SPR_HBAT, 3, 1, {NULL}, 0, 0, S_HANGSTER_RETURN1}, // S_HANGSTER_RETURN2 + {SPR_HBAT, 0, 15, {NULL}, 0, 0, S_HANGSTER_LOOK}, // S_HANGSTER_RETURN3 + + {SPR_NULL, 0, 35, {NULL}, 0, 0, S_CRUMBLE2}, // S_CRUMBLE1 {SPR_NULL, 0, 105, {A_Scream}, 0, 0, S_NULL}, // S_CRUMBLE2 // Spark @@ -3643,7 +3800,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_ENEMY|MF_SHOOTABLE|MF_NOGRAVITY|MF_MISSILE, // flags @@ -3886,7 +4043,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 1, // damage sfx_None, // activesound MF_PAIN|MF_NOGRAVITY, // flags @@ -4156,7 +4313,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 13*FRACUNIT, // radius 26*FRACUNIT, // height 0, // display offset - 0, // mass + DMG_SPIKE, // mass 8*FRACUNIT, // damage sfx_None, // activesound MF_PAIN|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING, // flags @@ -4453,7 +4610,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 14*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_FIRE, // flags @@ -4615,7 +4772,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 4*FRACUNIT, // height 0, // display offset - 4, // mass + DMG_WATER, // mass 0, // damage sfx_None, // activesound MF_PAIN, // flags @@ -4777,7 +4934,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 34*FRACUNIT, // radius 68*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 1, // damage sfx_mswing, // activesound MF_PAIN|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags @@ -4804,7 +4961,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 4, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_PAIN|MF_FIRE, // flags @@ -4885,7 +5042,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 11*FRACUNIT, // radius 8*FRACUNIT, // height 100, // display offset - 100, // mass + 0, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -4912,7 +5069,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -4966,7 +5123,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 48*FRACUNIT, // radius 160*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_ELECTRIC, // mass 1, // damage sfx_beelec, // activesound MF_PAIN|MF_FIRE|MF_NOGRAVITY|MF_PUSHABLE, // flags @@ -4993,7 +5150,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 11*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 32*FRACUNIT, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -5020,7 +5177,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -5047,7 +5204,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_PAIN|MF_FIRE|MF_RUNSPAWNFUNC, // flags @@ -5117,7 +5274,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance + 20*TICRATE, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate @@ -5128,7 +5285,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 20*TICRATE, // mass + 0, // mass 48*FRACUNIT, // damage sfx_s3k5d, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_BOUNCE|MF_GRENADEBOUNCE, // flags @@ -5155,7 +5312,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 32*FRACUNIT, // damage sfx_s3k99, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_BOUNCE, // flags @@ -5182,7 +5339,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE, // flags @@ -6176,7 +6333,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 1, // damage sfx_None, // activesound MF_PAIN|MF_NOGRAVITY, // flags @@ -6230,7 +6387,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 14*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_FIRE, // flags @@ -6248,7 +6405,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // painstate 0, // painchance sfx_s3k64, // painsound - S_NULL, // meleestate + S_SPIKE4, // meleestate S_NULL, // missilestate S_SPIKED1, // deathstate S_SPIKED2, // xdeathstate @@ -7931,7 +8088,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 11*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 20, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -7958,7 +8115,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 11*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 20, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -7985,7 +8142,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 11*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 20, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -8012,7 +8169,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 11*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 20, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -8039,7 +8196,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 60*FRACUNIT, // radius 120*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 20, // damage sfx_None, // activesound MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags @@ -8066,7 +8223,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 10*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 64*FRACUNIT, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE, // flags @@ -8093,7 +8250,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -8120,7 +8277,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 12*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -8147,7 +8304,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE, // flags @@ -8201,7 +8358,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -8228,7 +8385,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -9200,7 +9357,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_PAIN|MF_FIRE, // flags @@ -9524,9 +9681,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 17*FRACUNIT, // radius 34*FRACUNIT, // height 1, // display offset - 100, // mass + 0, // mass 1, // damage - sfx_mswing, // activesound + sfx_s3kc9s, //sfx_mswing, -- activesound MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -9551,9 +9708,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 34*FRACUNIT, // radius 68*FRACUNIT, // height 1, // display offset - 100, // mass + 0, // mass 1, // damage - sfx_mswing, // activesound + sfx_s3kc9s, //sfx_mswing, -- activesound MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -9632,7 +9789,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 17*FRACUNIT, // radius 34*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_SCENERY|MF_PAIN|MF_FIRE|MF_NOGRAVITY, // flags @@ -9659,7 +9816,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 34*FRACUNIT, // radius 68*FRACUNIT, // height 1, // display offset - 100, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_SCENERY|MF_PAIN|MF_FIRE|MF_NOGRAVITY, // flags @@ -9929,7 +10086,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_MISSILE|MF_FIRE, // flags @@ -10010,7 +10167,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_NOGRAVITY|MF_MISSILE|MF_FIRE|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags @@ -10665,6 +10822,303 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_JACKO1 + 3520, // doomednum + S_JACKO1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_SCENERY, // flags + S_JACKO1OVERLAY_1 // raisestate + }, + + { // MT_JACKO2 + 3521, // doomednum + S_JACKO2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_SCENERY, // flags + S_JACKO2OVERLAY_1 // raisestate + }, + + { // MT_JACKO3 + 3522, // doomednum + S_JACKO3, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_SCENERY, // flags + S_JACKO3OVERLAY_1 // raisestate + }, + + { // MT_HHZTREE_TOP + 3540, // doomednum + S_HHZTREE_TOP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_HHZTREE_PART + -1, // doomednum + S_HHZTREE_TRUNK,// spawnstate + 1000, // spawnhealth + S_HHZTREE_LEAF, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_HHZSHROOM + 3530, // doomednum + S_HHZSHROOM_1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_HHZGRASS + 3513, // doomednum + S_HHZGRASS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_HHZTENTACLE1 + 3515, // doomednum + S_HHZTENT1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_HHZTENTACLE2 + 3516, // doomednum + S_HHZTENT2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_HHZSTALAGMITE_TALL + 3517, // doomednum + S_HHZSTALAGMITE_TALL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_HHZSTALAGMITE_SHORT + 3518, // doomednum + S_HHZSTALAGMITE_SHORT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + // No, I did not do all of this by hand. // I made a script to make all of these for me. // Ha HA. ~Inuyasha @@ -11857,7 +12311,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIG_PALMTREE_TRUNK - 1472, // doomednum + -1, // doomednum S_BIG_PALMTREE_TRUNK, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11874,7 +12328,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 160*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -11901,17 +12355,17 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 160*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_RUNSPAWNFUNC|MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, { // MT_PALMTREE_TRUNK - 1474, // doomednum + -1, // doomednum S_PALMTREE_TRUNK, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11928,7 +12382,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 80*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -11955,12 +12409,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 80*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_RUNSPAWNFUNC|MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -12775,6 +13229,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_FLICKY_BUBBLE // raisestate }, + { // MT_SECRETFLICKY_01 + -1, // doomednum + S_SECRETFLICKY_01_OUT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIPTHING, // flags + S_FLICKY_BUBBLE // raisestate + }, + + { // MT_SECRETFLICKY_02 + -1, // doomednum + S_SECRETFLICKY_02_OUT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8, // speed + 8*FRACUNIT, // radius + 20*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIPTHING, // flags + S_FLICKY_BUBBLE // raisestate + }, + + { // MT_SEED + -1, // doomednum + S_SEED, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + -2*FRACUNIT, // speed + 4*FRACUNIT, // radius + 4*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_RAIN -1, // doomednum S_RAIN1, // spawnstate @@ -13045,33 +13580,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_SEED - -1, // doomednum - S_SEED, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // 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 - -2*FRACUNIT, // speed - 4*FRACUNIT, // radius - 4*FRACUNIT, // height - 0, // display offset - 4, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_SCENERY, // flags - S_NULL // raisestate - }, - { // MT_PARTICLE -1, // doomednum S_PARTICLE, // spawnstate @@ -13566,6 +14074,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_MACHINEAMBIENCE + 3405, // doomednum + S_INVISIBLE, // spawnstate + 24, // spawnhealth: repeat speed + S_NULL, // seestate + sfx_ambmac, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 1*FRACUNIT, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 20, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_AMBIENT, // flags + S_NULL // raisestate + }, + { // MT_CORK -1, // doomednum S_CORK, // spawnstate @@ -13586,7 +14121,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 16*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -13613,7 +14148,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -13993,7 +14528,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_bnce1, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_BOUNCE, // flags @@ -14020,7 +14555,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -14047,7 +14582,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -14074,7 +14609,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -14101,7 +14636,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags @@ -14114,7 +14649,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_NULL, // seestate sfx_wepfir, // seesound - 8, // reactiontime + 6*TICRATE, // reactiontime (<-- Looking for the Grenade Ring's fuse? It's right here! Again!) sfx_gbeep, // attacksound S_NULL, // painstate 192*FRACUNIT, // painchance @@ -14128,7 +14663,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 6*TICRATE, // mass (<-- Looking for the Grenade Ring's fuse? It's right here!) + 0, // mass 1, // damage sfx_s3k5d, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_BOUNCE|MF_GRENADEBOUNCE, // flags @@ -14290,7 +14825,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_FIRE|MF_MISSILE, // flags @@ -14317,7 +14852,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 20*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 1, // damage sfx_mario1, // activesound MF_SPECIAL|MF_SHOOTABLE|MF_BOUNCE, // flags @@ -14344,7 +14879,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 16*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_PAIN|MF_FIRE, // flags @@ -14398,7 +14933,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 0, // damage sfx_None, // activesound MF_PAIN, // flags @@ -14424,7 +14959,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 48*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 0, // damage sfx_None, // activesound MF_PAIN, // flags @@ -14451,7 +14986,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_MISSILE|MF_FIRE, // flags @@ -15107,6 +15642,249 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SMASHINGSPIKEBALL + 3001, // doomednum + S_SMASHSPIKE_FLOAT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 255, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 18*FRACUNIT, // radius + 28*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_HHZDUST + -1, // doomednum + S_HHZDUST1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 3*FRACUNIT, // speed + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_CACOLANTERN + 3102, // doomednum + S_CACO_LOOK, // spawnstate + 1, // spawnhealth + S_CACO_WAKE1, // seestate + sfx_s3k8a, // seesound + 32, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_CACO_DIE_FLAGS, // deathstate + S_NULL, // xdeathstate + sfx_lntdie, // deathsound + FRACUNIT, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_lntsit, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_RUNSPAWNFUNC|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_CACOSHARD + -1, // doomednum + S_CACOSHARD_RANDOMIZE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_lntdie, // deathsound + FRACUNIT, // speed + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_MISSILE|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_CACOFIRE + -1, // doomednum + S_CACOFIRE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_s3k70, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_CACOFIRE_EXPLODE1, // deathstate + S_NULL, // xdeathstate + sfx_s3k81, // deathsound + 20*FRACUNIT, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 0, // mass + 20, // damage + sfx_s3k48, // activesound + MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SPINBOBERT + 3100, // doomednum + S_SPINBOBERT_MOVE_FLIPUP, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_s3ka0, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD1, // deathstate + S_NULL, // xdeathstate + sfx_s3k92, // deathsound + 20*FRACUNIT, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 20, // damage + sfx_s3k48, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SPINBOBERT_FIRE1 + -1, // doomednum + S_SPINBOBERT_FIRE_MOVE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_ghosty, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD1, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 10*FRACUNIT, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 0, // mass + 20, // damage + sfx_None, // activesound + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_SPINBOBERT_FIRE2 + -1, // doomednum + S_SPINBOBERT_FIRE_MOVE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_ghosty, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD1, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + -10*FRACUNIT, // speed - only difference from above + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 0, // mass + 20, // damage + sfx_None, // activesound + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_HANGSTER + 3195, // doomednum + S_HANGSTER_LOOK, // spawnstate + 1, // spawnhealth + S_HANGSTER_SWOOP1, // seestate + sfx_s3ka0, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 20*FRACUNIT, // speed + 24*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 20, // damage + sfx_s3k48, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY|MF_SPAWNCEILING, // flags + S_NULL // raisestate + }, + { // MT_TELEPORTMAN 751, // doomednum S_INVISIBLE, // spawnstate @@ -15548,7 +16326,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_NULL, // seestate sfx_ambint, // seesound - 0, // reactiontime + 4, // reactiontime sfx_None, // attacksound S_NULL, // painstate 255, // painchance @@ -15562,7 +16340,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 16*FRACUNIT, // height 0, // display offset - 4, // mass + 0, // mass 0, // damage sfx_rocks1, // activesound MF_PAIN|MF_BOUNCE, // flags @@ -16022,7 +16800,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 30*FRACUNIT, // radius 40*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_NOSECTOR, // flags diff --git a/src/info.h b/src/info.h index dad067a23..dde746236 100644 --- a/src/info.h +++ b/src/info.h @@ -221,6 +221,9 @@ void A_Boss5Jump(); void A_LightBeamReset(); void A_MineExplode(); void A_MineRange(); +void A_ConnectToGround(); +void A_SpawnParticleRelative(); +void A_MultiShotDist(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 256 @@ -444,6 +447,12 @@ typedef enum sprite SPR_XMS4, // Lamppost SPR_XMS5, // Hanging Star + // Halloween Scenery + SPR_PUMK, // Pumpkins + SPR_HHPL, // Dr Seuss Trees + SPR_SHRM, // Mushroom + SPR_HHZM, // Misc + // Botanic Serenity Scenery SPR_BSZ1, // Tall flowers SPR_BSZ2, // Medium flowers @@ -494,6 +503,8 @@ typedef enum sprite SPR_FL14, // Dove SPR_FL15, // Cat SPR_FL16, // Canary + SPR_FS01, // Spider + SPR_FS02, // Bat // Springs SPR_SPRY, // yellow spring @@ -575,6 +586,16 @@ typedef enum sprite SPR_NPRU, // Nights Powerups SPR_CAPS, // Capsule thingy for NiGHTS + // Secret badniks and hazards, shhhh + SPR_FMCE, + SPR_HMCE, + SPR_CACO, + SPR_BAL2, + SPR_SBOB, + SPR_SBFL, + SPR_SBSK, + SPR_HBAT, + // Debris SPR_SPRK, // spark SPR_BOM1, // Robot Explosion @@ -2289,6 +2310,51 @@ typedef enum state S_XMASBERRYBUSH, S_XMASBUSH, + // Halloween Scenery + // Pumpkins + S_JACKO1, + S_JACKO1OVERLAY_1, + S_JACKO1OVERLAY_2, + S_JACKO1OVERLAY_3, + S_JACKO1OVERLAY_4, + S_JACKO2, + S_JACKO2OVERLAY_1, + S_JACKO2OVERLAY_2, + S_JACKO2OVERLAY_3, + S_JACKO2OVERLAY_4, + S_JACKO3, + S_JACKO3OVERLAY_1, + S_JACKO3OVERLAY_2, + S_JACKO3OVERLAY_3, + S_JACKO3OVERLAY_4, + // Dr Seuss Trees + S_HHZTREE_TOP, + S_HHZTREE_TRUNK, + S_HHZTREE_LEAF, + // Mushroom + S_HHZSHROOM_1, + S_HHZSHROOM_2, + S_HHZSHROOM_3, + S_HHZSHROOM_4, + S_HHZSHROOM_5, + S_HHZSHROOM_6, + S_HHZSHROOM_7, + S_HHZSHROOM_8, + S_HHZSHROOM_9, + S_HHZSHROOM_10, + S_HHZSHROOM_11, + S_HHZSHROOM_12, + S_HHZSHROOM_13, + S_HHZSHROOM_14, + S_HHZSHROOM_15, + S_HHZSHROOM_16, + // Misc + S_HHZGRASS, + S_HHZTENT1, + S_HHZTENT2, + S_HHZSTALAGMITE_TALL, + S_HHZSTALAGMITE_SHORT, + // Botanic Serenity's loads of scenery states S_BSZTALLFLOWER_RED, S_BSZTALLFLOWER_PURPLE, @@ -2728,6 +2794,19 @@ typedef enum state S_FLICKY_16_FLAP2, S_FLICKY_16_FLAP3, + // Spider + S_SECRETFLICKY_01_OUT, + S_SECRETFLICKY_01_AIM, + S_SECRETFLICKY_01_HOP, + S_SECRETFLICKY_01_UP, + S_SECRETFLICKY_01_DOWN, + + // Bat + S_SECRETFLICKY_02_OUT, + S_SECRETFLICKY_02_FLAP1, + S_SECRETFLICKY_02_FLAP2, + S_SECRETFLICKY_02_FLAP3, + S_YELLOWSPRING, S_YELLOWSPRING2, S_YELLOWSPRING3, @@ -3224,6 +3303,85 @@ typedef enum state S_NIGHTOPIANHELPER8, S_NIGHTOPIANHELPER9, + // Secret badniks and hazards, shhhh + S_SMASHSPIKE_FLOAT, + S_SMASHSPIKE_EASE1, + S_SMASHSPIKE_EASE2, + S_SMASHSPIKE_FALL, + S_SMASHSPIKE_STOMP1, + S_SMASHSPIKE_STOMP2, + S_SMASHSPIKE_RISE1, + S_SMASHSPIKE_RISE2, + + S_HHZDUST1, + S_HHZDUST2, + S_HHZDUST3, + S_HHZDUST4, + + S_CACO_LOOK, + S_CACO_WAKE1, + S_CACO_WAKE2, + S_CACO_WAKE3, + S_CACO_WAKE4, + S_CACO_ROAR, + S_CACO_CHASE, + S_CACO_CHASE_REPEAT, + S_CACO_RANDOM, + S_CACO_PREPARE_SOUND, + S_CACO_PREPARE1, + S_CACO_PREPARE2, + S_CACO_PREPARE3, + S_CACO_SHOOT_SOUND, + S_CACO_SHOOT1, + S_CACO_SHOOT2, + S_CACO_CLOSE, + S_CACO_DIE_FLAGS, + S_CACO_DIE_GIB1, + S_CACO_DIE_GIB2, + S_CACO_DIE_SCREAM, + S_CACO_DIE_SHATTER, + S_CACO_DIE_FALL, + S_CACOSHARD_RANDOMIZE, + S_CACOSHARD1_1, + S_CACOSHARD1_2, + S_CACOSHARD2_1, + S_CACOSHARD2_2, + S_CACOFIRE1, + S_CACOFIRE2, + S_CACOFIRE3, + S_CACOFIRE_EXPLODE1, + S_CACOFIRE_EXPLODE2, + S_CACOFIRE_EXPLODE3, + S_CACOFIRE_EXPLODE4, + + S_SPINBOBERT_MOVE_FLIPUP, + S_SPINBOBERT_MOVE_UP, + S_SPINBOBERT_MOVE_FLIPDOWN, + S_SPINBOBERT_MOVE_DOWN, + S_SPINBOBERT_FIRE_MOVE, + S_SPINBOBERT_FIRE_GHOST, + S_SPINBOBERT_FIRE_TRAIL1, + S_SPINBOBERT_FIRE_TRAIL2, + S_SPINBOBERT_FIRE_TRAIL3, + + S_HANGSTER_LOOK, + S_HANGSTER_SWOOP1, + S_HANGSTER_SWOOP2, + S_HANGSTER_ARC1, + S_HANGSTER_ARC2, + S_HANGSTER_ARC3, + S_HANGSTER_FLY1, + S_HANGSTER_FLY2, + S_HANGSTER_FLY3, + S_HANGSTER_FLY4, + S_HANGSTER_FLYREPEAT, + S_HANGSTER_ARCUP1, + S_HANGSTER_ARCUP2, + S_HANGSTER_ARCUP3, + S_HANGSTER_RETURN1, + S_HANGSTER_RETURN2, + S_HANGSTER_RETURN3, + S_CRUMBLE1, S_CRUMBLE2, @@ -3650,6 +3808,22 @@ typedef enum mobj_type MT_XMASBERRYBUSH, MT_XMASBUSH, + // Halloween Scenery + // Pumpkins + MT_JACKO1, + MT_JACKO2, + MT_JACKO3, + // Dr Seuss Trees + MT_HHZTREE_TOP, + MT_HHZTREE_PART, + // Misc + MT_HHZSHROOM, + MT_HHZGRASS, + MT_HHZTENTACLE1, + MT_HHZTENTACLE2, + MT_HHZSTALAGMITE_TALL, + MT_HHZSTALAGMITE_SHORT, + // Botanic Serenity scenery MT_BSZTALLFLOWER_RED, MT_BSZTALLFLOWER_PURPLE, @@ -3735,6 +3909,9 @@ typedef enum mobj_type MT_FLICKY_14, // Dove MT_FLICKY_15, // Cat MT_FLICKY_16, // Canary + MT_SECRETFLICKY_01, // Spider + MT_SECRETFLICKY_02, // Bat + MT_SEED, // Environmental Effects MT_RAIN, // Rain @@ -3747,7 +3924,6 @@ typedef enum mobj_type MT_WATERZAP, MT_SPINDUST, // Spindash dust MT_TFOG, - MT_SEED, MT_PARTICLE, MT_PARTICLEGEN, // For fans, etc. @@ -3770,6 +3946,7 @@ typedef enum mobj_type MT_AWATERH, // Ambient Water Sound 8 MT_RANDOMAMBIENT, MT_RANDOMAMBIENT2, + MT_MACHINEAMBIENCE, MT_CORK, @@ -3837,6 +4014,20 @@ typedef enum mobj_type MT_EGGCAPSULE, MT_NIGHTOPIANHELPER, // the actual helper object that orbits you + // Secret badniks and hazards, shhhh + MT_SMASHINGSPIKEBALL, + MT_HHZDUST, + + MT_CACOLANTERN, + MT_CACOSHARD, + MT_CACOFIRE, + + MT_SPINBOBERT, + MT_SPINBOBERT_FIRE1, + MT_SPINBOBERT_FIRE2, + + MT_HANGSTER, + // Utility Objects MT_TELEPORTMAN, MT_ALTVIEWMAN, diff --git a/src/p_enemy.c b/src/p_enemy.c index cc1d14a9b..e5a465dcf 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -249,6 +249,9 @@ void A_Boss5Jump(mobj_t *actor); void A_LightBeamReset(mobj_t *actor); void A_MineExplode(mobj_t *actor); void A_MineRange(mobj_t *actor); +void A_ConnectToGround(mobj_t *actor); +void A_SpawnParticleRelative(mobj_t *actor); +void A_MultiShotDist(mobj_t *actor); // // ENEMY THINKING @@ -3420,7 +3423,7 @@ void A_BubbleSpawn(mobj_t *actor) if (!(actor->flags2 & MF2_AMBUSH)) { // Quick! Look through players! - // Don't spawn bubbles unless a player is relatively close by (var2). + // Don't spawn bubbles unless a player is relatively close by (var1). for (i = 0; i < MAXPLAYERS; ++i) if (playeringame[i] && players[i].mo && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; + } // Function: A_ChangeAngleRelative @@ -10736,3 +10740,146 @@ void A_MineRange(mobj_t *actor) if ((dm>>FRACBITS) < locvar1) P_SetMobjState(actor, actor->info->meleestate); } + +// Function: A_ConnectToGround +// Description: Create a palm tree trunk/mine chain. +// +// var1 = Object type to connect to ground +// var2 = Object type to place on ground +// +void A_ConnectToGround(mobj_t *actor) +{ + mobj_t *work; + fixed_t workz; + fixed_t workh; + INT8 dir; + angle_t ang; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ConnectToGround", actor)) + return; +#endif + + P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); + + if (actor->flags2 & MF2_OBJECTFLIP) + { + workz = actor->ceilingz - (actor->z + actor->height); + dir = -1; + } + else + { + workz = actor->floorz - actor->z; + dir = 1; + } + + if (locvar2) + { + if (actor->flags2 & MF2_OBJECTFLIP) + workz -= FixedMul(mobjinfo[locvar2].height, actor->scale); + work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2); + } + + if (!locvar1) + return; + + workh = FixedMul(mobjinfo[locvar1].height, actor->scale); + + if (actor->flags2 & MF2_OBJECTFLIP) + workz -= workh; + + ang = actor->angle + ANGLE_45; + while (dir*workz < 0) + { + work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1); + if (work) + work->angle = ang; + ang += ANGLE_90; + workz += dir*workh; + } + + if (workz != 0) + actor->z += workz; +} + +// Function: A_SpawnParticleRelative +// +// Description: Spawns a particle effect relative to the location of the actor +// +// var1: +// var1 >> 16 = x +// var1 & 65535 = y +// var2: +// var2 >> 16 = z +// var2 & 65535 = state +// +void A_SpawnParticleRelative(mobj_t *actor) +{ + INT16 x, y, z; // Want to be sure we can use negative values + statenum_t state; + mobj_t *mo; + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnParticleRelative", actor)) + return; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_SpawnParticleRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); + + x = (INT16)(locvar1>>16); + y = (INT16)(locvar1&65535); + z = (INT16)(locvar2>>16); + state = (mobjtype_t)(locvar2&65535); + + // Spawn objects correctly in reverse gravity. + // NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame + mo = P_SpawnMobj(actor->x + FixedMul(x<scale), + actor->y + FixedMul(y<scale), + (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), MT_PARTICLE); + + // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn + mo->angle = actor->angle; + + if (actor->eflags & MFE_VERTICALFLIP) + mo->flags2 |= MF2_OBJECTFLIP; + + P_SetMobjState(mo, state); +} + +// Function: A_MultiShotDist +// +// Description: Spawns multiple shots based on player proximity +// +// var1: +// same as A_MultiShot +// var2: +// same as A_MultiShot +// +void A_MultiShotDist(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MultiShotDist", actor)) + return; +#endif + + { + UINT8 i; + // Quick! Look through players! + // Don't spawn dust unless a player is relatively close by (var1). + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].mo + && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (1600<flags & MF_SHOOTABLE) P_DamageMobj(thing, puncher, puncher, 1, 0); - else if (thing->type == MT_RING || thing->type == MT_COIN) + else if (thing->type == MT_RING || thing->type == MT_COIN || thing->type == MT_TOKEN) { thing->momz = FixedMul(3*FRACUNIT, thing->scale); P_TouchSpecialThing(thing, puncher, false); diff --git a/src/p_inter.c b/src/p_inter.c index 5de8b7fd3..c9cb6539f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2427,6 +2427,13 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_LinedefExecute(target->spawnpoint->angle, (source ? source : inflictor), target->subsector->sector); break; + case MT_SPINBOBERT: + if (target->hnext) + P_KillMobj(target->hnext, inflictor, source, damagetype); + if (target->hprev) + P_KillMobj(target->hprev, inflictor, source, damagetype); + break; + case MT_EGGTRAP: // Time for birdies! Yaaaaaaaay! target->fuse = TICRATE*2; diff --git a/src/p_local.h b/src/p_local.h index 49d3ed614..1958e6559 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -256,6 +256,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_CheckDeathPitCollide(mobj_t *mo); boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover); +void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype); mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type); diff --git a/src/p_map.c b/src/p_map.c index 3715e765b..9313d2149 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -673,10 +673,11 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (tmthing->player && tmthing->flags & MF_SHOOTABLE && thing->health > 0) { - UINT8 damagetype = 0; - if (thing->flags & MF_FIRE) // BURN! + UINT8 damagetype = thing->info->mass; + if (!damagetype && thing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; - P_DamageMobj(tmthing, thing, thing, 1, damagetype); + if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && thing->info->attacksound) + S_StartSound(thing, thing->info->attacksound); } return true; } @@ -689,10 +690,11 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (thing->player && thing->flags & MF_SHOOTABLE && tmthing->health > 0) { - UINT8 damagetype = 0; - if (tmthing->flags & MF_FIRE) // BURN! + UINT8 damagetype = tmthing->info->mass; + if (!damagetype && tmthing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; - P_DamageMobj(thing, tmthing, tmthing, 1, damagetype); + if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && tmthing->info->attacksound) + S_StartSound(tmthing, tmthing->info->attacksound); } return true; } @@ -860,7 +862,12 @@ static boolean PIT_CheckThing(mobj_t *thing) P_SetThingPosition(tmthing); } else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial - P_DamageMobj(thing, tmthing, tmthing->target, 1, 0); + { + UINT8 damagetype = tmthing->info->mass; + if (!damagetype && tmthing->flags & MF_FIRE) // BURN! + damagetype = DMG_FIRE; + P_DamageMobj(thing, tmthing, tmthing->target, 1, damagetype); + } // don't traverse any more diff --git a/src/p_mobj.c b/src/p_mobj.c index 45e1434d2..a7fa3bf97 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2200,7 +2200,7 @@ static void P_SceneryXYMovement(mobj_t *mo) // 1 - forces false check for water (rings) // 2 - forces false check for water + different quicksand behaviour (scenery) // -static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype) +void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype) { ffloor_t *rover; fixed_t delta1, delta2, thingtop; @@ -2764,7 +2764,7 @@ static boolean P_ZMovement(mobj_t *mo) else if (mo->type == MT_FALLINGROCK) { if (P_MobjFlip(mo)*mom.z > FixedMul(2*FRACUNIT, mo->scale)) - S_StartSound(mo, mo->info->activesound + P_RandomKey(mo->info->mass)); + S_StartSound(mo, mo->info->activesound + P_RandomKey(mo->info->reactiontime)); mom.z /= 2; // Rocks not so bouncy @@ -7410,6 +7410,61 @@ void P_MobjThinker(mobj_t *mobj) mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); P_SetThingPosition(mobj); break; + case MT_SMASHINGSPIKEBALL: + mobj->momx = mobj->momy = 0; + if (mobj->state-states == S_SMASHSPIKE_FALL && P_IsObjectOnGround(mobj)) + { + P_SetMobjState(mobj, S_SMASHSPIKE_STOMP1); + S_StartSound(mobj, sfx_spsmsh); + } + else if (mobj->state-states == S_SMASHSPIKE_RISE2 && P_MobjFlip(mobj)*(mobj->z - mobj->movecount) >= 0) + { + mobj->momz = 0; + P_SetMobjState(mobj, S_SMASHSPIKE_FLOAT); + } + break; + case MT_HANGSTER: + { + statenum_t st = mobj->state-states; + //ghost image trail when flying down + if (st == S_HANGSTER_SWOOP1 || st == S_HANGSTER_SWOOP2) + { + P_SpawnGhostMobj(mobj); + //curve when in line with target, otherwise curve to avoid crashing into floor + if ((mobj->z - mobj->floorz <= 80*FRACUNIT) || (mobj->target && (mobj->z - mobj->target->z <= 80*FRACUNIT))) + P_SetMobjState(mobj, (st = S_HANGSTER_ARC1)); + } + + //swoop arc movement stuff + if (st == S_HANGSTER_ARC1) + { + A_FaceTarget(mobj); + P_Thrust(mobj, mobj->angle, 1*FRACUNIT); + } + else if (st == S_HANGSTER_ARC2) + P_Thrust(mobj, mobj->angle, 2*FRACUNIT); + else if (st == S_HANGSTER_ARC3) + P_Thrust(mobj, mobj->angle, 4*FRACUNIT); + //if movement has stopped while flying (like hitting a wall), fly up immediately + else if (st == S_HANGSTER_FLY1 && !mobj->momx && !mobj->momy) + { + mobj->extravalue1 = 0; + P_SetMobjState(mobj, S_HANGSTER_ARCUP1); + } + //after swooping back up, check for ceiling + else if ((st == S_HANGSTER_RETURN1 || st == S_HANGSTER_RETURN2) && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height)) + P_SetMobjState(mobj, (st = S_HANGSTER_RETURN3)); + + //should you roost on a ceiling with F_SKY1 as its flat, disappear forever + if (st == S_HANGSTER_RETURN3 && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height) + && mobj->subsector->sector->ceilingpic == skyflatnum + && mobj->subsector->sector->ceilingheight == mobj->ceilingz) + { + P_RemoveMobj(mobj); + return; + } + } + break; case MT_EGGCAPSULE: if (!mobj->reactiontime) { @@ -8015,6 +8070,8 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s case MT_WALLSPIKE: P_SetMobjState(mobj, mobj->state->nextstate); mobj->fuse = mobj->info->speed; + if (mobj->spawnpoint) + mobj->fuse += (mobj->spawnpoint->angle/360); break; case MT_NIGHTSCORE: P_RemoveMobj(mobj); @@ -8396,7 +8453,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (titlemapinaction) mobj->flags &= ~MF_NOTHINK; break; case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: - mobj->fuse = mobj->info->mass; + mobj->fuse = mobj->info->painchance; break; case MT_BLACKEGGMAN: { @@ -8410,8 +8467,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Collision helper can be stood on but not pushed mobj->flags2 |= MF2_STANDONME; break; - case MT_WALLSPIKE: case MT_SPIKE: + case MT_WALLSPIKE: mobj->flags2 |= MF2_STANDONME; break; case MT_GFZTREE: @@ -8481,6 +8538,20 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_FLICKY_08: mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUA); break; + case MT_SMASHINGSPIKEBALL: + mobj->movecount = mobj->z; + break; + case MT_SPINBOBERT: + { + mobj_t *fire; + fire = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_SPINBOBERT_FIRE1); + P_SetTarget(&fire->target, mobj); + P_SetTarget(&mobj->hnext, fire); + fire = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_SPINBOBERT_FIRE2); + P_SetTarget(&fire->target, mobj); + P_SetTarget(&mobj->hprev, fire); + } + break; case MT_REDRING: // Make MT_REDRING red by default mobj->color = skincolor_redring; break; @@ -10208,12 +10279,42 @@ ML_EFFECT4 : Don't clip inside the ground break; case MT_THZTREE: { // Spawn the branches - angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); + angle_t mobjangle = FixedAngle((mthing->angle % 113)*FRACUNIT); P_SpawnMobjFromMobj(mobj, 1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; } break; + case MT_HHZTREE_TOP: + { // Spawn the branches + angle_t mobjangle; + mobj_t *leaf; + mobjangle = FixedAngle((mthing->angle % 90)*FRACUNIT); +#define doleaf(x, y) \ + leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ + leaf->angle = mobjangle;\ + P_SetMobjState(leaf, leaf->info->seestate);\ + mobjangle += ANGLE_90 + doleaf(1*FRACUNIT, 0); + doleaf(0, 1*FRACUNIT); + doleaf(-1*FRACUNIT, 0); + doleaf(0, -1*FRACUNIT); +#undef doleaf + } + break; + case MT_JACKO1: + case MT_JACKO2: + case MT_JACKO3: + { + mobj_t *overlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, mobj); + P_SetMobjState(overlay, mobj->info->raisestate); + } + break; + case MT_SMASHINGSPIKEBALL: + if (mthing->angle > 0) + mobj->tics += mthing->angle; + break; default: break; } @@ -10246,9 +10347,6 @@ ML_EFFECT4 : Don't clip inside the ground } else if (i == MT_TOKEN) { - if (mthing->options & MTF_OBJECTSPECIAL) // Mario Block version - mobj->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - // We advanced tokenbits earlier due to the return check. // Subtract 1 here for the correct value. mobj->health = 1 << (tokenbits - 1); @@ -10296,7 +10394,9 @@ ML_EFFECT4 : Don't clip inside the ground if (mthing->options & MTF_OBJECTSPECIAL) { mobj->flags &= ~MF_SCENERY; - mobj->fuse = mthing->angle + mobj->info->speed; + mobj->fuse = (16 - mthing->extrainfo) * (mthing->angle + mobj->info->speed) / 16; + if (mthing->options & MTF_EXTRA) + P_SetMobjState(mobj, mobj->info->meleestate); } // Use per-thing collision for spikes if the deaf flag isn't checked. if (!(mthing->options & MTF_AMBUSH) && !metalrecording) @@ -10313,7 +10413,9 @@ ML_EFFECT4 : Don't clip inside the ground if (mthing->options & MTF_OBJECTSPECIAL) { mobj->flags &= ~MF_SCENERY; - mobj->fuse = mobj->info->speed; + mobj->fuse = (16 - mthing->extrainfo) * ((mthing->angle/360) + mobj->info->speed) / 16; + if (mthing->options & MTF_EXTRA) + P_SetMobjState(mobj, mobj->info->meleestate); } // Use per-thing collision for spikes if the deaf flag isn't checked. if (!(mthing->options & MTF_AMBUSH) && !metalrecording) diff --git a/src/p_user.c b/src/p_user.c index 8ae91f81c..d2dc36a8e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3565,7 +3565,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) if (mo) { //P_InstaThrust(mo, player->mo->angle, FixedMul(mo->info->speed, player->mo->scale)); - mo->fuse = mo->info->mass; + mo->fuse = mo->info->reactiontime; } } // Scatter diff --git a/src/sounds.c b/src/sounds.c index 3a7219c6d..cabc7e686 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -76,6 +76,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"steam1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001 {"steam2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001 {"wbreak", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wood breaking"}, + {"ambmac", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machinery"}, + {"spsmsh", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy impact"}, {"rainin", true, 24, 4, -1, NULL, 0, -1, -1, LUMPERROR, "Rain"}, {"litng1", false, 16, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning"}, @@ -226,6 +228,12 @@ sfxinfo_t S_sfx[NUMSFX] = {"prloop", false, 104, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gust of wind"}, {"timeup", true, 256, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous Countdown"}, + // Halloween + {"lntsit", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cacolantern awake"}, + {"lntdie", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cacolantern death"}, + {"pumpkn", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pumpkin smash"}, + {"ghosty", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Laughter"}, + // Mario {"koopfr" , true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"}, {"mario1", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hitting a ceiling"}, @@ -295,16 +303,16 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning zap"}, {"s3k46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"}, {"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising dust"}, - {"s3k48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic clink"}, + {"s3k48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pulse"}, {"s3k49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling rock"}, {"s3k4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Grab"}, {"s3k4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Water splash"}, {"s3k4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"}, {"s3k4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing bullet"}, - {"s3k4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bomb explosion"}, + {"s3k4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Big explosion"}, {"s3k4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"}, {"s3k50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Siren"}, - {"s3k51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling bomb"}, + {"s3k51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling hazard"}, {"s3k52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, {"s3k53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, {"s3k54", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Firing"}, // MetalSonic shot fire @@ -325,7 +333,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, {"s3k64", false, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Clatter"}, {"s3k65", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got blue sphere"}, // Blue Spheres - {"s3k66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage clear"}, + {"s3k66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage end"}, {"s3k67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing missile"}, {"s3k68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Unknown possibilities"}, {"s3k69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Switch click"}, @@ -372,7 +380,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ghost"}, {"s3k93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rebuilding"}, {"s3k94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, - {"s3k95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising from lava"}, + {"s3k95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lava burst"}, {"s3k96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling object"}, {"s3k97", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind"}, {"s3k98", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling spike"}, diff --git a/src/sounds.h b/src/sounds.h index 60451b6ea..ab024c253 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -142,6 +142,8 @@ typedef enum sfx_steam1, sfx_steam2, sfx_wbreak, + sfx_ambmac, + sfx_spsmsh, sfx_rainin, sfx_litng1, @@ -292,6 +294,12 @@ typedef enum sfx_prloop, sfx_timeup, // Was gonna be played when less than ten seconds are on the clock; uncomment uses of this to see it in-context + // Halloween + sfx_lntsit, + sfx_lntdie, + sfx_pumpkn, + sfx_ghosty, + // Mario sfx_koopfr, sfx_mario1, From dbc0ac230314645ceae18ad02823110915485da8 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 2 May 2018 20:03:18 +0100 Subject: [PATCH 107/212] * Springs no longer need MF_SOLID to function. (I tried to add a special Sonic 1-3 style "springs are solid from the side" thing with native support, but it turns out that requires too many hacks for an optional extra feature not used in the campaign, so No.) * Springs no longer send you flying relative to the slope whilst you're on a slope. (I tried fixing this before, but this is a much more solid fix.) --- src/info.c | 20 +++++++++--------- src/p_map.c | 60 +++++++++++++++++++++++++++++------------------------ 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/info.c b/src/info.c index cd1705a51..3d1178000 100644 --- a/src/info.c +++ b/src/info.c @@ -6066,7 +6066,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 11*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SPRING, // flags S_BLUESPRING2 // raisestate }, @@ -6093,7 +6093,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SPRING, // flags S_YELLOWSPRING2 // raisestate }, @@ -6120,7 +6120,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SPRING, // flags S_REDSPRING2 // raisestate }, @@ -6147,7 +6147,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // mass 20*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SPRING, // flags S_YDIAG2 // raisestate }, @@ -6174,7 +6174,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // mass 32*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING, // flags + MF_SPRING, // flags S_RDIAG2 // raisestate }, @@ -6201,7 +6201,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 36*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_NOGRAVITY, // flags + MF_SPRING|MF_NOGRAVITY, // flags S_YHORIZ2 // raisestate }, @@ -6228,7 +6228,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 72*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_NOGRAVITY, // flags + MF_SPRING|MF_NOGRAVITY, // flags S_RHORIZ2 // raisestate }, @@ -6255,7 +6255,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 4*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_NOGRAVITY, // flags + MF_SPRING|MF_NOGRAVITY, // flags S_BHORIZ2 // raisestate }, @@ -9738,7 +9738,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // mass 0, // damage sfx_mswing, // activesound - MF_SCENERY|MF_SOLID|MF_SPRING|MF_NOGRAVITY, // flags + MF_SCENERY|MF_SPRING|MF_NOGRAVITY, // flags S_YELLOWSPRINGBALL2 // raisestate }, @@ -9765,7 +9765,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // mass 0, // damage sfx_mswing, // activesound - MF_SCENERY|MF_SOLID|MF_SPRING|MF_NOGRAVITY, // flags + MF_SCENERY|MF_SPRING|MF_NOGRAVITY, // flags S_REDSPRINGBALL2 // raisestate }, diff --git a/src/p_map.c b/src/p_map.c index 9313d2149..5122a6746 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -117,7 +117,12 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) fixed_t horizspeed = spring->info->damage; UINT8 secondjump; - if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic + // Does nothing? + if (!vertispeed && !horizspeed) + return false; + + // Object was already sprung this tic + if (object->eflags & MFE_SPRUNG) return false; // Spectators don't trigger springs. @@ -130,17 +135,26 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) return false; } + if (spring->eflags & MFE_VERTICALFLIP) + vertispeed *= -1; + +#ifdef ESLOPE + object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. +#endif + if (object->player && ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) || (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2))) { S_StartSound(object, sfx_s3k8b); - horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3); - vertispeed = FixedMul(vertispeed, (6*FRACUNIT)/5); // aprox square root of above + if (horizspeed) + horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3); + if (vertispeed) + vertispeed = FixedMul(vertispeed, (6*FRACUNIT)/5); // aprox square root of above } object->eflags |= MFE_SPRUNG; // apply this flag asap! - spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify + spring->flags &= ~(MF_SPRING|MF_SPECIAL); // De-solidify if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA { @@ -148,9 +162,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) P_TryMove(object, spring->x, spring->y, true); } - if (spring->eflags & MFE_VERTICALFLIP) - vertispeed *= -1; - if (vertispeed > 0) object->z = spring->z + spring->height + 1; else if (vertispeed < 0) @@ -186,7 +197,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(horizspeed,FixedSqrt(FixedMul(object->scale, spring->scale)))); // Re-solidify - spring->flags |= (spring->info->flags & (MF_SPECIAL|MF_SOLID)); + spring->flags |= (spring->info->flags & (MF_SPRING|MF_SPECIAL)); P_SetMobjState(spring, spring->info->raisestate); @@ -239,7 +250,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) } #ifdef ESLOPE - object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. + object->standingslope = NULL; // And again. #endif return true; @@ -398,7 +409,6 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails) static boolean PIT_CheckThing(mobj_t *thing) { fixed_t blockdist; - boolean iwassprung = false; // don't clip against self if (thing == tmthing) @@ -514,7 +524,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE))) + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return true; // Don't collide with your buddies while NiGHTS-flying. @@ -1062,12 +1072,17 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->flags & MF_PUSHABLE) { if (thing->type == MT_FAN || thing->type == MT_STEAM) + { P_DoFanAndGasJet(thing, tmthing); + return true; + } else if (thing->flags & MF_SPRING) { if ( thing->z <= tmthing->z + tmthing->height && tmthing->z <= thing->z + thing->height) - iwassprung = P_DoSpring(thing, tmthing); + if (P_DoSpring(thing, tmthing)) + return false; + return true; } } @@ -1158,7 +1173,9 @@ static boolean PIT_CheckThing(mobj_t *thing) { if ( thing->z <= tmthing->z + tmthing->height && tmthing->z <= thing->z + thing->height) - iwassprung = P_DoSpring(thing, tmthing); + if (P_DoSpring(thing, tmthing)) + return false; + return true; } // Are you touching the side of the object you're interacting with? else if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height @@ -1206,15 +1223,8 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - if (!(tmthing->player) && (thing->player)) + if ((!tmthing->player) && (thing->player)) ; // no solid thing should ever be able to step up onto a player - else if (thing->flags & MF_SPRING && (tmthing->player || tmthing->flags & MF_PUSHABLE)) - { - if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now... - return false; // "cancel" P_TryMove via blocking so you keep your current position - } - else if (tmthing->flags & MF_SPRING && (thing->flags & MF_PUSHABLE)) - ; // Fix a few nasty spring-jumping bugs that happen sometimes. // Monitors are not treated as solid to players who are jumping, spinning or gliding, // unless it's a CTF team monitor and you're on the wrong team else if (thing->flags & MF_MONITOR && tmthing->player @@ -1253,13 +1263,11 @@ static boolean PIT_CheckThing(mobj_t *thing) topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways - if (thing->flags & MF_SPRING) - ; // block only when jumping not high enough, // (dont climb max. 24units while already in air) // since return false doesn't handle momentum properly, // we lie to P_TryMove() so it's always too high - else if (tmthing->player && tmthing->z + tmthing->height > topz + if (tmthing->player && tmthing->z + tmthing->height > topz && tmthing->z + tmthing->height < tmthing->ceilingz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... @@ -1299,13 +1307,11 @@ static boolean PIT_CheckThing(mobj_t *thing) topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways - if (thing->flags & MF_SPRING) - ; // block only when jumping not high enough, // (dont climb max. 24units while already in air) // since return false doesn't handle momentum properly, // we lie to P_TryMove() so it's always too high - else if (tmthing->player && tmthing->z < topz + if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... From cf9d53efd8347232ea581170ed8744c9157e2067 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 2 May 2018 20:35:20 +0100 Subject: [PATCH 108/212] Kill MF2_STANDONME (mechanically; still occupies the slot... will change that next time I have to handle the DEHACKED lists.) --- src/p_enemy.c | 2 - src/p_map.c | 4 +- src/p_mobj.c | 175 ++++++++++++++++++++------------------------------ 3 files changed, 70 insertions(+), 111 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index e5a465dcf..9f588bd31 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2718,7 +2718,6 @@ void A_GoldMonitorPop(mobj_t *actor) // Players can now stand on top of us. P_UnsetThingPosition(actor); actor->flags &= ~(MF_MONITOR|MF_SHOOTABLE); - actor->flags2 |= MF2_STANDONME; P_SetThingPosition(actor); // Don't count this box in statistics. Sorry. @@ -2791,7 +2790,6 @@ void A_GoldMonitorRestore(mobj_t *actor) #endif actor->flags |= MF_MONITOR|MF_SHOOTABLE; - actor->flags2 &= ~MF2_STANDONME; actor->health = 1; // Just in case. } diff --git a/src/p_map.c b/src/p_map.c index 5122a6746..54737e960 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1270,7 +1270,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->player && tmthing->z + tmthing->height > topz && tmthing->z + tmthing->height < tmthing->ceilingz) { - if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... + if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... return false; tmfloorz = tmceilingz = topz; // block while in air @@ -1314,7 +1314,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz) { - if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... + if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... return false; tmfloorz = tmceilingz = topz; // block while in air diff --git a/src/p_mobj.c b/src/p_mobj.c index a7fa3bf97..1f8b9a720 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2701,9 +2701,7 @@ static boolean P_ZMovement(mobj_t *mo) if (P_MobjFlip(mo)*mom.z < 0) // falling { - if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) - mo->eflags |= MFE_JUSTHITFLOOR; + mo->eflags |= MFE_JUSTHITFLOOR; if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something mom.z = -mom.z; @@ -2783,14 +2781,11 @@ static boolean P_ZMovement(mobj_t *mo) mom.z = 0; } } - else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) - mom.z = tmfloorthing->momz; - else if (!tmfloorthing) - mom.z = 0; + else + mom.z = (tmfloorthing ? tmfloorthing->momz : 0); + } - else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) + else if (tmfloorthing) mom.z = tmfloorthing->momz; #ifdef ESLOPE @@ -2968,100 +2963,89 @@ static void P_PlayerZMovement(mobj_t *mo) if (P_MobjFlip(mo)*mo->momz < -FixedMul(8*FRACUNIT, mo->scale)) mo->player->deltaviewheight = (P_MobjFlip(mo)*mo->momz)>>3; // make sure momz is negative - if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) // Spin Attack + mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack + { - mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack - - if (mo->eflags & MFE_JUSTHITFLOOR) - { #ifdef POLYOBJECTS - // Check if we're on a polyobject - // that triggers a linedef executor. - msecnode_t *node; - boolean stopmovecut = false; + // Check if we're on a polyobject + // that triggers a linedef executor. + msecnode_t *node; + boolean stopmovecut = false; - for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) + { + sector_t *sec = node->m_sector; + subsector_t *newsubsec; + size_t i; + + for (i = 0; i < numsubsectors; i++) { - sector_t *sec = node->m_sector; - subsector_t *newsubsec; - size_t i; + newsubsec = &subsectors[i]; - for (i = 0; i < numsubsectors; i++) + if (newsubsec->sector != sec) + continue; + + if (newsubsec->polyList) { - newsubsec = &subsectors[i]; + polyobj_t *po = newsubsec->polyList; + sector_t *polysec; - if (newsubsec->sector != sec) - continue; - - if (newsubsec->polyList) + while(po) { - polyobj_t *po = newsubsec->polyList; - sector_t *polysec; - - while(po) + if (!P_MobjInsidePolyobj(po, mo) || !(po->flags & POF_SOLID)) { - if (!P_MobjInsidePolyobj(po, mo) || !(po->flags & POF_SOLID)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - // We're inside it! Yess... - polysec = po->lines[0]->backsector; - - // Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red - if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && po->thinker) - stopmovecut = true; - - if (!(po->flags & POF_LDEXEC)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - if (mo->z == polysec->ceilingheight) - { - // We're landing on a PO, so check for - // a linedef executor. - // Trigger tags are 32000 + the PO's ID number. - P_LinedefExecute((INT16)(32000 + po->id), mo, NULL); - } - po = (polyobj_t *)(po->link.next); + continue; } + + // We're inside it! Yess... + polysec = po->lines[0]->backsector; + + // Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red + if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && po->thinker) + stopmovecut = true; + + if (!(po->flags & POF_LDEXEC)) + { + po = (polyobj_t *)(po->link.next); + continue; + } + + if (mo->z == polysec->ceilingheight) + { + // We're landing on a PO, so check for + // a linedef executor. + // Trigger tags are 32000 + the PO's ID number. + P_LinedefExecute((INT16)(32000 + po->id), mo, NULL); + } + + po = (polyobj_t *)(po->link.next); } } } - - if (!stopmovecut) -#endif - - // Cut momentum in half when you hit the ground and - // aren't pressing any controls. - if (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING)) - { - mo->momx >>= 1; - mo->momy >>= 1; - } } - clipmomz = P_PlayerHitFloor(mo->player); + if (!stopmovecut) +#endif + + // Cut momentum in half when you hit the ground and + // aren't pressing any controls. + if (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING)) + { + mo->momx >>= 1; + mo->momy >>= 1; + } } + + clipmomz = P_PlayerHitFloor(mo->player); + if (!(mo->player->pflags & PF_SPINNING) && mo->player->powers[pw_carry] != CR_NIGHTSMODE) mo->player->pflags &= ~PF_STARTDASH; if (clipmomz) - { - if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) - mo->momz = tmfloorthing->momz; - else if (!tmfloorthing) - mo->momz = 0; - } + mo->momz = (tmfloorthing ? tmfloorthing->momz : 0); } - else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) + else if (tmfloorthing) mo->momz = tmfloorthing->momz; } else if (!(mo->flags & MF_NOGRAVITY)) // Gravity here! @@ -3266,12 +3250,9 @@ static boolean P_SceneryZMovement(mobj_t *mo) if (P_MobjFlip(mo)*mo->momz < 0) // falling { - if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) - mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack + mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack - if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) + if (tmfloorthing) mo->momz = tmfloorthing->momz; else if (!tmfloorthing) mo->momz = 0; @@ -8463,23 +8444,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) P_SetTarget(&spawn->target, mobj); } break; - case MT_BLACKEGGMAN_HELPER: - // Collision helper can be stood on but not pushed - mobj->flags2 |= MF2_STANDONME; - break; - case MT_SPIKE: - case MT_WALLSPIKE: - mobj->flags2 |= MF2_STANDONME; - break; - case MT_GFZTREE: - case MT_GFZBERRYTREE: - case MT_GFZCHERRYTREE: - case MT_LAMPPOST1: - case MT_LAMPPOST2: - case MT_DSZSTALAGMITE: - case MT_DSZ2STALAGMITE: - mobj->flags2 |= MF2_STANDONME; - break; case MT_DETON: mobj->movedir = 0; break; @@ -10524,10 +10488,7 @@ ML_EFFECT4 : Don't clip inside the ground } if (mobj->flags & MF_PUSHABLE) - { mobj->flags &= ~MF_PUSHABLE; - mobj->flags2 |= MF2_STANDONME; - } if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) { From 856edd50dfdace589c683a0f908006b8e72a2b0b Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 2 May 2018 20:55:07 +0100 Subject: [PATCH 109/212] Remove the ugly double-hack for monitors! Doesn't QUITE do it via the return value of P_DamageMobj like MI and I theorised it should do, but it's functionally identical whilst being less code to maintain. --- src/p_map.c | 83 ++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 54737e960..a219d3b97 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1177,66 +1177,57 @@ static boolean PIT_CheckThing(mobj_t *thing) return false; return true; } - // Are you touching the side of the object you're interacting with? - else if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height - && thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z) + // Monitor? + else if (thing->flags & MF_MONITOR + && !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2))) { // 0 = none, 1 = elemental pierce, 2 = bubble bounce UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY) ? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2) : 0); - if (thing->flags & MF_MONITOR - && (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) - || ((tmthing->player->pflags & PF_JUMPED) - && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) - || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) - || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) - || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING) - && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) - || elementalpierce)) + if (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) + || ((tmthing->player->pflags & PF_JUMPED) + && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) + || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) + || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) + || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING) + && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) + || elementalpierce) { - player_t *player = tmthing->player; - SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed. - fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;; - fixed_t *z = &tmthing->z; // aau. - P_DamageMobj(thing, tmthing, tmthing, 1, 0); // break the monitor - // Going down? Then bounce back up. - if ((P_MobjWasRemoved(thing) // Monitor was removed - || !thing->health) // or otherwise popped - && (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up - && (elementalpierce != 1)) // you're not piercing through the monitor... + if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height + && thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z) { - if (elementalpierce == 2) - P_DoBubbleBounce(player); - else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) - *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. + player_t *player = tmthing->player; + SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed. + fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;; + fixed_t *z = &tmthing->z; // aau. + // Going down? Then bounce back up. + if (P_DamageMobj(thing, tmthing, tmthing, 1, 0) // break the monitor + && (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up + && (elementalpierce != 1)) // you're not piercing through the monitor... + { + if (elementalpierce == 2) + P_DoBubbleBounce(player); + else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. + } + if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. + { + if (player->pflags & PF_BOUNCING) + P_DoAbilityBounce(player, false); + return false; + } + else + *z -= *momz; // to ensure proper collision. } - if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. - { - if (player->pflags & PF_BOUNCING) - P_DoAbilityBounce(player, false); - return false; - } - else - *z -= *momz; // to ensure proper collision. + + return true; } } } if ((!tmthing->player) && (thing->player)) ; // no solid thing should ever be able to step up onto a player - // Monitors are not treated as solid to players who are jumping, spinning or gliding, - // unless it's a CTF team monitor and you're on the wrong team - else if (thing->flags & MF_MONITOR && tmthing->player - && (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) - || ((tmthing->player->pflags & PF_JUMPED) - && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) - || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) - || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) - || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING) - && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))) - && !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2))) - ; // z checking at last // Treat noclip things as non-solid! else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID From 6d1ba20a1d02f635c3c6ee01cc482bbf521cedc3 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 2 May 2018 23:48:50 +0100 Subject: [PATCH 110/212] * Add native support for multi-hit badiks to MF_ENEMY. * MF2_FRET application and removal. * Flashing when flag present. * Bounce player back on successful damaging. * Add their spawnhealth to the chain. * Reduce code duplication in P_TouchSpecialThing. * Play with Crawla Commander a little bit as a test of its power. --- src/info.c | 4 +- src/p_enemy.c | 20 +- src/p_inter.c | 215 ++++------ src/p_mobj.c | 1064 ++++++++++++++++++++++++------------------------ src/r_things.c | 2 +- 5 files changed, 626 insertions(+), 679 deletions(-) diff --git a/src/info.c b/src/info.c index 3d1178000..e568d6ae2 100644 --- a/src/info.c +++ b/src/info.c @@ -3760,7 +3760,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_CCOMMAND3, // seestate sfx_None, // seesound 2*TICRATE, // reactiontime - sfx_None, // attacksound + sfx_s3k60, // attacksound S_CCOMMAND3, // painstate 200, // painchance sfx_dmpain, // painsound @@ -3775,7 +3775,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 100, // mass 0, // damage - sfx_None, // activesound + sfx_s3k5d, // activesound MF_SLIDEME|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags S_NULL // raisestate }, diff --git a/src/p_enemy.c b/src/p_enemy.c index 9f588bd31..8ef75ff93 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5005,11 +5005,6 @@ void A_CrawlaCommanderThink(mobj_t *actor) else thefloor = actor->floorz; - if (actor->fuse & 1) - actor->flags2 |= MF2_DONTDRAW; - else - actor->flags2 &= ~MF2_DONTDRAW; - if (actor->reactiontime > 0) actor->reactiontime--; @@ -5043,14 +5038,13 @@ void A_CrawlaCommanderThink(mobj_t *actor) dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y); - if (actor->target->player && actor->health > 1) + if (actor->target->player) { - if (dist < FixedMul(128*FRACUNIT, actor->scale) + if (dist < FixedMul(64<<(FRACBITS+(actor->health == 1 ? 0 : 1)), actor->scale) && ((actor->target->player->pflags & PF_JUMPED) || (actor->target->player->pflags & PF_SPINNING))) { - // Auugh! He's trying to kill you! Strafe! STRAAAAFFEEE!! - if (actor->target->momx || actor->target->momy) - P_InstaThrust(actor, actor->angle - ANGLE_180, FixedMul(20*FRACUNIT, actor->scale)); + // Auugh! She's trying to kill you! Strafe! STRAAAAFFEEE!! + P_InstaThrust(actor, actor->angle - ANGLE_180, FixedMul(20*FRACUNIT, actor->scale)); return; } } @@ -5076,7 +5070,7 @@ void A_CrawlaCommanderThink(mobj_t *actor) actor->angle -= (P_RandomByte()<<10); if (actor->health > 1) - P_InstaThrust(actor, actor->angle, FixedMul(10*FRACUNIT, actor->scale)); + P_Thrust(actor, actor->angle, 2*actor->scale); } else if (!actor->reactiontime) { @@ -5085,8 +5079,9 @@ void A_CrawlaCommanderThink(mobj_t *actor) if (dist < FixedMul(512*FRACUNIT, actor->scale)) { actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_InstaThrust(actor, actor->angle, FixedMul(60*FRACUNIT, actor->scale)); + P_InstaThrust(actor, actor->angle, FixedMul(30*FRACUNIT, actor->scale)); actor->threshold = 1; + S_StartSound(actor, actor->info->attacksound); } } actor->reactiontime = 2*TICRATE + P_RandomByte()/2; @@ -5103,6 +5098,7 @@ void A_CrawlaCommanderThink(mobj_t *actor) actor->momz = FixedMul(locvar2, actor->scale); actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); P_InstaThrust(actor, actor->angle, FixedMul(locvar2/8, actor->scale)); + S_StartSound(actor, actor->info->activesound); // pogo on player } else diff --git a/src/p_inter.c b/src/p_inter.c index c9cb6539f..c4f05963c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -349,8 +349,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->spectator) return; - // Ignore eggman in "ouchie" mode - if (special->flags & MF_BOSS && special->flags2 & MF2_FRET) + // Ignore multihits in "ouchie" mode + if (special->flags & (MF_ENEMY|MF_BOSS) && special->flags2 & MF2_FRET) return; #ifdef HAVE_BLUA @@ -363,14 +363,52 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) ? (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2) : 0); - if (special->flags & MF_BOSS) + if ((special->flags & (MF_ENEMY|MF_BOSS)) && !(special->flags & MF_MISSILE)) { + //////////////////////////////////////////////////////// + /////ENEMIES & BOSSES!!///////////////////////////////// + //////////////////////////////////////////////////////// + if (special->type == MT_BLACKEGGMAN) { P_DamageMobj(toucher, special, special, 1, 0); // ouch return; } + if (special->type == MT_BIGMINE) + { + special->momx = toucher->momx/3; + special->momy = toucher->momy/3; + special->momz = toucher->momz/3; + toucher->momx /= -8; + toucher->momy /= -8; + toucher->momz /= -8; + special->flags &= ~MF_SPECIAL; + if (special->info->activesound) + S_StartSound(special, special->info->activesound); + P_SetTarget(&special->tracer, toucher); + player->homing = 0; + return; + } + + if (special->type == MT_GSNAPPER && !elementalpierce + && toucher->z < special->z + special->height && toucher->z + toucher->height > special->z + && P_DamageMobj(toucher, special, special, 1, DMG_SPIKE)) + return; // Can only hit snapper from above + + if (special->type == MT_SHARP + && ((special->state == &states[special->info->xdeathstate]) || (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0))) + { + if (player->pflags & PF_BOUNCING) + { + toucher->momz = -toucher->momz; + P_DoAbilityBounce(player, false); + return; + } + else if (P_DamageMobj(toucher, special, special, 1, DMG_SPIKE)) + return; // Cannot hit sharp from above or when red and angry + } + if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) || ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) || (player->pflags & (PF_SPINNING|PF_GLIDING)) @@ -388,15 +426,18 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } if (player->pflags & PF_BOUNCING) P_DoAbilityBounce(player, false); - toucher->momx = -toucher->momx; - toucher->momy = -toucher->momy; + if (special->info->spawnhealth > 1) // Multi-hit? Bounce back! + { + toucher->momx = -toucher->momx; + toucher->momy = -toucher->momy; + } P_DamageMobj(special, toucher, toucher, 1, 0); } else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP)) || (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) && player->charability == CA_FLY && (player->powers[pw_tailsfly] - || toucher->state-states == S_PLAY_FLY_TIRED)) // Tails can shred stuff with his propeller. + || toucher->state-states == S_PLAY_FLY_TIRED)) // Tails can shred stuff with her propeller. { toucher->momz = -toucher->momz/2; @@ -407,81 +448,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } - else if ((special->flags & MF_ENEMY) && !(special->flags & MF_MISSILE)) - { - //////////////////////////////////////////////////////// - /////ENEMIES!!////////////////////////////////////////// - //////////////////////////////////////////////////////// - if (special->type == MT_BIGMINE) - { - special->momx = toucher->momx/3; - special->momy = toucher->momy/3; - special->momz = toucher->momz/3; - toucher->momx /= -8; - toucher->momy /= -8; - toucher->momz /= -8; - special->flags &= ~MF_SPECIAL; - if (special->info->activesound) - S_StartSound(special, special->info->activesound); - P_SetTarget(&special->tracer, toucher); - player->homing = 0; - return; - } - else if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) - || player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce) - && toucher->z < special->z + special->height && toucher->z + toucher->height > special->z - && !(player->powers[pw_shield] & SH_PROTECTSPIKE)) - { - // Can only hit snapper from above - P_DamageMobj(toucher, special, special, 1, DMG_SPIKE); - } - else if (special->type == MT_SHARP - && ((special->state == &states[special->info->xdeathstate]) || (toucher->z > special->z + special->height/2)) - && !(player->powers[pw_shield] & SH_PROTECTSPIKE)) - { - if (player->pflags & PF_BOUNCING) - { - toucher->momz = -toucher->momz; - P_DoAbilityBounce(player, false); - } - else // Cannot hit sharp from above or when red and angry - P_DamageMobj(toucher, special, special, 1, DMG_SPIKE); - } - else if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) - || ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) - || (player->pflags & (PF_SPINNING|PF_GLIDING)) - || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) - || ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0)) - || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? - { - if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) - { - if (elementalpierce == 2) - P_DoBubbleBounce(player); - else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) - toucher->momz = -toucher->momz; - } - if (player->pflags & PF_BOUNCING) - P_DoAbilityBounce(player, false); - - P_DamageMobj(special, toucher, toucher, 1, 0); - } - else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP)) - || (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) // Flame is bad at logic - JTE - && player->charability == CA_FLY - && (player->powers[pw_tailsfly] - || toucher->state-states == S_PLAY_FLY_TIRED)) // Tails can shred stuff with his propeller. - { - if (P_MobjFlip(toucher)*toucher->momz < 0) - toucher->momz = -toucher->momz/2; - - P_DamageMobj(special, toucher, toucher, 1, 0); - } - else - P_DamageMobj(toucher, special, special, 1, 0); - - return; - } else if (special->flags & MF_FIRE) { P_DamageMobj(toucher, special, special, 1, DMG_FIRE); @@ -2195,21 +2161,27 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { if (target->flags & MF_BOSS) score = 1000; - else if ((target->flags & MF_ENEMY) && !(target->flags & MF_MISSILE)) + else if ((target->flags & MF_ENEMY) && !(target->flags & MF_MISSILE) && target->info->spawnhealth) { + UINT8 locscoreadd = source->player->scoreadd + target->info->spawnhealth; mobj_t *scoremobj; UINT32 scorestate = mobjinfo[MT_SCORE].spawnstate; scoremobj = P_SpawnMobj(target->x, target->y, target->z + (target->height / 2), MT_SCORE); - // On ground? No chain starts. - if (!source->player->powers[pw_invulnerability] && P_IsObjectOnGround(source)) + // More Sonic-like point system + if (!mariomode) switch (locscoreadd) { - source->player->scoreadd = 0; - score = 100; + case 1: score = 100; break; + case 2: score = 200; scorestate += 1; break; + case 3: score = 500; scorestate += 2; break; + case 4: case 5: case 6: case 7: case 8: case 9: + case 10: case 11: case 12: case 13: case 14: + score = 1000; scorestate += 3; break; + default: score = 10000; scorestate += 4; break; } // Mario Mode has Mario-like chain point values - else if (mariomode) switch (++source->player->scoreadd) + else switch (locscoreadd) { case 1: score = 100; break; case 2: score = 200; scorestate += 1; break; @@ -2229,19 +2201,12 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget scorestate += 10; break; } - // More Sonic-like point system - else switch (++source->player->scoreadd) - { - case 1: score = 100; break; - case 2: score = 200; scorestate += 1; break; - case 3: score = 500; scorestate += 2; break; - case 4: case 5: case 6: case 7: case 8: case 9: - case 10: case 11: case 12: case 13: case 14: - score = 1000; scorestate += 3; break; - default: score = 10000; scorestate += 4; break; - } P_SetMobjState(scoremobj, scorestate); + + // On ground? No chain starts. + if (!source->player->powers[pw_invulnerability] && P_IsObjectOnGround(source)) + source->player->scoreadd = locscoreadd; } } @@ -2385,6 +2350,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_SpawnMobjFromMobj(target, 0, 0, 0, MT_YELLOWSPRING); break; + case MT_CRAWLACOMMANDER: + target->momx = target->momy = target->momz = 0; + break; + case MT_EGGMOBILE3: { thinker_t *th; @@ -3131,36 +3100,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; } - // Special case for Crawla Commander - if (target->type == MT_CRAWLACOMMANDER) - { - if (!force && target->fuse) // Invincible - return false; - -#ifdef HAVE_BLUA - if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) - return true; -#endif - - if (target->health > 1) - { - if (target->info->painsound) - S_StartSound(target, target->info->painsound); - - target->fuse = TICRATE/2; - target->flags2 |= MF2_FRET; - } - else - { - target->flags |= MF_NOGRAVITY; - target->fuse = 0; - } - - target->momx = target->momy = target->momz = 0; - - P_InstaThrust(target, target->angle-ANGLE_180, FixedMul(5*FRACUNIT, target->scale)); - } - else if (target->flags & MF_BOSS) + if (target->flags & (MF_ENEMY|MF_BOSS)) { if (!force && target->flags2 & MF2_FRET) // Currently flashing from being hit return false; @@ -3173,13 +3113,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (target->health > 1) target->flags2 |= MF2_FRET; } -#ifdef HAVE_BLUA - else if (target->flags & MF_ENEMY) - { - if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) - return true; - } -#endif player = target->player; @@ -3348,6 +3281,18 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da else switch (target->type) { + case MT_CRAWLACOMMANDER: + if (target->info->painsound) + S_StartSound(target, target->info->painsound); + + target->fuse = TICRATE/2; + target->momz = 0; + + P_InstaThrust(target, target->angle-ANGLE_180, FixedMul(5*FRACUNIT, target->scale)); + + P_SetMobjState(target, target->info->painstate); + + break; case MT_EGGMOBILE2: // egg slimer if (target->health < target->info->damage) // in pinch phase { diff --git a/src/p_mobj.c b/src/p_mobj.c index 1f8b9a720..027a5f48d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7312,376 +7312,392 @@ void P_MobjThinker(mobj_t *mobj) default: break; } - else switch (mobj->type) + else { - case MT_WALLSPIKEBASE: - if (!mobj->target) { - P_RemoveMobj(mobj); - return; - } - mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK); -#if 0 - if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle - { - mobj_t *target = mobj->target; // shortcut - const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale); - P_UnsetThingPosition(mobj); - mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); - mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); - P_SetThingPosition(mobj); - mobj->angle = target->angle + ANGLE_90; - } -#endif - break; - case MT_FALLINGROCK: - // Despawn rocks here in case zmovement code can't do so (blame slopes) - if (!mobj->momx && !mobj->momy && !mobj->momz - && ((mobj->eflags & MFE_VERTICALFLIP) ? - mobj->z + mobj->height >= mobj->ceilingz - : mobj->z <= mobj->floorz)) - { - P_RemoveMobj(mobj); - return; - } - P_MobjCheckWater(mobj); - break; - case MT_EMERALDSPAWN: - if (mobj->threshold) - { - mobj->threshold--; + if ((mobj->flags & MF_ENEMY) && (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)) + mobj->flags2 &= ~MF2_FRET; - if (!mobj->threshold && !mobj->target && mobj->reactiontime) - { - mobj_t *emerald = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->reactiontime); - emerald->threshold = 42; - P_SetTarget(&mobj->target, emerald); - P_SetTarget(&emerald->target, mobj); + switch (mobj->type) + { + case MT_WALLSPIKEBASE: + if (!mobj->target) { + P_RemoveMobj(mobj); + return; } - } - break; - case MT_AQUABUZZ: - mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn - { - if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 - && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16) + mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK); +#if 0 + if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle { - // Home in on the target. - P_HomingAttack(mobj, mobj->tracer); + mobj_t *target = mobj->target; // shortcut + const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale); + P_UnsetThingPosition(mobj); + mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); + mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); + P_SetThingPosition(mobj); + mobj->angle = target->angle + ANGLE_90; + } +#endif + break; + case MT_FALLINGROCK: + // Despawn rocks here in case zmovement code can't do so (blame slopes) + if (!mobj->momx && !mobj->momy && !mobj->momz + && ((mobj->eflags & MFE_VERTICALFLIP) ? + mobj->z + mobj->height >= mobj->ceilingz + : mobj->z <= mobj->floorz)) + { + P_RemoveMobj(mobj); + return; + } + P_MobjCheckWater(mobj); + break; + case MT_EMERALDSPAWN: + if (mobj->threshold) + { + mobj->threshold--; - if (mobj->z < mobj->floorz) - mobj->z = mobj->floorz; + if (!mobj->threshold && !mobj->target && mobj->reactiontime) + { + mobj_t *emerald = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->reactiontime); + emerald->threshold = 42; + P_SetTarget(&mobj->target, emerald); + P_SetTarget(&emerald->target, mobj); + } + } + break; + case MT_AQUABUZZ: + mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn + { + if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 + && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16) + { + // Home in on the target. + P_HomingAttack(mobj, mobj->tracer); - if (leveltime % mobj->info->painchance == 0) - S_StartSound(mobj, mobj->info->activesound); + if (mobj->z < mobj->floorz) + mobj->z = mobj->floorz; + + if (leveltime % mobj->info->painchance == 0) + S_StartSound(mobj, mobj->info->activesound); + } + else + { + // Try to find a player + P_LookForPlayers(mobj, true, true, mobj->radius * 16); + mobj->momx >>= 1; + mobj->momy >>= 1; + mobj->momz >>= 1; + } + } + break; + case MT_BIGMINE: + mobj->extravalue1 += 3; + mobj->extravalue1 %= 360; + P_UnsetThingPosition(mobj); + mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); + P_SetThingPosition(mobj); + break; + case MT_SMASHINGSPIKEBALL: + mobj->momx = mobj->momy = 0; + if (mobj->state-states == S_SMASHSPIKE_FALL && P_IsObjectOnGround(mobj)) + { + P_SetMobjState(mobj, S_SMASHSPIKE_STOMP1); + S_StartSound(mobj, sfx_spsmsh); + } + else if (mobj->state-states == S_SMASHSPIKE_RISE2 && P_MobjFlip(mobj)*(mobj->z - mobj->movecount) >= 0) + { + mobj->momz = 0; + P_SetMobjState(mobj, S_SMASHSPIKE_FLOAT); + } + break; + case MT_HANGSTER: + { + statenum_t st = mobj->state-states; + //ghost image trail when flying down + if (st == S_HANGSTER_SWOOP1 || st == S_HANGSTER_SWOOP2) + { + P_SpawnGhostMobj(mobj); + //curve when in line with target, otherwise curve to avoid crashing into floor + if ((mobj->z - mobj->floorz <= 80*FRACUNIT) || (mobj->target && (mobj->z - mobj->target->z <= 80*FRACUNIT))) + P_SetMobjState(mobj, (st = S_HANGSTER_ARC1)); + } + + //swoop arc movement stuff + if (st == S_HANGSTER_ARC1) + { + A_FaceTarget(mobj); + P_Thrust(mobj, mobj->angle, 1*FRACUNIT); + } + else if (st == S_HANGSTER_ARC2) + P_Thrust(mobj, mobj->angle, 2*FRACUNIT); + else if (st == S_HANGSTER_ARC3) + P_Thrust(mobj, mobj->angle, 4*FRACUNIT); + //if movement has stopped while flying (like hitting a wall), fly up immediately + else if (st == S_HANGSTER_FLY1 && !mobj->momx && !mobj->momy) + { + mobj->extravalue1 = 0; + P_SetMobjState(mobj, S_HANGSTER_ARCUP1); + } + //after swooping back up, check for ceiling + else if ((st == S_HANGSTER_RETURN1 || st == S_HANGSTER_RETURN2) && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height)) + P_SetMobjState(mobj, (st = S_HANGSTER_RETURN3)); + + //should you roost on a ceiling with F_SKY1 as its flat, disappear forever + if (st == S_HANGSTER_RETURN3 && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height) + && mobj->subsector->sector->ceilingpic == skyflatnum + && mobj->subsector->sector->ceilingheight == mobj->ceilingz) + { + P_RemoveMobj(mobj); + return; + } + } + break; + case MT_EGGCAPSULE: + if (!mobj->reactiontime) + { + // Target nearest player on your mare. + // (You can make it float up/down by adding MF_FLOAT, + // but beware level design pitfalls.) + fixed_t shortest = 1024*FRACUNIT; + INT32 i; + P_SetTarget(&mobj->target, NULL); + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].mo + && players[i].mare == mobj->threshold && players[i].rings > 0) + { + fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); + if (dist < shortest) + { + P_SetTarget(&mobj->target, players[i].mo); + shortest = dist; + } + } + } + break; + case MT_EGGMOBILE2_POGO: + if (!mobj->target + || !mobj->target->health + || mobj->target->state == &states[mobj->target->info->spawnstate] + || mobj->target->state == &states[mobj->target->info->raisestate]) + { + P_RemoveMobj(mobj); + return; + } + P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height); + break; + case MT_HAMMER: + if (mobj->z <= mobj->floorz) + { + P_RemoveMobj(mobj); + return; + } + break; + case MT_KOOPA: + P_KoopaThinker(mobj); + break; + case MT_REDRING: + if (((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz)) + && mobj->flags & MF_MISSILE) + { + P_ExplodeMissile(mobj); + return; + } + break; + case MT_BOSSFLYPOINT: + return; + case MT_NIGHTSCORE: + mobj->color = (UINT8)(leveltime % SKINCOLOR_WHITE); + break; + case MT_JETFUME1: + { + fixed_t jetx, jety; + + if (!mobj->target // if you have no target + || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now + { // then remove yourself as well! + P_RemoveMobj(mobj); + return; + } + + jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); + jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); + + if (mobj->fuse == 56) // First one + { + P_UnsetThingPosition(mobj); + mobj->x = jetx; + mobj->y = jety; + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(38*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(38*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + else if (mobj->fuse == 57) + { + P_UnsetThingPosition(mobj); + mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + else if (mobj->fuse == 58) + { + P_UnsetThingPosition(mobj); + mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + else if (mobj->fuse == 59) + { + jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, -mobj->target->radius); + jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, -mobj->target->radius); + P_UnsetThingPosition(mobj); + mobj->x = jetx; + mobj->y = jety; + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height/2 + mobj->height/2; + else + mobj->z = mobj->target->z + mobj->target->height/2 - mobj->height/2; + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + mobj->fuse++; + } + break; + case MT_PROPELLER: + { + fixed_t jetx, jety; + + if (!mobj->target // if you have no target + || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now + { // then remove yourself as well! + P_RemoveMobj(mobj); + return; + } + + jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale)); + jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale)); + + P_UnsetThingPosition(mobj); + mobj->x = jetx; + mobj->y = jety; + mobj->z = mobj->target->z + FixedMul(17*FRACUNIT, mobj->target->scale); + mobj->angle = mobj->target->angle - ANGLE_180; + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + break; + case MT_JETFLAME: + { + if (!mobj->target // if you have no target + || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now + { // then remove yourself as well! + P_RemoveMobj(mobj); + return; + } + + P_UnsetThingPosition(mobj); + mobj->x = mobj->target->x; + mobj->y = mobj->target->y; + mobj->z = mobj->target->z - FixedMul(50*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + break; + case MT_NIGHTSDRONE: + if (mobj->state >= &states[S_NIGHTSDRONE_SPARKLING1] && mobj->state <= &states[S_NIGHTSDRONE_SPARKLING16]) + { + mobj->flags2 &= ~MF2_DONTDRAW; + mobj->z = mobj->floorz + mobj->height + (mobj->spawnpoint->options >> ZSHIFT) * FRACUNIT; + mobj->angle = 0; + + if (!mobj->target) + { + mobj_t *goalpost = P_SpawnMobj(mobj->x, mobj->y, mobj->z + FRACUNIT, MT_NIGHTSGOAL); + CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n"); + goalpost->angle = mobj->angle; + P_SetTarget(&mobj->target, goalpost); + } + + if (G_IsSpecialStage(gamemap)) + { // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime. + INT32 i; + boolean bonustime = false; + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime) + { + bonustime = true; + break; + } + if (!bonustime) + { + mobj->flags &= ~MF_NOGRAVITY; + P_SetMobjState(mobj, S_NIGHTSDRONE1); + mobj->flags2 |= MF2_DONTDRAW; + } + } + else if (mobj->tracer && mobj->tracer->player) + { + if (!(mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE)) + { + mobj->flags &= ~MF_NOGRAVITY; + mobj->flags2 &= ~MF2_DONTDRAW; + P_SetMobjState(mobj, S_NIGHTSDRONE1); + } + else if (!mobj->tracer->player->bonustime) + { + mobj->flags &= ~MF_NOGRAVITY; + P_SetMobjState(mobj, S_NIGHTSDRONE1); + } + } } else { - // Try to find a player - P_LookForPlayers(mobj, true, true, mobj->radius * 16); - mobj->momx >>= 1; - mobj->momy >>= 1; - mobj->momz >>= 1; - } - } - break; - case MT_BIGMINE: - mobj->extravalue1 += 3; - mobj->extravalue1 %= 360; - P_UnsetThingPosition(mobj); - mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); - P_SetThingPosition(mobj); - break; - case MT_SMASHINGSPIKEBALL: - mobj->momx = mobj->momy = 0; - if (mobj->state-states == S_SMASHSPIKE_FALL && P_IsObjectOnGround(mobj)) - { - P_SetMobjState(mobj, S_SMASHSPIKE_STOMP1); - S_StartSound(mobj, sfx_spsmsh); - } - else if (mobj->state-states == S_SMASHSPIKE_RISE2 && P_MobjFlip(mobj)*(mobj->z - mobj->movecount) >= 0) - { - mobj->momz = 0; - P_SetMobjState(mobj, S_SMASHSPIKE_FLOAT); - } - break; - case MT_HANGSTER: - { - statenum_t st = mobj->state-states; - //ghost image trail when flying down - if (st == S_HANGSTER_SWOOP1 || st == S_HANGSTER_SWOOP2) - { - P_SpawnGhostMobj(mobj); - //curve when in line with target, otherwise curve to avoid crashing into floor - if ((mobj->z - mobj->floorz <= 80*FRACUNIT) || (mobj->target && (mobj->z - mobj->target->z <= 80*FRACUNIT))) - P_SetMobjState(mobj, (st = S_HANGSTER_ARC1)); - } + if (G_IsSpecialStage(gamemap)) + { // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime. + INT32 i; - //swoop arc movement stuff - if (st == S_HANGSTER_ARC1) - { - A_FaceTarget(mobj); - P_Thrust(mobj, mobj->angle, 1*FRACUNIT); - } - else if (st == S_HANGSTER_ARC2) - P_Thrust(mobj, mobj->angle, 2*FRACUNIT); - else if (st == S_HANGSTER_ARC3) - P_Thrust(mobj, mobj->angle, 4*FRACUNIT); - //if movement has stopped while flying (like hitting a wall), fly up immediately - else if (st == S_HANGSTER_FLY1 && !mobj->momx && !mobj->momy) - { - mobj->extravalue1 = 0; - P_SetMobjState(mobj, S_HANGSTER_ARCUP1); - } - //after swooping back up, check for ceiling - else if ((st == S_HANGSTER_RETURN1 || st == S_HANGSTER_RETURN2) && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height)) - P_SetMobjState(mobj, (st = S_HANGSTER_RETURN3)); + boolean bonustime = false; + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime) + { + bonustime = true; + break; + } - //should you roost on a ceiling with F_SKY1 as its flat, disappear forever - if (st == S_HANGSTER_RETURN3 && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height) - && mobj->subsector->sector->ceilingpic == skyflatnum - && mobj->subsector->sector->ceilingheight == mobj->ceilingz) - { - P_RemoveMobj(mobj); - return; - } - } - break; - case MT_EGGCAPSULE: - if (!mobj->reactiontime) - { - // Target nearest player on your mare. - // (You can make it float up/down by adding MF_FLOAT, - // but beware level design pitfalls.) - fixed_t shortest = 1024*FRACUNIT; - INT32 i; - P_SetTarget(&mobj->target, NULL); - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo - && players[i].mare == mobj->threshold && players[i].rings > 0) - { - fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); - if (dist < shortest) + if (bonustime) { - P_SetTarget(&mobj->target, players[i].mo); - shortest = dist; + P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1); + mobj->flags |= MF_NOGRAVITY; + } + else + { + if (mobj->target) + { + CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); + P_RemoveMobj(mobj->target); + P_SetTarget(&mobj->target, NULL); + } + mobj->flags2 |= MF2_DONTDRAW; } } - } - break; - case MT_EGGMOBILE2_POGO: - if (!mobj->target - || !mobj->target->health - || mobj->target->state == &states[mobj->target->info->spawnstate] - || mobj->target->state == &states[mobj->target->info->raisestate]) - { - P_RemoveMobj(mobj); - return; - } - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height); - break; - case MT_HAMMER: - if (mobj->z <= mobj->floorz) - { - P_RemoveMobj(mobj); - return; - } - break; - case MT_KOOPA: - P_KoopaThinker(mobj); - break; - case MT_REDRING: - if (((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz)) - && mobj->flags & MF_MISSILE) - { - P_ExplodeMissile(mobj); - return; - } - break; - case MT_BOSSFLYPOINT: - return; - case MT_NIGHTSCORE: - mobj->color = (UINT8)(leveltime % SKINCOLOR_WHITE); - break; - case MT_JETFUME1: - { - fixed_t jetx, jety; - - if (!mobj->target // if you have no target - || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; - } - - jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); - jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); - - if (mobj->fuse == 56) // First one - { - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(38*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(38*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 57) - { - P_UnsetThingPosition(mobj); - mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 58) - { - P_UnsetThingPosition(mobj); - mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 59) - { - jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, -mobj->target->radius); - jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, -mobj->target->radius); - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height/2 + mobj->height/2; - else - mobj->z = mobj->target->z + mobj->target->height/2 - mobj->height/2; - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - mobj->fuse++; - } - break; - case MT_PROPELLER: - { - fixed_t jetx, jety; - - if (!mobj->target // if you have no target - || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; - } - - jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale)); - jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale)); - - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - mobj->z = mobj->target->z + FixedMul(17*FRACUNIT, mobj->target->scale); - mobj->angle = mobj->target->angle - ANGLE_180; - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - break; - case MT_JETFLAME: - { - if (!mobj->target // if you have no target - || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; - } - - P_UnsetThingPosition(mobj); - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - mobj->z = mobj->target->z - FixedMul(50*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - break; - case MT_NIGHTSDRONE: - if (mobj->state >= &states[S_NIGHTSDRONE_SPARKLING1] && mobj->state <= &states[S_NIGHTSDRONE_SPARKLING16]) - { - mobj->flags2 &= ~MF2_DONTDRAW; - mobj->z = mobj->floorz + mobj->height + (mobj->spawnpoint->options >> ZSHIFT) * FRACUNIT; - mobj->angle = 0; - - if (!mobj->target) - { - mobj_t *goalpost = P_SpawnMobj(mobj->x, mobj->y, mobj->z + FRACUNIT, MT_NIGHTSGOAL); - CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n"); - goalpost->angle = mobj->angle; - P_SetTarget(&mobj->target, goalpost); - } - - if (G_IsSpecialStage(gamemap)) - { // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime. - INT32 i; - boolean bonustime = false; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime) - { - bonustime = true; - break; - } - if (!bonustime) - { - mobj->flags &= ~MF_NOGRAVITY; - P_SetMobjState(mobj, S_NIGHTSDRONE1); - mobj->flags2 |= MF2_DONTDRAW; - } - } - else if (mobj->tracer && mobj->tracer->player) - { - if (!(mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE)) - { - mobj->flags &= ~MF_NOGRAVITY; - mobj->flags2 &= ~MF2_DONTDRAW; - P_SetMobjState(mobj, S_NIGHTSDRONE1); - } - else if (!mobj->tracer->player->bonustime) - { - mobj->flags &= ~MF_NOGRAVITY; - P_SetMobjState(mobj, S_NIGHTSDRONE1); - } - } - } - else - { - if (G_IsSpecialStage(gamemap)) - { // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime. - INT32 i; - - boolean bonustime = false; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime) - { - bonustime = true; - break; - } - - if (bonustime) - { - P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1); - mobj->flags |= MF_NOGRAVITY; - } - else + else if (mobj->tracer && mobj->tracer->player) { if (mobj->target) { @@ -7689,192 +7705,182 @@ void P_MobjThinker(mobj_t *mobj) P_RemoveMobj(mobj->target); P_SetTarget(&mobj->target, NULL); } - mobj->flags2 |= MF2_DONTDRAW; + + if (mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE) + { + if (mobj->tracer->player->bonustime) + { + P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1); + mobj->flags |= MF_NOGRAVITY; + } + else + mobj->flags2 |= MF2_DONTDRAW; + } + else // Not NiGHTS + mobj->flags2 &= ~MF2_DONTDRAW; + } + mobj->angle += ANG10; + if (mobj->z <= mobj->floorz) + mobj->momz = 5*FRACUNIT; + } + break; + case MT_PLAYER: + if (mobj->player) + P_PlayerMobjThinker(mobj); + return; + case MT_SKIM: + // check mobj against possible water content, before movement code + P_MobjCheckWater(mobj); + + // Keep Skim at water surface + if (mobj->z <= mobj->watertop) + { + mobj->flags |= MF_NOGRAVITY; + if (mobj->z < mobj->watertop) + { + if (mobj->watertop - mobj->z <= FixedMul(mobj->info->speed*FRACUNIT, mobj->scale)) + mobj->z = mobj->watertop; + else + mobj->momz = FixedMul(mobj->info->speed*FRACUNIT, mobj->scale); } } - else if (mobj->tracer && mobj->tracer->player) + else { - if (mobj->target) - { - CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); - P_RemoveMobj(mobj->target); - P_SetTarget(&mobj->target, NULL); - } + mobj->flags &= ~MF_NOGRAVITY; + if (mobj->z > mobj->watertop && mobj->z - mobj->watertop < FixedMul(MAXSTEPMOVE, mobj->scale)) + mobj->z = mobj->watertop; + } + break; + case MT_RING: + case MT_COIN: + case MT_BLUEBALL: + case MT_REDTEAMRING: + case MT_BLUETEAMRING: + // No need to check water. Who cares? + P_RingThinker(mobj); + if (mobj->flags2 & MF2_NIGHTSPULL) + P_NightsItemChase(mobj); + else + A_AttractChase(mobj); + return; + // Flung items + case MT_FLINGRING: + case MT_FLINGCOIN: + if (mobj->flags2 & MF2_NIGHTSPULL) + P_NightsItemChase(mobj); + else + A_AttractChase(mobj); + break; + case MT_NIGHTSWING: + if (mobj->flags2 & MF2_NIGHTSPULL) + P_NightsItemChase(mobj); + break; + case MT_EMBLEM: + if (mobj->flags2 & MF2_NIGHTSPULL) + P_NightsItemChase(mobj); + break; + case MT_SHELL: + if (mobj->threshold && mobj->threshold != TICRATE) + mobj->threshold--; - if (mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE) + if (mobj->threshold >= TICRATE) + { + mobj->angle += ((mobj->movedir == 1) ? ANGLE_22h : ANGLE_337h); + P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), (mobj->info->speed*mobj->scale)); + } + break; + case MT_TURRET: + P_MobjCheckWater(mobj); + P_CheckPosition(mobj, mobj->x, mobj->y); + if (P_MobjWasRemoved(mobj)) + return; + mobj->floorz = tmfloorz; + mobj->ceilingz = tmceilingz; + + if ((mobj->eflags & MFE_UNDERWATER) && mobj->health > 0) + { + P_SetMobjState(mobj, mobj->info->deathstate); + mobj->health = 0; + mobj->flags2 &= ~MF2_FIRING; + } + else if (mobj->health > 0 && mobj->z + mobj->height > mobj->ceilingz) // Crushed + { + INT32 i,j; + fixed_t ns; + fixed_t x,y,z; + mobj_t *mo2; + + z = mobj->subsector->sector->floorheight + FixedMul(64*FRACUNIT, mobj->scale); + for (j = 0; j < 2; j++) { - if (mobj->tracer->player->bonustime) + for (i = 0; i < 32; i++) { - P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1); - mobj->flags |= MF_NOGRAVITY; + const angle_t fa = (i*FINEANGLES/16) & FINEMASK; + ns = FixedMul(64 * FRACUNIT, mobj->scale); + x = mobj->x + FixedMul(FINESINE(fa),ns); + y = mobj->y + FixedMul(FINECOSINE(fa),ns); + + mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); + ns = FixedMul(16 * FRACUNIT, mobj->scale); + mo2->momx = FixedMul(FINESINE(fa),ns); + mo2->momy = FixedMul(FINECOSINE(fa),ns); } - else + z -= FixedMul(32*FRACUNIT, mobj->scale); + } + P_SetMobjState(mobj, mobj->info->deathstate); + mobj->health = 0; + mobj->flags2 &= ~MF2_FIRING; + } + break; + case MT_BLUEFLAG: + case MT_REDFLAG: + { + sector_t *sec2; + sec2 = P_ThingOnSpecial3DFloor(mobj); + if ((sec2 && GETSECSPECIAL(sec2->special, 4) == 2) || (GETSECSPECIAL(mobj->subsector->sector->special, 4) == 2)) + mobj->fuse = 1; // Return to base. + break; + } + case MT_CANNONBALL: +#ifdef FLOORSPLATS + R_AddFloorSplat(mobj->tracer->subsector, mobj->tracer, "TARGET", mobj->tracer->x, + mobj->tracer->y, mobj->tracer->floorz, SPLATDRAWMODE_SHADE); +#endif + break; + case MT_SPINDUST: // Spindash dust + mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 + mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same + //mobj->momz = mobj->momz+P_MobjFlip(mobj)/3; // no meaningful change in value to be frank + if (mobj->state >= &states[S_SPINDUST_BUBBLE1] && mobj->state <= &states[S_SPINDUST_BUBBLE4]) // bubble dust! + { + P_MobjCheckWater(mobj); + if (mobj->watertop != mobj->subsector->sector->floorheight - 1000*FRACUNIT + && mobj->z+mobj->height >= mobj->watertop - 5*FRACUNIT) mobj->flags2 |= MF2_DONTDRAW; } - else // Not NiGHTS - mobj->flags2 &= ~MF2_DONTDRAW; - } - mobj->angle += ANG10; - if (mobj->z <= mobj->floorz) - mobj->momz = 5*FRACUNIT; - } - break; - case MT_PLAYER: - if (mobj->player) - P_PlayerMobjThinker(mobj); - return; - case MT_SKIM: - // check mobj against possible water content, before movement code - P_MobjCheckWater(mobj); - - // Keep Skim at water surface - if (mobj->z <= mobj->watertop) - { - mobj->flags |= MF_NOGRAVITY; - if (mobj->z < mobj->watertop) - { - if (mobj->watertop - mobj->z <= FixedMul(mobj->info->speed*FRACUNIT, mobj->scale)) - mobj->z = mobj->watertop; - else - mobj->momz = FixedMul(mobj->info->speed*FRACUNIT, mobj->scale); - } - } - else - { - mobj->flags &= ~MF_NOGRAVITY; - if (mobj->z > mobj->watertop && mobj->z - mobj->watertop < FixedMul(MAXSTEPMOVE, mobj->scale)) - mobj->z = mobj->watertop; - } - break; - case MT_RING: - case MT_COIN: - case MT_BLUEBALL: - case MT_REDTEAMRING: - case MT_BLUETEAMRING: - // No need to check water. Who cares? - P_RingThinker(mobj); - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - else - A_AttractChase(mobj); - return; - // Flung items - case MT_FLINGRING: - case MT_FLINGCOIN: - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - else - A_AttractChase(mobj); - break; - case MT_NIGHTSWING: - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - break; - case MT_EMBLEM: - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - break; - case MT_SHELL: - if (mobj->threshold && mobj->threshold != TICRATE) - mobj->threshold--; - - if (mobj->threshold >= TICRATE) - { - mobj->angle += ((mobj->movedir == 1) ? ANGLE_22h : ANGLE_337h); - P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), (mobj->info->speed*mobj->scale)); - } - break; - case MT_TURRET: - P_MobjCheckWater(mobj); - P_CheckPosition(mobj, mobj->x, mobj->y); - if (P_MobjWasRemoved(mobj)) - return; - mobj->floorz = tmfloorz; - mobj->ceilingz = tmceilingz; - - if ((mobj->eflags & MFE_UNDERWATER) && mobj->health > 0) - { - P_SetMobjState(mobj, mobj->info->deathstate); - mobj->health = 0; - mobj->flags2 &= ~MF2_FIRING; - } - else if (mobj->health > 0 && mobj->z + mobj->height > mobj->ceilingz) // Crushed - { - INT32 i,j; - fixed_t ns; - fixed_t x,y,z; - mobj_t *mo2; - - z = mobj->subsector->sector->floorheight + FixedMul(64*FRACUNIT, mobj->scale); - for (j = 0; j < 2; j++) - { - for (i = 0; i < 32; i++) - { - const angle_t fa = (i*FINEANGLES/16) & FINEMASK; - ns = FixedMul(64 * FRACUNIT, mobj->scale); - x = mobj->x + FixedMul(FINESINE(fa),ns); - y = mobj->y + FixedMul(FINECOSINE(fa),ns); - - mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); - ns = FixedMul(16 * FRACUNIT, mobj->scale); - mo2->momx = FixedMul(FINESINE(fa),ns); - mo2->momy = FixedMul(FINECOSINE(fa),ns); - } - z -= FixedMul(32*FRACUNIT, mobj->scale); - } - P_SetMobjState(mobj, mobj->info->deathstate); - mobj->health = 0; - mobj->flags2 &= ~MF2_FIRING; - } - break; - case MT_BLUEFLAG: - case MT_REDFLAG: - { - sector_t *sec2; - sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 4) == 2) || (GETSECSPECIAL(mobj->subsector->sector->special, 4) == 2)) - mobj->fuse = 1; // Return to base. break; - } - case MT_CANNONBALL: -#ifdef FLOORSPLATS - R_AddFloorSplat(mobj->tracer->subsector, mobj->tracer, "TARGET", mobj->tracer->x, - mobj->tracer->y, mobj->tracer->floorz, SPLATDRAWMODE_SHADE); -#endif - break; - case MT_SPINDUST: // Spindash dust - mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 - mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same - //mobj->momz = mobj->momz+P_MobjFlip(mobj)/3; // no meaningful change in value to be frank - if (mobj->state >= &states[S_SPINDUST_BUBBLE1] && mobj->state <= &states[S_SPINDUST_BUBBLE4]) // bubble dust! + case MT_SPINFIRE: + if (mobj->flags & MF_NOGRAVITY) { - P_MobjCheckWater(mobj); - if (mobj->watertop != mobj->subsector->sector->floorheight - 1000*FRACUNIT - && mobj->z+mobj->height >= mobj->watertop - 5*FRACUNIT) - mobj->flags2 |= MF2_DONTDRAW; + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->ceilingz - mobj->height; + else + mobj->z = mobj->floorz; } - break; - case MT_SPINFIRE: - if (mobj->flags & MF_NOGRAVITY) - { - if (mobj->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->ceilingz - mobj->height; - else - mobj->z = mobj->floorz; - } - /* FALLTHRU */ - default: - // check mobj against possible water content, before movement code - P_MobjCheckWater(mobj); + /* FALLTHRU */ + default: + // check mobj against possible water content, before movement code + P_MobjCheckWater(mobj); - // Extinguish fire objects in water - if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL - && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) - { - P_KillMobj(mobj, NULL, NULL, 0); - return; - } - break; + // Extinguish fire objects in water + if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL + && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) + { + P_KillMobj(mobj, NULL, NULL, 0); + return; + } + break; + } } if (P_MobjWasRemoved(mobj)) return; diff --git a/src/r_things.c b/src/r_things.c index fad47d26b..b0cb3ab8e 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -717,7 +717,7 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; - if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" + if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" { // translate certain pixels to white colfunc = transcolfunc; From 94c7d9bc52c19e5f7595b99166711ba18fe57330 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 3 May 2018 00:00:22 +0100 Subject: [PATCH 111/212] Forgot to do this before making the previous commit; completes support for no-points drone badniks. --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 027a5f48d..a6c89a760 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8347,7 +8347,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->height = info->height; mobj->flags = info->flags; - mobj->health = info->spawnhealth; + mobj->health = (info->spawnhealth ? info->spawnhealth : 1); mobj->reactiontime = info->reactiontime; From 8f71e93ceec2fb394c25095fdcd51277d5250ec6 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 3 May 2018 14:04:29 +0100 Subject: [PATCH 112/212] * Remove Commander-specific hack, incorporate into A_CrawlaCommanderThink. * Make my changes to its thinker slightly more consistent. --- src/p_enemy.c | 47 ++++++++++++++++++++++++++++++++++++----------- src/p_inter.c | 12 ------------ 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 8ef75ff93..303dbc3bd 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4994,6 +4994,7 @@ void A_CrawlaCommanderThink(mobj_t *actor) fixed_t thefloor; INT32 locvar1 = var1; INT32 locvar2 = var2; + boolean hovermode = (actor->health > 1 || actor->fuse); #ifdef HAVE_BLUA if (LUA_CallAction("A_CrawlaCommanderThink", actor)) return; @@ -5005,6 +5006,17 @@ void A_CrawlaCommanderThink(mobj_t *actor) else thefloor = actor->floorz; + if (!actor->fuse && actor->flags2 & MF2_FRET) + { + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); + + actor->fuse = TICRATE/2; + actor->momz = 0; + + P_InstaThrust(actor, actor->angle-ANGLE_180, FixedMul(5*FRACUNIT, actor->scale)); + } + if (actor->reactiontime > 0) actor->reactiontime--; @@ -5015,7 +5027,7 @@ void A_CrawlaCommanderThink(mobj_t *actor) } // Hover mode - if (actor->health > 1 || actor->fuse) + if (hovermode) { if (actor->z < thefloor + FixedMul(16*FRACUNIT, actor->scale)) actor->momz += FixedMul(FRACUNIT, actor->scale); @@ -5025,7 +5037,7 @@ void A_CrawlaCommanderThink(mobj_t *actor) actor->momz += FixedMul(16, actor->scale); } - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + if (!actor->target) { // look for a new target if (P_LookForPlayers(actor, true, false, 0)) @@ -5038,9 +5050,9 @@ void A_CrawlaCommanderThink(mobj_t *actor) dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y); - if (actor->target->player) + if (actor->target->player && (!hovermode || actor->reactiontime <= 2*TICRATE)) { - if (dist < FixedMul(64<<(FRACBITS+(actor->health == 1 ? 0 : 1)), actor->scale) + if (dist < FixedMul(64<<(FRACBITS+(hovermode ? 1 : 0)), actor->scale) && ((actor->target->player->pflags & PF_JUMPED) || (actor->target->player->pflags & PF_SPINNING))) { // Auugh! She's trying to kill you! Strafe! STRAAAAFFEEE!! @@ -5069,36 +5081,49 @@ void A_CrawlaCommanderThink(mobj_t *actor) actor->angle += (P_RandomByte()<<10); actor->angle -= (P_RandomByte()<<10); - if (actor->health > 1) + if (hovermode) + { + fixed_t mom; P_Thrust(actor, actor->angle, 2*actor->scale); + mom = P_AproxDistance(actor->momx, actor->momy); + if (mom > 20*actor->scale) + { + mom += 20*actor->scale; + mom >>= 1; + P_InstaThrust(actor, R_PointToAngle2(0, 0, actor->momx, actor->momy), mom); + } + } } else if (!actor->reactiontime) { - if (actor->health > 1) // Hover Mode + if (hovermode && !(actor->flags2 & MF2_FRET)) // Hover Mode { if (dist < FixedMul(512*FRACUNIT, actor->scale)) { actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_InstaThrust(actor, actor->angle, FixedMul(30*FRACUNIT, actor->scale)); + P_InstaThrust(actor, actor->angle, FixedMul(40*FRACUNIT, actor->scale)); actor->threshold = 1; - S_StartSound(actor, actor->info->attacksound); + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); } } - actor->reactiontime = 2*TICRATE + P_RandomByte()/2; + actor->reactiontime = 3*TICRATE + (P_RandomByte()>>2); } if (actor->health == 1) P_Thrust(actor, actor->angle, 1); // Pogo Mode - if (!actor->fuse && actor->health == 1 && actor->z <= actor->floorz) + if (!hovermode && actor->z <= actor->floorz) { + if (actor->info->activesound) + S_StartSound(actor, actor->info->activesound); + if (dist < FixedMul(256*FRACUNIT, actor->scale)) { actor->momz = FixedMul(locvar2, actor->scale); actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); P_InstaThrust(actor, actor->angle, FixedMul(locvar2/8, actor->scale)); - S_StartSound(actor, actor->info->activesound); // pogo on player } else diff --git a/src/p_inter.c b/src/p_inter.c index c4f05963c..d437d494d 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3281,18 +3281,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da else switch (target->type) { - case MT_CRAWLACOMMANDER: - if (target->info->painsound) - S_StartSound(target, target->info->painsound); - - target->fuse = TICRATE/2; - target->momz = 0; - - P_InstaThrust(target, target->angle-ANGLE_180, FixedMul(5*FRACUNIT, target->scale)); - - P_SetMobjState(target, target->info->painstate); - - break; case MT_EGGMOBILE2: // egg slimer if (target->health < target->info->damage) // in pinch phase { From d0575f7fb05ed6a0799b706606c561caa0e64e84 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 4 May 2018 21:30:15 +0100 Subject: [PATCH 113/212] * Hive Elementals and Bumblebores, plus associated useful action functions. * Made Facestabbers take two hits and have associated pain/death animations. No other changes, just wanted to make sure THIS was done. * Move Bubblebuzz-related stuff to go alongside the secret badniks and etc. * MF2_INVERTAIMABLE. Inverts whether P_LookForEnemies can get at; replaces a hardcoded thingy. --- src/dehacked.c | 459 +++++++++++++++++++++------------------- src/hardware/hw_light.c | 20 +- src/info.c | 226 +++++++++++++------- src/info.h | 62 ++++-- src/p_enemy.c | 120 ++++++++++- src/p_inter.c | 22 +- src/p_mobj.c | 56 ++++- src/p_mobj.h | 4 +- src/p_user.c | 4 +- src/sounds.c | 4 +- 10 files changed, 640 insertions(+), 337 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index e3aee6654..b6bd59501 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1618,206 +1618,209 @@ typedef struct */ static actionpointer_t actionpointers[] = { - {{A_Explode}, "A_EXPLODE"}, - {{A_Pain}, "A_PAIN"}, - {{A_Fall}, "A_FALL"}, - {{A_MonitorPop}, "A_MONITORPOP"}, - {{A_GoldMonitorPop}, "A_GOLDMONITORPOP"}, - {{A_GoldMonitorRestore}, "A_GOLDMONITORRESTORE"}, - {{A_GoldMonitorSparkle}, "A_GOLDMONITORSPARKLE"}, - {{A_Look}, "A_LOOK"}, - {{A_Chase}, "A_CHASE"}, - {{A_FaceStabChase}, "A_FACESTABCHASE"}, - {{A_FaceTarget}, "A_FACETARGET"}, - {{A_FaceTracer}, "A_FACETRACER"}, - {{A_Scream}, "A_SCREAM"}, - {{A_BossDeath}, "A_BOSSDEATH"}, - {{A_CustomPower}, "A_CUSTOMPOWER"}, - {{A_GiveWeapon}, "A_GIVEWEAPON"}, - {{A_RingBox}, "A_RINGBOX"}, - {{A_Invincibility}, "A_INVINCIBILITY"}, - {{A_SuperSneakers}, "A_SUPERSNEAKERS"}, - {{A_BunnyHop}, "A_BUNNYHOP"}, - {{A_BubbleSpawn}, "A_BUBBLESPAWN"}, - {{A_FanBubbleSpawn}, "A_FANBUBBLESPAWN"}, - {{A_BubbleRise}, "A_BUBBLERISE"}, - {{A_BubbleCheck}, "A_BUBBLECHECK"}, - {{A_AwardScore}, "A_AWARDSCORE"}, - {{A_ExtraLife}, "A_EXTRALIFE"}, - {{A_GiveShield}, "A_GIVESHIELD"}, - {{A_GravityBox}, "A_GRAVITYBOX"}, - {{A_ScoreRise}, "A_SCORERISE"}, - {{A_ParticleSpawn}, "A_PARTICLESPAWN"}, - {{A_AttractChase}, "A_ATTRACTCHASE"}, - {{A_DropMine}, "A_DROPMINE"}, - {{A_FishJump}, "A_FISHJUMP"}, - {{A_ThrownRing}, "A_THROWNRING"}, - {{A_SetSolidSteam}, "A_SETSOLIDSTEAM"}, - {{A_UnsetSolidSteam}, "A_UNSETSOLIDSTEAM"}, - {{A_SignPlayer}, "A_SIGNPLAYER"}, - {{A_OverlayThink}, "A_OVERLAYTHINK"}, - {{A_JetChase}, "A_JETCHASE"}, - {{A_JetbThink}, "A_JETBTHINK"}, - {{A_JetgThink}, "A_JETGTHINK"}, - {{A_JetgShoot}, "A_JETGSHOOT"}, - {{A_ShootBullet}, "A_SHOOTBULLET"}, - {{A_MinusDigging}, "A_MINUSDIGGING"}, - {{A_MinusPopup}, "A_MINUSPOPUP"}, - {{A_MinusCheck}, "A_MINUSCHECK"}, - {{A_ChickenCheck}, "A_CHICKENCHECK"}, - {{A_MouseThink}, "A_MOUSETHINK"}, - {{A_DetonChase}, "A_DETONCHASE"}, - {{A_CapeChase}, "A_CAPECHASE"}, - {{A_RotateSpikeBall}, "A_ROTATESPIKEBALL"}, - {{A_SlingAppear}, "A_SLINGAPPEAR"}, - {{A_UnidusBall}, "A_UNIDUSBALL"}, - {{A_RockSpawn}, "A_ROCKSPAWN"}, - {{A_SetFuse}, "A_SETFUSE"}, - {{A_CrawlaCommanderThink}, "A_CRAWLACOMMANDERTHINK"}, - {{A_SmokeTrailer}, "A_SMOKETRAILER"}, - {{A_RingExplode}, "A_RINGEXPLODE"}, - {{A_OldRingExplode}, "A_OLDRINGEXPLODE"}, - {{A_MixUp}, "A_MIXUP"}, - {{A_RecyclePowers}, "A_RECYCLEPOWERS"}, - {{A_Boss1Chase}, "A_BOSS1CHASE"}, - {{A_FocusTarget}, "A_FOCUSTARGET"}, - {{A_Boss2Chase}, "A_BOSS2CHASE"}, - {{A_Boss2Pogo}, "A_BOSS2POGO"}, - {{A_BossZoom}, "A_BOSSZOOM"}, - {{A_BossScream}, "A_BOSSSCREAM"}, - {{A_Boss2TakeDamage}, "A_BOSS2TAKEDAMAGE"}, - {{A_Boss7Chase}, "A_BOSS7CHASE"}, - {{A_GoopSplat}, "A_GOOPSPLAT"}, - {{A_Boss2PogoSFX}, "A_BOSS2POGOSFX"}, - {{A_Boss2PogoTarget}, "A_BOSS2POGOTARGET"}, - {{A_BossJetFume}, "A_BOSSJETFUME"}, - {{A_EggmanBox}, "A_EGGMANBOX"}, - {{A_TurretFire}, "A_TURRETFIRE"}, - {{A_SuperTurretFire}, "A_SUPERTURRETFIRE"}, - {{A_TurretStop}, "A_TURRETSTOP"}, - {{A_JetJawRoam}, "A_JETJAWROAM"}, - {{A_JetJawChomp}, "A_JETJAWCHOMP"}, - {{A_PointyThink}, "A_POINTYTHINK"}, - {{A_CheckBuddy}, "A_CHECKBUDDY"}, - {{A_HoodThink}, "A_HOODTHINK"}, - {{A_ArrowCheck}, "A_ARROWCHECK"}, - {{A_SnailerThink}, "A_SNAILERTHINK"}, - {{A_SharpChase}, "A_SHARPCHASE"}, - {{A_SharpSpin}, "A_SHARPSPIN"}, - {{A_VultureVtol}, "A_VULTUREVTOL"}, - {{A_VultureCheck}, "A_VULTURECHECK"}, - {{A_SkimChase}, "A_SKIMCHASE"}, - {{A_1upThinker}, "A_1UPTHINKER"}, - {{A_SkullAttack}, "A_SKULLATTACK"}, - {{A_LobShot}, "A_LOBSHOT"}, - {{A_FireShot}, "A_FIRESHOT"}, - {{A_SuperFireShot}, "A_SUPERFIRESHOT"}, - {{A_BossFireShot}, "A_BOSSFIRESHOT"}, - {{A_Boss7FireMissiles}, "A_BOSS7FIREMISSILES"}, - {{A_Boss1Laser}, "A_BOSS1LASER"}, - {{A_Boss4Reverse}, "A_BOSS4REVERSE"}, - {{A_Boss4SpeedUp}, "A_BOSS4SPEEDUP"}, - {{A_Boss4Raise}, "A_BOSS4RAISE"}, - {{A_SparkFollow}, "A_SPARKFOLLOW"}, - {{A_BuzzFly}, "A_BUZZFLY"}, - {{A_GuardChase}, "A_GUARDCHASE"}, - {{A_EggShield}, "A_EGGSHIELD"}, - {{A_SetReactionTime}, "A_SETREACTIONTIME"}, - {{A_Boss1Spikeballs}, "A_BOSS1SPIKEBALLS"}, - {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, - {{A_Boss3Path}, "A_BOSS3PATH"}, - {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, - {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, - {{A_PlayAttackSound}, "A_PLAYATTACKSOUND"}, - {{A_PlayActiveSound}, "A_PLAYACTIVESOUND"}, - {{A_SpawnObjectAbsolute}, "A_SPAWNOBJECTABSOLUTE"}, - {{A_SpawnObjectRelative}, "A_SPAWNOBJECTRELATIVE"}, - {{A_ChangeAngleRelative}, "A_CHANGEANGLERELATIVE"}, - {{A_ChangeAngleAbsolute}, "A_CHANGEANGLEABSOLUTE"}, - {{A_PlaySound}, "A_PLAYSOUND"}, - {{A_FindTarget}, "A_FINDTARGET"}, - {{A_FindTracer}, "A_FINDTRACER"}, - {{A_SetTics}, "A_SETTICS"}, - {{A_SetRandomTics}, "A_SETRANDOMTICS"}, - {{A_ChangeColorRelative}, "A_CHANGECOLORRELATIVE"}, - {{A_ChangeColorAbsolute}, "A_CHANGECOLORABSOLUTE"}, - {{A_MoveRelative}, "A_MOVERELATIVE"}, - {{A_MoveAbsolute}, "A_MOVEABSOLUTE"}, - {{A_Thrust}, "A_THRUST"}, - {{A_ZThrust}, "A_ZTHRUST"}, - {{A_SetTargetsTarget}, "A_SETTARGETSTARGET"}, - {{A_SetObjectFlags}, "A_SETOBJECTFLAGS"}, - {{A_SetObjectFlags2}, "A_SETOBJECTFLAGS2"}, - {{A_RandomState}, "A_RANDOMSTATE"}, - {{A_RandomStateRange}, "A_RANDOMSTATERANGE"}, - {{A_DualAction}, "A_DUALACTION"}, - {{A_RemoteAction}, "A_REMOTEACTION"}, - {{A_ToggleFlameJet}, "A_TOGGLEFLAMEJET"}, - {{A_OrbitNights}, "A_ORBITNIGHTS"}, - {{A_GhostMe}, "A_GHOSTME"}, - {{A_SetObjectState}, "A_SETOBJECTSTATE"}, - {{A_SetObjectTypeState}, "A_SETOBJECTTYPESTATE"}, - {{A_KnockBack}, "A_KNOCKBACK"}, - {{A_PushAway}, "A_PUSHAWAY"}, - {{A_RingDrain}, "A_RINGDRAIN"}, - {{A_SplitShot}, "A_SPLITSHOT"}, - {{A_MissileSplit}, "A_MISSILESPLIT"}, - {{A_MultiShot}, "A_MULTISHOT"}, - {{A_InstaLoop}, "A_INSTALOOP"}, - {{A_Custom3DRotate}, "A_CUSTOM3DROTATE"}, - {{A_SearchForPlayers}, "A_SEARCHFORPLAYERS"}, - {{A_CheckRandom}, "A_CHECKRANDOM"}, - {{A_CheckTargetRings}, "A_CHECKTARGETRINGS"}, - {{A_CheckRings}, "A_CHECKRINGS"}, - {{A_CheckTotalRings}, "A_CHECKTOTALRINGS"}, - {{A_CheckHealth}, "A_CHECKHEALTH"}, - {{A_CheckRange}, "A_CHECKRANGE"}, - {{A_CheckHeight}, "A_CHECKHEIGHT"}, - {{A_CheckTrueRange}, "A_CHECKTRUERANGE"}, - {{A_CheckThingCount}, "A_CHECKTHINGCOUNT"}, - {{A_CheckAmbush}, "A_CHECKAMBUSH"}, - {{A_CheckCustomValue}, "A_CHECKCUSTOMVALUE"}, - {{A_CheckCusValMemo}, "A_CHECKCUSVALMEMO"}, - {{A_SetCustomValue}, "A_SETCUSTOMVALUE"}, - {{A_UseCusValMemo}, "A_USECUSVALMEMO"}, - {{A_RelayCustomValue}, "A_RELAYCUSTOMVALUE"}, - {{A_CusValAction}, "A_CUSVALACTION"}, - {{A_ForceStop}, "A_FORCESTOP"}, - {{A_ForceWin}, "A_FORCEWIN"}, - {{A_SpikeRetract}, "A_SPIKERETRACT"}, - {{A_InfoState}, "A_INFOSTATE"}, - {{A_Repeat}, "A_REPEAT"}, - {{A_SetScale}, "A_SETSCALE"}, - {{A_RemoteDamage}, "A_REMOTEDAMAGE"}, - {{A_HomingChase}, "A_HOMINGCHASE"}, - {{A_TrapShot}, "A_TRAPSHOT"}, - {{A_VileTarget}, "A_VILETARGET"}, - {{A_VileAttack}, "A_VILEATTACK"}, - {{A_VileFire}, "A_VILEFIRE"}, - {{A_BrakChase}, "A_BRAKCHASE"}, - {{A_BrakFireShot}, "A_BRAKFIRESHOT"}, - {{A_BrakLobShot}, "A_BRAKLOBSHOT"}, - {{A_NapalmScatter}, "A_NAPALMSCATTER"}, - {{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"}, - {{A_FlickySpawn}, "A_FLICKYSPAWN"}, - {{A_FlickyAim}, "A_FLICKYAIM"}, - {{A_FlickyFly}, "A_FLICKYFLY"}, - {{A_FlickySoar}, "A_FLICKYSOAR"}, - {{A_FlickyCoast}, "A_FLICKYCOAST"}, - {{A_FlickyHop}, "A_FLICKYHOP"}, - {{A_FlickyFlounder}, "A_FLICKYFLOUNDER"}, - {{A_FlickyCheck}, "A_FLICKYCHECK"}, - {{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"}, - {{A_FlickyFlutter}, "A_FLICKYFLUTTER"}, - {{A_FlameParticle}, "A_FLAMEPARTICLE"}, - {{A_FadeOverlay}, "A_FADEOVERLAY"}, - {{A_Boss5Jump}, "A_BOSS5JUMP"}, - {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, - {{A_MineExplode}, "A_MINEEXPLODE"}, - {{A_MineRange}, "A_MINERANGE"}, - {{A_ConnectToGround}, "A_CONNECTTOGROUND"}, - {{A_SpawnParticleRelative},"A_SPAWNPARTICLERELATIVE"}, - {{A_MultiShotDist}, "A_MULTISHOTDIST"}, + {{A_Explode}, "A_EXPLODE"}, + {{A_Pain}, "A_PAIN"}, + {{A_Fall}, "A_FALL"}, + {{A_MonitorPop}, "A_MONITORPOP"}, + {{A_GoldMonitorPop}, "A_GOLDMONITORPOP"}, + {{A_GoldMonitorRestore}, "A_GOLDMONITORRESTORE"}, + {{A_GoldMonitorSparkle}, "A_GOLDMONITORSPARKLE"}, + {{A_Look}, "A_LOOK"}, + {{A_Chase}, "A_CHASE"}, + {{A_FaceStabChase}, "A_FACESTABCHASE"}, + {{A_FaceTarget}, "A_FACETARGET"}, + {{A_FaceTracer}, "A_FACETRACER"}, + {{A_Scream}, "A_SCREAM"}, + {{A_BossDeath}, "A_BOSSDEATH"}, + {{A_CustomPower}, "A_CUSTOMPOWER"}, + {{A_GiveWeapon}, "A_GIVEWEAPON"}, + {{A_RingBox}, "A_RINGBOX"}, + {{A_Invincibility}, "A_INVINCIBILITY"}, + {{A_SuperSneakers}, "A_SUPERSNEAKERS"}, + {{A_BunnyHop}, "A_BUNNYHOP"}, + {{A_BubbleSpawn}, "A_BUBBLESPAWN"}, + {{A_FanBubbleSpawn}, "A_FANBUBBLESPAWN"}, + {{A_BubbleRise}, "A_BUBBLERISE"}, + {{A_BubbleCheck}, "A_BUBBLECHECK"}, + {{A_AwardScore}, "A_AWARDSCORE"}, + {{A_ExtraLife}, "A_EXTRALIFE"}, + {{A_GiveShield}, "A_GIVESHIELD"}, + {{A_GravityBox}, "A_GRAVITYBOX"}, + {{A_ScoreRise}, "A_SCORERISE"}, + {{A_ParticleSpawn}, "A_PARTICLESPAWN"}, + {{A_AttractChase}, "A_ATTRACTCHASE"}, + {{A_DropMine}, "A_DROPMINE"}, + {{A_FishJump}, "A_FISHJUMP"}, + {{A_ThrownRing}, "A_THROWNRING"}, + {{A_SetSolidSteam}, "A_SETSOLIDSTEAM"}, + {{A_UnsetSolidSteam}, "A_UNSETSOLIDSTEAM"}, + {{A_SignPlayer}, "A_SIGNPLAYER"}, + {{A_OverlayThink}, "A_OVERLAYTHINK"}, + {{A_JetChase}, "A_JETCHASE"}, + {{A_JetbThink}, "A_JETBTHINK"}, + {{A_JetgThink}, "A_JETGTHINK"}, + {{A_JetgShoot}, "A_JETGSHOOT"}, + {{A_ShootBullet}, "A_SHOOTBULLET"}, + {{A_MinusDigging}, "A_MINUSDIGGING"}, + {{A_MinusPopup}, "A_MINUSPOPUP"}, + {{A_MinusCheck}, "A_MINUSCHECK"}, + {{A_ChickenCheck}, "A_CHICKENCHECK"}, + {{A_MouseThink}, "A_MOUSETHINK"}, + {{A_DetonChase}, "A_DETONCHASE"}, + {{A_CapeChase}, "A_CAPECHASE"}, + {{A_RotateSpikeBall}, "A_ROTATESPIKEBALL"}, + {{A_SlingAppear}, "A_SLINGAPPEAR"}, + {{A_UnidusBall}, "A_UNIDUSBALL"}, + {{A_RockSpawn}, "A_ROCKSPAWN"}, + {{A_SetFuse}, "A_SETFUSE"}, + {{A_CrawlaCommanderThink}, "A_CRAWLACOMMANDERTHINK"}, + {{A_SmokeTrailer}, "A_SMOKETRAILER"}, + {{A_RingExplode}, "A_RINGEXPLODE"}, + {{A_OldRingExplode}, "A_OLDRINGEXPLODE"}, + {{A_MixUp}, "A_MIXUP"}, + {{A_RecyclePowers}, "A_RECYCLEPOWERS"}, + {{A_Boss1Chase}, "A_BOSS1CHASE"}, + {{A_FocusTarget}, "A_FOCUSTARGET"}, + {{A_Boss2Chase}, "A_BOSS2CHASE"}, + {{A_Boss2Pogo}, "A_BOSS2POGO"}, + {{A_BossZoom}, "A_BOSSZOOM"}, + {{A_BossScream}, "A_BOSSSCREAM"}, + {{A_Boss2TakeDamage}, "A_BOSS2TAKEDAMAGE"}, + {{A_Boss7Chase}, "A_BOSS7CHASE"}, + {{A_GoopSplat}, "A_GOOPSPLAT"}, + {{A_Boss2PogoSFX}, "A_BOSS2POGOSFX"}, + {{A_Boss2PogoTarget}, "A_BOSS2POGOTARGET"}, + {{A_BossJetFume}, "A_BOSSJETFUME"}, + {{A_EggmanBox}, "A_EGGMANBOX"}, + {{A_TurretFire}, "A_TURRETFIRE"}, + {{A_SuperTurretFire}, "A_SUPERTURRETFIRE"}, + {{A_TurretStop}, "A_TURRETSTOP"}, + {{A_JetJawRoam}, "A_JETJAWROAM"}, + {{A_JetJawChomp}, "A_JETJAWCHOMP"}, + {{A_PointyThink}, "A_POINTYTHINK"}, + {{A_CheckBuddy}, "A_CHECKBUDDY"}, + {{A_HoodThink}, "A_HOODTHINK"}, + {{A_ArrowCheck}, "A_ARROWCHECK"}, + {{A_SnailerThink}, "A_SNAILERTHINK"}, + {{A_SharpChase}, "A_SHARPCHASE"}, + {{A_SharpSpin}, "A_SHARPSPIN"}, + {{A_VultureVtol}, "A_VULTUREVTOL"}, + {{A_VultureCheck}, "A_VULTURECHECK"}, + {{A_SkimChase}, "A_SKIMCHASE"}, + {{A_1upThinker}, "A_1UPTHINKER"}, + {{A_SkullAttack}, "A_SKULLATTACK"}, + {{A_LobShot}, "A_LOBSHOT"}, + {{A_FireShot}, "A_FIRESHOT"}, + {{A_SuperFireShot}, "A_SUPERFIRESHOT"}, + {{A_BossFireShot}, "A_BOSSFIRESHOT"}, + {{A_Boss7FireMissiles}, "A_BOSS7FIREMISSILES"}, + {{A_Boss1Laser}, "A_BOSS1LASER"}, + {{A_Boss4Reverse}, "A_BOSS4REVERSE"}, + {{A_Boss4SpeedUp}, "A_BOSS4SPEEDUP"}, + {{A_Boss4Raise}, "A_BOSS4RAISE"}, + {{A_SparkFollow}, "A_SPARKFOLLOW"}, + {{A_BuzzFly}, "A_BUZZFLY"}, + {{A_GuardChase}, "A_GUARDCHASE"}, + {{A_EggShield}, "A_EGGSHIELD"}, + {{A_SetReactionTime}, "A_SETREACTIONTIME"}, + {{A_Boss1Spikeballs}, "A_BOSS1SPIKEBALLS"}, + {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, + {{A_Boss3Path}, "A_BOSS3PATH"}, + {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, + {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, + {{A_PlayAttackSound}, "A_PLAYATTACKSOUND"}, + {{A_PlayActiveSound}, "A_PLAYACTIVESOUND"}, + {{A_SpawnObjectAbsolute}, "A_SPAWNOBJECTABSOLUTE"}, + {{A_SpawnObjectRelative}, "A_SPAWNOBJECTRELATIVE"}, + {{A_ChangeAngleRelative}, "A_CHANGEANGLERELATIVE"}, + {{A_ChangeAngleAbsolute}, "A_CHANGEANGLEABSOLUTE"}, + {{A_PlaySound}, "A_PLAYSOUND"}, + {{A_FindTarget}, "A_FINDTARGET"}, + {{A_FindTracer}, "A_FINDTRACER"}, + {{A_SetTics}, "A_SETTICS"}, + {{A_SetRandomTics}, "A_SETRANDOMTICS"}, + {{A_ChangeColorRelative}, "A_CHANGECOLORRELATIVE"}, + {{A_ChangeColorAbsolute}, "A_CHANGECOLORABSOLUTE"}, + {{A_MoveRelative}, "A_MOVERELATIVE"}, + {{A_MoveAbsolute}, "A_MOVEABSOLUTE"}, + {{A_Thrust}, "A_THRUST"}, + {{A_ZThrust}, "A_ZTHRUST"}, + {{A_SetTargetsTarget}, "A_SETTARGETSTARGET"}, + {{A_SetObjectFlags}, "A_SETOBJECTFLAGS"}, + {{A_SetObjectFlags2}, "A_SETOBJECTFLAGS2"}, + {{A_RandomState}, "A_RANDOMSTATE"}, + {{A_RandomStateRange}, "A_RANDOMSTATERANGE"}, + {{A_DualAction}, "A_DUALACTION"}, + {{A_RemoteAction}, "A_REMOTEACTION"}, + {{A_ToggleFlameJet}, "A_TOGGLEFLAMEJET"}, + {{A_OrbitNights}, "A_ORBITNIGHTS"}, + {{A_GhostMe}, "A_GHOSTME"}, + {{A_SetObjectState}, "A_SETOBJECTSTATE"}, + {{A_SetObjectTypeState}, "A_SETOBJECTTYPESTATE"}, + {{A_KnockBack}, "A_KNOCKBACK"}, + {{A_PushAway}, "A_PUSHAWAY"}, + {{A_RingDrain}, "A_RINGDRAIN"}, + {{A_SplitShot}, "A_SPLITSHOT"}, + {{A_MissileSplit}, "A_MISSILESPLIT"}, + {{A_MultiShot}, "A_MULTISHOT"}, + {{A_InstaLoop}, "A_INSTALOOP"}, + {{A_Custom3DRotate}, "A_CUSTOM3DROTATE"}, + {{A_SearchForPlayers}, "A_SEARCHFORPLAYERS"}, + {{A_CheckRandom}, "A_CHECKRANDOM"}, + {{A_CheckTargetRings}, "A_CHECKTARGETRINGS"}, + {{A_CheckRings}, "A_CHECKRINGS"}, + {{A_CheckTotalRings}, "A_CHECKTOTALRINGS"}, + {{A_CheckHealth}, "A_CHECKHEALTH"}, + {{A_CheckRange}, "A_CHECKRANGE"}, + {{A_CheckHeight}, "A_CHECKHEIGHT"}, + {{A_CheckTrueRange}, "A_CHECKTRUERANGE"}, + {{A_CheckThingCount}, "A_CHECKTHINGCOUNT"}, + {{A_CheckAmbush}, "A_CHECKAMBUSH"}, + {{A_CheckCustomValue}, "A_CHECKCUSTOMVALUE"}, + {{A_CheckCusValMemo}, "A_CHECKCUSVALMEMO"}, + {{A_SetCustomValue}, "A_SETCUSTOMVALUE"}, + {{A_UseCusValMemo}, "A_USECUSVALMEMO"}, + {{A_RelayCustomValue}, "A_RELAYCUSTOMVALUE"}, + {{A_CusValAction}, "A_CUSVALACTION"}, + {{A_ForceStop}, "A_FORCESTOP"}, + {{A_ForceWin}, "A_FORCEWIN"}, + {{A_SpikeRetract}, "A_SPIKERETRACT"}, + {{A_InfoState}, "A_INFOSTATE"}, + {{A_Repeat}, "A_REPEAT"}, + {{A_SetScale}, "A_SETSCALE"}, + {{A_RemoteDamage}, "A_REMOTEDAMAGE"}, + {{A_HomingChase}, "A_HOMINGCHASE"}, + {{A_TrapShot}, "A_TRAPSHOT"}, + {{A_VileTarget}, "A_VILETARGET"}, + {{A_VileAttack}, "A_VILEATTACK"}, + {{A_VileFire}, "A_VILEFIRE"}, + {{A_BrakChase}, "A_BRAKCHASE"}, + {{A_BrakFireShot}, "A_BRAKFIRESHOT"}, + {{A_BrakLobShot}, "A_BRAKLOBSHOT"}, + {{A_NapalmScatter}, "A_NAPALMSCATTER"}, + {{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"}, + {{A_FlickySpawn}, "A_FLICKYSPAWN"}, + {{A_FlickyAim}, "A_FLICKYAIM"}, + {{A_FlickyFly}, "A_FLICKYFLY"}, + {{A_FlickySoar}, "A_FLICKYSOAR"}, + {{A_FlickyCoast}, "A_FLICKYCOAST"}, + {{A_FlickyHop}, "A_FLICKYHOP"}, + {{A_FlickyFlounder}, "A_FLICKYFLOUNDER"}, + {{A_FlickyCheck}, "A_FLICKYCHECK"}, + {{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"}, + {{A_FlickyFlutter}, "A_FLICKYFLUTTER"}, + {{A_FlameParticle}, "A_FLAMEPARTICLE"}, + {{A_FadeOverlay}, "A_FADEOVERLAY"}, + {{A_Boss5Jump}, "A_BOSS5JUMP"}, + {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, + {{A_MineExplode}, "A_MINEEXPLODE"}, + {{A_MineRange}, "A_MINERANGE"}, + {{A_ConnectToGround}, "A_CONNECTTOGROUND"}, + {{A_SpawnParticleRelative}, "A_SPAWNPARTICLERELATIVE"}, + {{A_MultiShotDist}, "A_MULTISHOTDIST"}, + {{A_WhoCaresIfYourSonIsABee},"A_WHOCARESIFYOURSONISABEE"}, + {{A_ParentTriesToSleep}, "A_PARENTTRIESTOSLEEP"}, + {{A_CryingToMomma}, "A_CRYINGTOMOMMA"}, {{NULL}, "NONE"}, @@ -3585,10 +3588,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_RBUZZFLY1", "S_RBUZZFLY2", - // AquaBuzz - "S_BBUZZFLY1", - "S_BBUZZFLY2", - // Jetty-Syn Bomber "S_JETBLOOK1", "S_JETBLOOK2", @@ -3740,6 +3739,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FACESTABBER_CHARGE2", "S_FACESTABBER_CHARGE3", "S_FACESTABBER_CHARGE4", + "S_FACESTABBER_PAIN", + "S_FACESTABBER_DIE1", + "S_FACESTABBER_DIE2", + "S_FACESTABBER_DIE3", // Egg Guard "S_EGGGUARD_STND", @@ -5967,6 +5970,32 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_NIGHTOPIANHELPER9", // Secret badniks and hazards, shhhh + "S_HIVEELEMENTAL_LOOK", + "S_HIVEELEMENTAL_PREPARE1", + "S_HIVEELEMENTAL_PREPARE2", + "S_HIVEELEMENTAL_SHOOT1", + "S_HIVEELEMENTAL_SHOOT2", + "S_HIVEELEMENTAL_DORMANT", + "S_HIVEELEMENTAL_PAIN", + "S_HIVEELEMENTAL_DIE1", + "S_HIVEELEMENTAL_DIE2", + "S_HIVEELEMENTAL_DIE3", + + "S_BUMBLEBORE_SPAWN", + "S_BUMBLEBORE_LOOK1", + "S_BUMBLEBORE_LOOK2", + "S_BUMBLEBORE_FLY1", + "S_BUMBLEBORE_FLY2", + "S_BUMBLEBORE_RAISE", + "S_BUMBLEBORE_FALL1", + "S_BUMBLEBORE_FALL2", + "S_BUMBLEBORE_STUCK1", + "S_BUMBLEBORE_STUCK2", + "S_BUMBLEBORE_DIE", + + "S_BBUZZFLY1", + "S_BBUZZFLY2", + "S_SMASHSPIKE_FLOAT", "S_SMASHSPIKE_EASE1", "S_SMASHSPIKE_EASE2", @@ -5976,11 +6005,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SMASHSPIKE_RISE1", "S_SMASHSPIKE_RISE2", - "S_HHZDUST1", - "S_HHZDUST2", - "S_HHZDUST3", - "S_HHZDUST4", - "S_CACO_LOOK", "S_CACO_WAKE1", "S_CACO_WAKE2", @@ -6084,6 +6108,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_WPLD5", "S_WPLD6", + "S_DUST1", + "S_DUST2", + "S_DUST3", + "S_DUST4", + "S_ROCKSPAWN", "S_ROCKCRUMBLEA", @@ -6125,7 +6154,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_GFZFISH", // Greenflower Fish "MT_GOLDBUZZ", "MT_REDBUZZ", - "MT_AQUABUZZ", "MT_JETTBOMBER", // Jetty-Syn Bomber "MT_JETTGUNNER", // Jetty-Syn Gunner "MT_CRAWLACOMMANDER", // Crawla Commander @@ -6658,8 +6686,12 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_NIGHTOPIANHELPER", // the actual helper object that orbits you // Secret badniks and hazards, shhhh + "MT_HIVEELEMENTAL", + "MT_BUMBLEBORE", + + "MT_BUBBLEBUZZ", + "MT_SMASHINGSPIKEBALL", - "MT_HHZDUST", "MT_CACOLANTERN", "MT_CACOSHARD", "MT_CACOFIRE", @@ -6688,6 +6720,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SPARK", //spark "MT_EXPLODE", // Robot Explosion "MT_UWEXPLODE", // Underwater Explosion + "MT_DUST", "MT_ROCKSPAWNER", "MT_FALLINGROCK", "MT_ROCKCRUMBLE1", @@ -6759,8 +6792,8 @@ static const char *const MOBJFLAG2_LIST[] = { "SCATTER", // Thrown ring has scatter properties "BEYONDTHEGRAVE", // Source of this missile has died and has since respawned. "SLIDEPUSH", // MF_PUSHABLE that pushes continuously. - "CLASSICPUSH", // Drops straight down when object has negative Z. - "STANDONME", // While not pushable, stand on me anyway. + "CLASSICPUSH", // Drops straight down when object has negative momz. + "INVERTAIMABLE", // Flips whether it's targetable by A_LookForEnemies (enemies no, decoys yes) "INFLOAT", // Floating to a height for a move, don't auto float to target's height. "DEBRIS", // Splash ring from explosion ring "NIGHTSPULL", // Attracted from a paraloop diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 9397eaec2..1c1f10d59 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -174,7 +174,6 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_MNUS &lspr[NOLIGHT], // SPR_SSHL &lspr[NOLIGHT], // SPR_UNID - &lspr[NOLIGHT], // SPR_BBUZ // Generic Boos Items &lspr[JETLIGHT_L], // SPR_JETF // Boss jet fumes @@ -489,14 +488,17 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_CAPS // Secret badniks and hazards, shhhh - &lspr[NOLIGHT], // SPR_FMCE", - &lspr[NOLIGHT], // SPR_HMCE", - &lspr[NOLIGHT], // SPR_CACO", - &lspr[BLUEBALL_L], // SPR_BAL2", - &lspr[NOLIGHT], // SPR_SBOB", - &lspr[BLUEBALL_L], // SPR_SBFL", - &lspr[BLUEBALL_L], // SPR_SBSK", - &lspr[NOLIGHT], // SPR_BATT", + &lspr[NOLIGHT], // SPR_HIVE + &lspr[NOLIGHT], // SPR_BUMB, + &lspr[NOLIGHT], // SPR_BBUZ + &lspr[NOLIGHT], // SPR_FMCE, + &lspr[NOLIGHT], // SPR_HMCE, + &lspr[NOLIGHT], // SPR_CACO, + &lspr[BLUEBALL_L], // SPR_BAL2, + &lspr[NOLIGHT], // SPR_SBOB, + &lspr[BLUEBALL_L], // SPR_SBFL, + &lspr[BLUEBALL_L], // SPR_SBSK, + &lspr[NOLIGHT], // SPR_BATT, // Debris &lspr[RINGSPARK_L], // SPR_SPRK diff --git a/src/info.c b/src/info.c index e568d6ae2..e744be054 100644 --- a/src/info.c +++ b/src/info.c @@ -62,7 +62,6 @@ char sprnames[NUMSPRITES + 1][5] = "MNUS", // Minus "SSHL", // Spring Shell "UNID", // Unidus - "BBUZ", // AquaBuzz, for Azure Temple // Generic Boss Items "JETF", // Boss jet fumes @@ -383,6 +382,9 @@ char sprnames[NUMSPRITES + 1][5] = "CAPS", // Capsule thingy for NiGHTS // Secret badniks and hazards, shhhh + "HIVE", + "BUMB", + "BBUZ", "FMCE", "HMCE", "CACO", @@ -807,10 +809,6 @@ state_t states[NUMSTATES] = {SPR_RBUZ, 0, 2, {A_BuzzFly}, sfx_buzz4, 0, S_RBUZZFLY2}, // S_RBUZZFLY1 {SPR_RBUZ, 1, 2, {A_BuzzFly}, 0, 0, S_RBUZZFLY1}, // S_RBUZZFLY2 - // AquaBuzz - {SPR_BBUZ, 0, 2, {NULL}, 0, 0, S_BBUZZFLY2}, // S_BBUZZFLY1 - {SPR_BBUZ, 1, 2, {NULL}, 0, 0, S_BBUZZFLY1}, // S_BBUZZFLY2 - // Jetty-Syn Bomber {SPR_JETB, 0, 4, {A_Look}, 0, 0, S_JETBLOOK2}, // S_JETBLOOK1 {SPR_JETB, 1, 4, {A_Look}, 0, 0, S_JETBLOOK1}, // S_JETBLOOK2 @@ -963,6 +961,10 @@ state_t states[NUMSTATES] = {SPR_CBFS, 6, 0, {A_PlayAttackSound}, 0, 0, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE2 {SPR_CBFS, 6, 0, {A_FaceTarget}, 0, 0, S_FACESTABBER_CHARGE4}, // S_FACESTABBER_CHARGE3 {SPR_CBFS, 7, 35, {A_Thrust}, 20, 1, S_FACESTABBER_STND1}, // S_FACESTABBER_CHARGE4 + {SPR_CBFS, 0, 35, {A_Pain}, 0, 0, S_FACESTABBER_STND1}, // S_FACESTABBER_PAIN + {SPR_CBFS, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE2}, // S_FACESTABBER_DIE1 + {SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE3}, // S_FACESTABBER_DIE2 + {SPR_NULL, 0, 0, {A_Repeat}, 7, S_FACESTABBER_DIE1, S_XPLD_FLICKY}, // S_FACESTABBER_DIE3 // Egg Guard {SPR_SPSH, 0, 1, {A_Look}, 0, 0, S_EGGGUARD_STND}, // S_EGGGUARD_STND @@ -3257,22 +3259,43 @@ state_t states[NUMSTATES] = {SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1}, // S_NIGHTOPIANHELPER9 // Secret badniks and hazards, shhhh + {SPR_HIVE, 0, 5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK + {SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1 + {SPR_HIVE, 0, 6, {A_PlaySound}, sfx_s3k8c, 1, S_HIVEELEMENTAL_SHOOT1}, // S_HIVEELEMENTAL_PREPARE2 + {SPR_HIVE, 1, 4, {A_WhoCaresIfYourSonIsABee}, (MT_BUMBLEBORE<<16)|4, (1<<16)|32, S_HIVEELEMENTAL_SHOOT2}, // S_HIVEELEMENTAL_SHOOT1 + {SPR_HIVE, 2, 2, {NULL}, 0, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_SHOOT2 + {SPR_HIVE, 0, 5, {A_ParentTriesToSleep}, S_HIVEELEMENTAL_PREPARE1, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_DORMANT + {SPR_HIVE, 3, 35, {A_Pain}, 0, 0, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_PAIN + {SPR_HIVE, 3, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_HIVEELEMENTAL_DIE2}, // S_HIVEELEMENTAL_DIE1 + {SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_HIVEELEMENTAL_DIE3}, // S_HIVEELEMENTAL_DIE2 + {SPR_NULL, 0, 0, {A_Repeat}, 7, S_HIVEELEMENTAL_DIE1, S_XPLD_FLICKY}, // S_HIVEELEMENTAL_DIE3 + + {SPR_BUMB, 1, 10, {NULL}, 0, 0, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_SPAWN + {SPR_BUMB, 0, 4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK2}, // S_BUMBLEBORE_LOOK1 + {SPR_BUMB, 1, 4, {A_Look}, 1, 1, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_LOOK2 + {SPR_BUMB, 0, 4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY2}, // S_BUMBLEBORE_FLY1 + {SPR_BUMB, 1, 4, {A_JetbThink}, 0, 0, S_BUMBLEBORE_FLY1}, // S_BUMBLEBORE_FLY2 + {SPR_BUMB, 2|FF_FULLBRIGHT, 12, {A_ZThrust}, 4, (1<<16)|1, S_BUMBLEBORE_FALL1}, // S_BUMBLEBORE_RAISE + {SPR_BUMB, 2|FF_FULLBRIGHT, 0, {A_ZThrust}, -8, (1<<16)|1, S_BUMBLEBORE_FALL2}, // S_BUMBLEBORE_FALL1 + {SPR_BUMB, 2|FF_FULLBRIGHT, 300, {NULL}, 0, 0, S_BUMBLEBORE_DIE}, // S_BUMBLEBORE_FALL2 + {SPR_BUMB, 4, 3, {A_MultiShotDist}, (MT_DUST<<16)|6, -40, S_BUMBLEBORE_STUCK2}, // S_BUMBLEBORE_STUCK1 + {SPR_BUMB, 5, 120, {NULL}, 0, 0, S_BUMBLEBORE_DIE}, // S_BUMBLEBORE_STUCK2 + {SPR_BUMB, 5, 0, {A_CryingToMomma}, 0, 0, S_XPLD1}, // S_BUMBLEBORE_DIE + + {SPR_BBUZ, 0, 2, {NULL}, 0, 0, S_BBUZZFLY2}, // S_BBUZZFLY1 + {SPR_BBUZ, 1, 2, {NULL}, 0, 0, S_BBUZZFLY1}, // S_BBUZZFLY2 + {SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1}, // S_SMASHSPIKE_FLOAT {SPR_FMCE, 0, 4, {A_ZThrust}, 4, (1<<16)|1, S_SMASHSPIKE_EASE2}, // S_SMASHSPIKE_EASE1 {SPR_FMCE, 0, 4, {A_ZThrust}, 0, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_EASE1 {SPR_FMCE, 0, 2, {A_ZThrust}, -6, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_FALL - {SPR_FMCE, 1, 2, {A_MultiShotDist}, (MT_HHZDUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1 + {SPR_FMCE, 1, 2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1 {SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1}, // S_SMASHSPIKE_STOMP2 {SPR_FMCE, 1, 2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE1 {SPR_FMCE, 0, 2, {A_ZThrust}, 6, (1<<16)|1, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE2 - {SPR_DUST, FF_TRANS40, 4, {NULL}, 0, 0, S_HHZDUST2}, // S_HHZDUST1 - {SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_HHZDUST3}, // S_HHZDUST2 - {SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_HHZDUST4}, // S_HHZDUST3 - {SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL}, // S_HHZDUST4 - {SPR_CACO, 0, 5, {A_Look}, (1100<<16)|1, 0, S_CACO_LOOK}, // S_CACO_LOOK - {SPR_CACO, 1, 0, {A_MultiShotDist}, (MT_HHZDUST<<16)|7, -48, S_CACO_WAKE2}, // S_CACO_WAKE1 + {SPR_CACO, 1, 0, {A_MultiShotDist}, (MT_DUST<<16)|7, -48, S_CACO_WAKE2}, // S_CACO_WAKE1 {SPR_CACO, 1, 10, {A_ZThrust}, 4, (1<<16)|1, S_CACO_WAKE3}, // S_CACO_WAKE2 {SPR_CACO, 2, 8, {A_ZThrust}, 2, (1<<16)|1, S_CACO_WAKE4}, // S_CACO_WAKE3 {SPR_CACO, 2, 4, {A_ZThrust}, 0, (1<<16)|1, S_CACO_ROAR}, // S_CACO_WAKE4 @@ -3319,7 +3342,7 @@ state_t states[NUMSTATES] = {SPR_SBFL, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_SPINBOBERT_FIRE_TRAIL3 {SPR_HBAT, 0, 5, {A_Look}, (900<<16)|1, 0, S_HANGSTER_LOOK}, // S_HANGSTER_LOOK - {SPR_HBAT, 1, 0, {A_MultiShotDist}, (MT_HHZDUST<<16)|10, -34, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP1 + {SPR_HBAT, 1, 0, {A_MultiShotDist}, (MT_DUST<<16)|10, -34, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP1 {SPR_HBAT, 1, 2, {A_ZThrust}, -8, (1<<16)|1, S_HANGSTER_SWOOP2}, // S_HANGSTER_SWOOP2 {SPR_HBAT, 1, 6, {A_ZThrust}, -5, (1<<16), S_HANGSTER_ARC2}, // S_HANGSTER_ARC1 {SPR_HBAT, 1, 5, {A_ZThrust}, -2, (1<<16), S_HANGSTER_ARC3}, // S_HANGSTER_ARC2 @@ -3376,6 +3399,11 @@ state_t states[NUMSTATES] = {SPR_BOM4, 4, 3, {NULL}, 0, 0, S_WPLD6}, // S_WPLD5 {SPR_BOM4, 5, 3, {NULL}, 0, 0, S_NULL}, // S_WPLD6 + {SPR_DUST, FF_TRANS40, 4, {NULL}, 0, 0, S_DUST2}, // S_DUST1 + {SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_DUST3}, // S_DUST2 + {SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4}, // S_DUST3 + {SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL}, // S_DUST4 + {SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN {SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEA}, // S_ROCKCRUMBLEA @@ -3672,33 +3700,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_AQUABUZZ - 124, // doomednum - S_BBUZZFLY1, // spawnstate - 1, // spawnhealth - S_BBUZZFLY1, // seestate - sfx_None, // seesound - 2, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - TICRATE, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_XPLD_FLICKY, // deathstate - S_NULL, // xdeathstate - sfx_pop, // deathsound - 6*FRACUNIT, // speed - 20*FRACUNIT, // radius - 24*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_gbeep, // activesound - MF_SLIDEME|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags - S_NULL // raisestate - }, - { // MT_JETTBOMBER 105, // doomednum S_JETBLOOK1, // spawnstate @@ -4080,19 +4081,19 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FACESTABBER 118, // doomednum S_FACESTABBER_STND1, // spawnstate - 1, // spawnhealth + 2, // spawnhealth S_FACESTABBER_STND1, // seestate sfx_None, // seesound 35, // reactiontime sfx_None, // attacksound - S_NULL, // painstate + S_FACESTABBER_PAIN, // painstate 0, // painchance - sfx_None, // painsound + sfx_dmpain, // painsound S_FACESTABBER_CHARGE1, // meleestate S_NULL, // missilestate - S_XPLD_FLICKY, // deathstate + S_FACESTABBER_DIE1, // deathstate S_NULL, // xdeathstate - sfx_pop, // deathsound + sfx_cybdth, // deathsound 3, // speed 32*FRACUNIT, // radius 64*FRACUNIT, // height @@ -15642,6 +15643,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_HIVEELEMENTAL + 3190, // doomednum + S_HIVEELEMENTAL_LOOK, // spawnstate + 2, // spawnhealth + S_HIVEELEMENTAL_PREPARE1, // seestate + sfx_s3k74, // seesound + 0, // reactiontime + sfx_s3k91, // attacksound + S_HIVEELEMENTAL_PAIN, // painstate + 0, // painchance + sfx_dmpain, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_HIVEELEMENTAL_DIE1, // deathstate + S_NULL, // xdeathstate + sfx_cybdth, // deathsound + 6*FRACUNIT, // speed + 30*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3k72, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY, // flags + S_NULL // raisestate + }, + + { // MT_BUMBLEBORE + 3191, // doomednum + S_BUMBLEBORE_SPAWN, // spawnstate + 0, // spawnhealth -- this is how you do drones... + S_BUMBLEBORE_FLY1, // seestate + sfx_s3k8e, // seesound + 2, // reactiontime + sfx_s3k9e, // attacksound + S_BUMBLEBORE_STUCK1, // painstate + 0, // painchance + sfx_None, // painsound + S_BUMBLEBORE_RAISE, // meleestate + S_NULL, // missilestate + S_BUMBLEBORE_DIE, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 4*FRACUNIT, // speed + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY|MF_SLIDEME, // flags + S_NULL // raisestate + }, + + { // MT_BUBBLEBUZZ + 124, // doomednum + S_BBUZZFLY1, // spawnstate + 1, // spawnhealth + S_BBUZZFLY1, // seestate + sfx_None, // seesound + 2, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + TICRATE, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 6*FRACUNIT, // speed + 20*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_gbeep, // activesound + MF_SLIDEME|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_SMASHINGSPIKEBALL 3001, // doomednum S_SMASHSPIKE_FLOAT, // spawnstate @@ -15669,33 +15751,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_HHZDUST - -1, // doomednum - S_HHZDUST1, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // 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 - 3*FRACUNIT, // speed - FRACUNIT, // radius - FRACUNIT, // height - 0, // display offset - 4, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags - S_NULL // raisestate - }, - { // MT_CACOLANTERN 3102, // doomednum S_CACO_LOOK, // spawnstate @@ -16293,6 +16348,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_DUST + -1, // doomednum + S_DUST1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 3*FRACUNIT, // speed + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags + S_NULL // raisestate + }, + { // MT_ROCKSPAWNER 1202, // doomednum S_ROCKSPAWN, // spawnstate diff --git a/src/info.h b/src/info.h index dde746236..0acaf6775 100644 --- a/src/info.h +++ b/src/info.h @@ -224,6 +224,9 @@ void A_MineRange(); void A_ConnectToGround(); void A_SpawnParticleRelative(); void A_MultiShotDist(); +void A_WhoCaresIfYourSonIsABee(); +void A_ParentTriesToSleep(); +void A_CryingToMomma(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 256 @@ -266,7 +269,6 @@ typedef enum sprite SPR_MNUS, // Minus SPR_SSHL, // Spring Shell SPR_UNID, // Unidus - SPR_BBUZ, // AquaBuzz, for Azure Temple // Generic Boss Items SPR_JETF, // Boss jet fumes @@ -587,6 +589,9 @@ typedef enum sprite SPR_CAPS, // Capsule thingy for NiGHTS // Secret badniks and hazards, shhhh + SPR_HIVE, + SPR_BUMB, + SPR_BBUZ, SPR_FMCE, SPR_HMCE, SPR_CACO, @@ -920,10 +925,6 @@ typedef enum state S_RBUZZFLY1, S_RBUZZFLY2, - // AquaBuzz - S_BBUZZFLY1, - S_BBUZZFLY2, - // Jetty-Syn Bomber S_JETBLOOK1, S_JETBLOOK2, @@ -1075,6 +1076,10 @@ typedef enum state S_FACESTABBER_CHARGE2, S_FACESTABBER_CHARGE3, S_FACESTABBER_CHARGE4, + S_FACESTABBER_PAIN, + S_FACESTABBER_DIE1, + S_FACESTABBER_DIE2, + S_FACESTABBER_DIE3, // Egg Guard S_EGGGUARD_STND, @@ -3304,6 +3309,32 @@ typedef enum state S_NIGHTOPIANHELPER9, // Secret badniks and hazards, shhhh + S_HIVEELEMENTAL_LOOK, + S_HIVEELEMENTAL_PREPARE1, + S_HIVEELEMENTAL_PREPARE2, + S_HIVEELEMENTAL_SHOOT1, + S_HIVEELEMENTAL_SHOOT2, + S_HIVEELEMENTAL_DORMANT, + S_HIVEELEMENTAL_PAIN, + S_HIVEELEMENTAL_DIE1, + S_HIVEELEMENTAL_DIE2, + S_HIVEELEMENTAL_DIE3, + + S_BUMBLEBORE_SPAWN, + S_BUMBLEBORE_LOOK1, + S_BUMBLEBORE_LOOK2, + S_BUMBLEBORE_FLY1, + S_BUMBLEBORE_FLY2, + S_BUMBLEBORE_RAISE, + S_BUMBLEBORE_FALL1, + S_BUMBLEBORE_FALL2, + S_BUMBLEBORE_STUCK1, + S_BUMBLEBORE_STUCK2, + S_BUMBLEBORE_DIE, + + S_BBUZZFLY1, + S_BBUZZFLY2, + S_SMASHSPIKE_FLOAT, S_SMASHSPIKE_EASE1, S_SMASHSPIKE_EASE2, @@ -3313,11 +3344,6 @@ typedef enum state S_SMASHSPIKE_RISE1, S_SMASHSPIKE_RISE2, - S_HHZDUST1, - S_HHZDUST2, - S_HHZDUST3, - S_HHZDUST4, - S_CACO_LOOK, S_CACO_WAKE1, S_CACO_WAKE2, @@ -3421,6 +3447,11 @@ typedef enum state S_WPLD5, S_WPLD6, + S_DUST1, + S_DUST2, + S_DUST3, + S_DUST4, + S_ROCKSPAWN, S_ROCKCRUMBLEA, @@ -3482,7 +3513,6 @@ typedef enum mobj_type MT_GFZFISH, // Greenflower Fish MT_GOLDBUZZ, MT_REDBUZZ, - MT_AQUABUZZ, // AquaBuzz for ATZ MT_JETTBOMBER, // Jetty-Syn Bomber MT_JETTGUNNER, // Jetty-Syn Gunner MT_CRAWLACOMMANDER, // Crawla Commander @@ -4015,17 +4045,18 @@ typedef enum mobj_type MT_NIGHTOPIANHELPER, // the actual helper object that orbits you // Secret badniks and hazards, shhhh - MT_SMASHINGSPIKEBALL, - MT_HHZDUST, + MT_HIVEELEMENTAL, + MT_BUMBLEBORE, + MT_BUBBLEBUZZ, + + MT_SMASHINGSPIKEBALL, MT_CACOLANTERN, MT_CACOSHARD, MT_CACOFIRE, - MT_SPINBOBERT, MT_SPINBOBERT_FIRE1, MT_SPINBOBERT_FIRE2, - MT_HANGSTER, // Utility Objects @@ -4048,6 +4079,7 @@ typedef enum mobj_type MT_SPARK, //spark MT_EXPLODE, // Robot Explosion MT_UWEXPLODE, // Underwater Explosion + MT_DUST, MT_ROCKSPAWNER, MT_FALLINGROCK, MT_ROCKCRUMBLE1, diff --git a/src/p_enemy.c b/src/p_enemy.c index 303dbc3bd..1ecf8cd3a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -252,6 +252,9 @@ void A_MineRange(mobj_t *actor); void A_ConnectToGround(mobj_t *actor); void A_SpawnParticleRelative(mobj_t *actor); void A_MultiShotDist(mobj_t *actor); +void A_WhoCaresIfYourSonIsABee(mobj_t *actor); +void A_ParentTriesToSleep(mobj_t *actor); +void A_CryingToMomma(mobj_t *actor); // // ENEMY THINKING @@ -4153,7 +4156,8 @@ void A_JetbThink(mobj_t *actor) { A_JetChase(actor); // check for melee attack - if ((actor->z > (actor->floorz + FixedMul((32<scale))) + if (actor->info->raisestate + && (actor->z > (actor->floorz + FixedMul((32<scale))) && P_JetbCheckMeleeRange(actor) && !actor->reactiontime && (actor->target->z >= actor->floorz)) { @@ -10851,7 +10855,7 @@ void A_SpawnParticleRelative(mobj_t *actor) x = (INT16)(locvar1>>16); y = (INT16)(locvar1&65535); z = (INT16)(locvar2>>16); - state = (mobjtype_t)(locvar2&65535); + state = (statenum_t)(locvar2&65535); // Spawn objects correctly in reverse gravity. // NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame @@ -10872,10 +10876,8 @@ void A_SpawnParticleRelative(mobj_t *actor) // // Description: Spawns multiple shots based on player proximity // -// var1: -// same as A_MultiShot -// var2: -// same as A_MultiShot +// var1 = same as A_MultiShot +// var2 = same as A_MultiShot // void A_MultiShotDist(mobj_t *actor) { @@ -10902,3 +10904,109 @@ void A_MultiShotDist(mobj_t *actor) var2 = locvar2; A_MultiShot(actor); } + +// Function: A_WhoCaresIfYourSonIsABee +// +// Description: Makes a child object, storing the number of created children in the parent's extravalue1. +// +// var1 = mobjtype of child +// var2 >> 16 = mobjtype of child +// var2 & 65535 = vertical momentum +// var2: +// var2 >> 16 = forward offset +// var2 & 65535 = vertical offset +// +void A_WhoCaresIfYourSonIsABee(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t foffsetx; + fixed_t foffsety; + mobj_t *son; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_WhoCaresIfYourSonIsABee", actor)) + return; +#endif + + A_FaceTarget(actor); + + if (actor->extravalue1) + actor->extravalue1--; + + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); + + foffsetx = P_ReturnThrustX(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + foffsety = P_ReturnThrustY(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + + if (!(son = P_SpawnMobjFromMobj(actor, foffsetx, foffsety, (locvar2&65535)*FRACUNIT, (mobjtype_t)(locvar1 >> 16)))) + return; + + P_SetObjectMomZ(son, (locvar1 & 65535)<tracer, actor); + P_SetTarget(&son->target, actor->target); +} + +// Function: A_ParentTriesToSleep +// +// Description: If extravalue1 is less than or equal to var1, go to var2. +// +// var1 = state to go to when extravalue1 +// var2 = unused +// +void A_ParentTriesToSleep(mobj_t *actor) +{ + INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ParentTriesToSleep", actor)) + return; +#endif + + if (actor->extravalue1) + { + if (actor->info->seesound) + S_StartSound(actor, actor->info->seesound); + actor->reactiontime = 0; + P_SetMobjState(actor, locvar1); + } + else if (!actor->reactiontime) + { + actor->reactiontime = 1; + if (actor->info->activesound) // more like INactivesound doy hoy hoy + S_StartSound(actor, actor->info->activesound); + } +} + + +// Function: A_CryingToMomma +// +// Description: If you're a child, let your parent know something's happened to you through extravalue1. Also, prepare to die. +// +// var1 = unused +// var2 = unused +// +void A_CryingToMomma(mobj_t *actor) +{ + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CryingToMomma", actor)) + return; +#endif + + if (actor->tracer) + actor->tracer->extravalue1++; + + actor->momx = actor->momy = actor->momz = 0; + + P_UnsetThingPosition(actor); + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + actor->flags = MF_NOBLOCKMAP|MF_NOCLIPTHING; + P_SetThingPosition(actor); +} diff --git a/src/p_inter.c b/src/p_inter.c index d437d494d..f50191ec1 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2334,7 +2334,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->fuse = target->info->damage; break; - case MT_AQUABUZZ: + case MT_BUBBLEBUZZ: if (inflictor && inflictor->player // did a player kill you? Spawn relative to the player so they're bound to get it && P_AproxDistance(inflictor->x - target->x, inflictor->y - target->y) <= inflictor->radius + target->radius + FixedMul(8*FRACUNIT, inflictor->scale) // close enough? && inflictor->z <= target->z + target->height + FixedMul(8*FRACUNIT, inflictor->scale) @@ -3278,20 +3278,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player) P_ResetPlayer(target->player); + else if ((target->type == MT_EGGMOBILE2) // egg slimer + && (target->health < target->info->damage)) // in pinch phase + P_SetMobjState(target, target->info->meleestate); // go to pinch pain state else - switch (target->type) - { - case MT_EGGMOBILE2: // egg slimer - if (target->health < target->info->damage) // in pinch phase - { - P_SetMobjState(target, target->info->meleestate); // go to pinch pain state - break; - } - /* FALLTHRU */ - default: - P_SetMobjState(target, target->info->painstate); - break; - } + P_SetMobjState(target, target->info->painstate); + + if (target->type == MT_HIVEELEMENTAL) + target->extravalue1 += 3; target->reactiontime = 0; // we're awake now... diff --git a/src/p_mobj.c b/src/p_mobj.c index a6c89a760..f0dcaf872 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7364,7 +7364,7 @@ void P_MobjThinker(mobj_t *mobj) } } break; - case MT_AQUABUZZ: + case MT_BUBBLEBUZZ: mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn { if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 @@ -7389,6 +7389,49 @@ void P_MobjThinker(mobj_t *mobj) } } break; + case MT_BUMBLEBORE: + { + statenum_t st = mobj->state-states; + if (st == S_BUMBLEBORE_FLY1 || st == S_BUMBLEBORE_FLY2) + { + if (!mobj->target) + P_SetMobjState(mobj, mobj->info->spawnstate); + else if (P_MobjFlip(mobj)*((mobj->z + (mobj->height>>1)) - (mobj->target->z + (mobj->target->height>>1))) > 0 + && R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) <= 32*FRACUNIT) + { + mobj->momx >>= 1; + mobj->momy >>= 1; + if (++mobj->movefactor == 4) + { + S_StartSound(mobj, mobj->info->seesound); + mobj->momx = mobj->momy = mobj->momz = 0; + mobj->flags = (mobj->flags|MF_PAIN) & ~MF_NOGRAVITY; + P_SetMobjState(mobj, mobj->info->meleestate); + } + } + else + mobj->movefactor = 0; + } + else if (st == S_BUMBLEBORE_RAISE || st == S_BUMBLEBORE_FALL2) // no _FALL1 because it's an 0-tic + { + if (P_IsObjectOnGround(mobj)) + { + S_StopSound(mobj); + S_StartSound(mobj, mobj->info->attacksound); + mobj->flags = (mobj->flags|MF_NOGRAVITY) & ~MF_PAIN; + mobj->momx = mobj->momy = mobj->momz = 0; + P_SetMobjState(mobj, mobj->info->painstate); + } + else + { + mobj->angle += ANGLE_22h; + mobj->frame = mobj->state->frame + ((mobj->tics & 2)>>1); + } + } + else if (st == S_BUMBLEBORE_STUCK2 && mobj->tics < TICRATE) + mobj->frame = mobj->state->frame + ((mobj->tics & 2)>>1); + } + break; case MT_BIGMINE: mobj->extravalue1 += 3; mobj->extravalue1 %= 360; @@ -8450,6 +8493,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) P_SetTarget(&spawn->target, mobj); } break; + case MT_FAKEMOBILE: + case MT_EGGSHIELD: + mobj->flags2 |= MF2_INVERTAIMABLE; + break; case MT_DETON: mobj->movedir = 0; break; @@ -8508,6 +8555,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_FLICKY_08: mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUA); break; + case MT_HIVEELEMENTAL: + mobj->extravalue1 = 5; + break; case MT_SMASHINGSPIKEBALL: mobj->movecount = mobj->z; break; @@ -10232,6 +10282,10 @@ ML_EFFECT4 : Don't clip inside the ground if (mthing->angle > 0) mobj->health = mthing->angle; break; + case MT_HIVEELEMENTAL: + if (mthing->extrainfo) + mobj->extravalue1 = mthing->extrainfo; + break; case MT_TRAPGOYLE: case MT_TRAPGOYLEUP: case MT_TRAPGOYLEDOWN: diff --git a/src/p_mobj.h b/src/p_mobj.h index f6ebd3cad..405dca77e 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -175,8 +175,8 @@ typedef enum MF2_SCATTER = 1<<8, // Thrown ring has scatter properties MF2_BEYONDTHEGRAVE = 1<<9, // Source of this missile has died and has since respawned. MF2_SLIDEPUSH = 1<<10, // MF_PUSHABLE that pushes continuously. - MF2_CLASSICPUSH = 1<<11, // Drops straight down when object has negative Z. - MF2_STANDONME = 1<<12, // While not pushable, stand on me anyway. + MF2_CLASSICPUSH = 1<<11, // Drops straight down when object has negative momz. + MF2_INVERTAIMABLE = 1<<12, // Flips whether it's targetable by A_LookForEnemies (enemies no, decoys yes) MF2_INFLOAT = 1<<13, // Floating to a height for a move, don't auto float to target's height. MF2_DEBRIS = 1<<14, // Splash ring from explosion ring MF2_NIGHTSPULL = 1<<15, // Attracted from a paraloop diff --git a/src/p_user.c b/src/p_user.c index d2dc36a8e..475079825 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8174,9 +8174,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; // not a mobj thinker mo = (mobj_t *)think; - if (!(mo->flags & targetmask - || mo->type == MT_FAKEMOBILE // hehehehe - || mo->type == MT_EGGSHIELD)) + if (!(mo->flags & targetmask) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag continue; // not a valid target if (mo->health <= 0) // dead diff --git a/src/sounds.c b/src/sounds.c index cabc7e686..f95256610 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -371,9 +371,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k89", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Advanced technology"}, {"s3k8a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boing"}, {"s3k8b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful hit"}, - {"s3k8c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s3k8c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Humming power"}, {"s3k8d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s3k8e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s3k8e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accelerating"}, {"s3k8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Opening"}, {"s3k90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"}, {"s3k91", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Closed"}, From 29e80c53005ee3fe2e9cf4cd07ebfdacaf294aa8 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 8 May 2018 18:14:39 -0400 Subject: [PATCH 114/212] Don't increment totalplaytime if a demo is playing. --- src/p_tick.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_tick.c b/src/p_tick.c index f4bc59323..e81d0e5b6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -607,6 +607,7 @@ void P_Ticker(boolean run) } // Keep track of how long they've been playing! + if (!demoplayback) // Don't incerment if a demo is playing. totalplaytime++; if (!useNightsSS && G_IsSpecialStage(gamemap)) From 8a61d8796155341fc3c4be52c7d489d102e92f94 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 8 May 2018 23:26:36 +0100 Subject: [PATCH 115/212] * Add new damagetype flag (DMG_CANHURTSELF) that allows a player to hurt themselves indirectly. * Add damagetype to P_RadiusAttack (optinteger in lua, A_Explode var1). * Removed the prevention of MF_BOSS objects from getting P_RadiusAttacked. This was a holdover from DooM (I checked) - a way to prevent the Cyberdemon from gibbing itself when firing point blank into a wall, and also a way to make it and the Spider Mastermind harder. * Enemies are solid to other enemies movement-wise now. * (Fun little aside - if you remove MF_SOLID from a monitor, it now behaves like they did in Sonic Adventure (poppable by colliding with, not just attacking). * Fixed Metal Sonic battle conflict in MF_PAIN/mass not picked up earlier. * Miscellaneous tiny code tweaks. --- src/dehacked.c | 1 + src/info.c | 2 +- src/lua_baselib.c | 3 ++- src/p_enemy.c | 11 ++++---- src/p_inter.c | 29 +++++++++++--------- src/p_local.h | 4 ++- src/p_map.c | 67 ++++++++++++++++++++--------------------------- src/p_mobj.c | 2 +- 8 files changed, 59 insertions(+), 60 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b6bd59501..b028b9c53 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7400,6 +7400,7 @@ struct { {"DMG_CRUSHED",DMG_CRUSHED}, {"DMG_SPECTATOR",DMG_SPECTATOR}, //// Masks + {"DMG_CANHURTSELF",DMG_CANHURTSELF}, {"DMG_DEATHMASK",DMG_DEATHMASK}, // Gametypes, for use with global var "gametype" diff --git a/src/info.c b/src/info.c index e744be054..91b8a2025 100644 --- a/src/info.c +++ b/src/info.c @@ -5422,7 +5422,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 48*FRACUNIT, // height 0, // display offset - sfx_s3k5a, // mass + 0, // mass 3, // damage sfx_mswarp, // activesound MF_NOGRAVITY|MF_BOSS|MF_SLIDEME, // flags diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 0cb530b53..c1fd87af3 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1356,11 +1356,12 @@ static int lib_pRadiusAttack(lua_State *L) mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); fixed_t damagedist = luaL_checkfixed(L, 3); + UINT8 damagetype = luaL_optinteger(L, 4, 0); NOHUD INLEVEL if (!spot || !source) return LUA_ErrInvalid(L, "mobj_t"); - P_RadiusAttack(spot, source, damagedist); + P_RadiusAttack(spot, source, damagedist, damagetype); return 0; } diff --git a/src/p_enemy.c b/src/p_enemy.c index 1ecf8cd3a..5cf045454 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2824,16 +2824,17 @@ void A_GoldMonitorSparkle(mobj_t *actor) // // Description: Explodes an object, doing damage to any objects nearby. The target is used as the cause of the explosion. Damage value is used as explosion range. // -// var1 = unused +// var1 = damagetype // var2 = unused // void A_Explode(mobj_t *actor) { + INT32 locvar1 = var1; #ifdef HAVE_BLUA if (LUA_CallAction("A_Explode", actor)) return; #endif - P_RadiusAttack(actor, actor->target, actor->info->damage); + P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1); } // Function: A_BossDeath @@ -9580,7 +9581,7 @@ void A_VileAttack(mobj_t *actor) actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), fire->z); - P_RadiusAttack(fire, actor, 70*FRACUNIT); + P_RadiusAttack(fire, actor, 70*FRACUNIT, 0); } else { @@ -9625,7 +9626,7 @@ void A_VileAttack(mobj_t *actor) actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), fire->z); - P_RadiusAttack(fire, actor, 70*FRACUNIT); + P_RadiusAttack(fire, actor, 70*FRACUNIT, 0); } } @@ -10709,7 +10710,7 @@ void A_MineExplode(mobj_t *actor) quake.intensity = 8*FRACUNIT; quake.time = TICRATE/3; - P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT); + P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT, DMG_CANHURTSELF); P_MobjCheckWater(actor); { diff --git a/src/p_inter.c b/src/p_inter.c index f50191ec1..7f712c84a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2670,7 +2670,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source) } } -static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) +static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { player_t *player = target->player; (void)damage; //unused parm @@ -2680,7 +2680,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return false; // Ignore IT players shooting each other, unless friendlyfire is on. - if ((player->pflags & PF_TAGIT && !(cv_friendlyfire.value && + if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && source && source->player && source->player->pflags & PF_TAGIT))) return false; @@ -2690,7 +2690,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou // Don't allow players on the same team to hurt one another, // unless cv_friendlyfire is on. - if (!cv_friendlyfire.value && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT)) + if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT)) { if (!(inflictor->flags & MF_FIRE)) P_GivePlayerRings(player, 1); @@ -2745,21 +2745,26 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return true; } -static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) +static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { player_t *player = target->player; - // You can't kill yourself, idiot... - if (source == target) - return false; + if (!(damagetype & DMG_CANHURTSELF)) + { + // You can't kill yourself, idiot... + if (source == target) + return false; - // In COOP/RACE/CHAOS, you can't hurt other players unless cv_friendlyfire is on - if (!cv_friendlyfire.value && (G_PlatformGametype())) - return false; + // In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on + if (!cv_friendlyfire.value && (G_PlatformGametype())) + return false; + } // Tag handling if (G_TagGametype()) - return P_TagDamage(target, inflictor, source, damage); + return P_TagDamage(target, inflictor, source, damage, damagetype); + else if (damagetype & DMG_CANHURTSELF) + return true; else if (G_GametypeHasTeams()) // CTF + Team Match { // Don't allow players on the same team to hurt one another, @@ -3177,7 +3182,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Player hits another player if (!force && source && source->player) { - if (!P_PlayerHitsPlayer(target, inflictor, source, damage)) + if (!P_PlayerHitsPlayer(target, inflictor, source, damage, damagetype)) return false; } diff --git a/src/p_local.h b/src/p_local.h index 1958e6559..da4c70b0f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -363,7 +363,7 @@ void P_DelPrecipSeclist(mprecipsecnode_t *node); void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y); void P_Initsecnode(void); -void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist); +void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype); fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); boolean PIT_PushableMoved(mobj_t *thing); @@ -413,6 +413,8 @@ typedef struct BasicFF_s #define DMG_DEATHPIT 0x80+3 #define DMG_CRUSHED 0x80+4 #define DMG_SPECTATOR 0x80+5 +// Masks +#define DMG_CANHURTSELF 0x40 // Flag - can hurt self/team indirectly, such as through mines #define DMG_DEATHMASK DMG_INSTAKILL // if bit 7 is set, this is a death type instead of a damage type void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period); diff --git a/src/p_map.c b/src/p_map.c index a219d3b97..a9d49a7e1 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -674,14 +674,14 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - if (thing->flags & MF_PAIN) + if (thing->flags & MF_PAIN && tmthing->player) { // Player touches painful thing sitting on the floor // see if it went over / under if (thing->z > tmthing->z + tmthing->height) return true; // overhead if (thing->z + thing->height < tmthing->z) return true; // underneath - if (tmthing->player && tmthing->flags & MF_SHOOTABLE && thing->health > 0) + if (tmthing->flags & MF_SHOOTABLE && thing->health > 0) { UINT8 damagetype = thing->info->mass; if (!damagetype && thing->flags & MF_FIRE) // BURN! @@ -691,14 +691,14 @@ static boolean PIT_CheckThing(mobj_t *thing) } return true; } - else if (tmthing->flags & MF_PAIN) + else if (tmthing->flags & MF_PAIN && thing->player) { // Painful thing splats player in the face // see if it went over / under if (tmthing->z > thing->z + thing->height) return true; // overhead if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (thing->player && thing->flags & MF_SHOOTABLE && tmthing->health > 0) + if (thing->flags & MF_SHOOTABLE && tmthing->health > 0) { UINT8 damagetype = tmthing->info->mass; if (!damagetype && tmthing->flags & MF_FIRE) // BURN! @@ -751,6 +751,7 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down return true; } + // missiles can hit other things if (tmthing->flags & MF_MISSILE || tmthing->type == MT_SHELL) { @@ -805,30 +806,11 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_EGGSHIELD) { - fixed_t touchx, touchy; - angle_t angle; + angle_t angle = (R_PointToAngle2(thing->x, thing->y, tmthing->x - tmthing->momx, tmthing->y - tmthing->momy) - thing->angle) - ANGLE_90; - if (P_AproxDistance(tmthing->x-thing->x, tmthing->y-thing->y) > - P_AproxDistance((tmthing->x-tmthing->momx)-thing->x, (tmthing->y-tmthing->momy)-thing->y)) - { - touchx = tmthing->x + tmthing->momx; - touchy = tmthing->y + tmthing->momy; - } - else - { - touchx = tmthing->x; - touchy = tmthing->y; - } - - angle = R_PointToAngle2(thing->x, thing->y, touchx, touchy) - thing->angle; - - if (!(angle > ANGLE_90 && angle < ANGLE_270)) // hit front of shield, didn't destroy it - return false; - else // hit shield from behind, shield is destroyed! - { + if (angle < ANGLE_180) // hit shield from behind, shield is destroyed! P_KillMobj(thing, tmthing, tmthing, 0); - return false; - } + return false; } // damage / explode @@ -1086,6 +1068,14 @@ static boolean PIT_CheckThing(mobj_t *thing) } } + // thanks to sal for solidenemies dot lua + if (thing->flags & (MF_ENEMY|MF_BOSS) && tmthing->flags & (MF_ENEMY|MF_BOSS)) + { + if ((thing->z + thing->height >= tmthing->z) + && (tmthing->z + tmthing->height >= thing->z)) + return false; + } + // Damage other players when invincible if (tmthing->player && thing->player // Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person. @@ -1150,7 +1140,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { // Objects kill you if it falls from above. if (thing != tmthing->target) - P_DamageMobj(thing, tmthing, tmthing->target, 1, DMG_INSTAKILL); + P_DamageMobj(thing, tmthing, tmthing->target, 1, DMG_CRUSHED); tmthing->momz = -tmthing->momz/2; // Bounce, just for fun! // The tmthing->target allows the pusher of the object @@ -1185,7 +1175,8 @@ static boolean PIT_CheckThing(mobj_t *thing) UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY) ? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2) : 0); - if (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) + if (!(thing->flags & MF_SOLID) + || tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) || ((tmthing->player->pflags & PF_JUMPED) && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) @@ -1194,8 +1185,8 @@ static boolean PIT_CheckThing(mobj_t *thing) && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) || elementalpierce) { - if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height - && thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z) + if (thing->z - thing->scale <= tmthing->z + tmthing->height + && thing->z + thing->height + thing->scale >= tmthing->z) { player_t *player = tmthing->player; SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed. @@ -3527,6 +3518,7 @@ bounceback: static fixed_t bombdamage; static mobj_t *bombsource; static mobj_t *bombspot; +static UINT8 bombdamagetype; // // PIT_RadiusAttack @@ -3537,17 +3529,13 @@ static boolean PIT_RadiusAttack(mobj_t *thing) { fixed_t dx, dy, dz, dist; - if (thing == bombspot // ignore the bomb itself (Deton fix) - || (bombsource && thing->type == bombsource->type)) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.) + if (thing == bombspot) // ignore the bomb itself (Deton fix) return true; - if (!(thing->flags & MF_SHOOTABLE)) + if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) != MF_SHOOTABLE) return true; - if (thing->flags & MF_BOSS) - return true; - - if (thing->flags & MF_MONITOR) + if (bombsource && thing->type == bombsource->type && !(bombdamagetype & DMG_CANHURTSELF)) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.) return true; dx = abs(thing->x - bombspot->x); @@ -3571,7 +3559,7 @@ static boolean PIT_RadiusAttack(mobj_t *thing) if (P_CheckSight(thing, bombspot)) { // must be in direct path - P_DamageMobj(thing, bombspot, bombsource, 1, 0); // Tails 01-11-2001 + P_DamageMobj(thing, bombspot, bombsource, 1, bombdamagetype); // Tails 01-11-2001 } return true; @@ -3581,7 +3569,7 @@ static boolean PIT_RadiusAttack(mobj_t *thing) // P_RadiusAttack // Source is the creature that caused the explosion at spot. // -void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist) +void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype) { INT32 x, y; INT32 xl, xh, yl, yh; @@ -3598,6 +3586,7 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist) bombspot = spot; bombsource = source; bombdamage = FixedMul(damagedist, spot->scale); + bombdamagetype = damagetype; for (y = yl; y <= yh; y++) for (x = xl; x <= xh; x++) diff --git a/src/p_mobj.c b/src/p_mobj.c index f0dcaf872..8e9f39a33 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -877,7 +877,7 @@ void P_ExplodeMissile(mobj_t *mo) if (mo->type == MT_DETON) { - P_RadiusAttack(mo, mo, 96*FRACUNIT); + P_RadiusAttack(mo, mo, 96*FRACUNIT, 0); explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); P_SetScale(explodemo, mo->scale); From 9ff491dd78f295412170832ff268d0b5aec24c99 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 8 May 2018 18:36:47 -0400 Subject: [PATCH 116/212] Add indentation --- src/p_tick.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index e81d0e5b6..aaf44f5e1 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -608,7 +608,7 @@ void P_Ticker(boolean run) // Keep track of how long they've been playing! if (!demoplayback) // Don't incerment if a demo is playing. - totalplaytime++; + totalplaytime++; if (!useNightsSS && G_IsSpecialStage(gamemap)) P_DoSpecialStageStuff(); From a1d696b38e650e4f2e05d01a50d63756200782b9 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 8 May 2018 18:38:28 -0400 Subject: [PATCH 117/212] Fix small typo --- src/p_tick.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index aaf44f5e1..4c59f8b48 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -607,7 +607,7 @@ void P_Ticker(boolean run) } // Keep track of how long they've been playing! - if (!demoplayback) // Don't incerment if a demo is playing. + if (!demoplayback) // Don't increment if a demo is playing. totalplaytime++; if (!useNightsSS && G_IsSpecialStage(gamemap)) From 4f75ae3a6819b68b476542abce497eea213a168e Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 11 May 2018 20:35:46 +0100 Subject: [PATCH 118/212] Fix both Bouncy FOF and Space Countdown sector specials working on FOFs without the FF_EXISTS flag Also move the Bouncy FOF sector special check above the FOF heights checking in P_CheckBouncySectors, because it means not having to waste time calculating FOF heights only for it not to be bouncy anyway :P --- src/p_user.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 7abf85347..da8e19caa 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1621,6 +1621,9 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space for (rover = sector->ffloors; rover; rover = rover->next) { + if (!(rover->flags & FF_EXISTS)) + continue; + if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL) continue; #ifdef ESLOPE @@ -1835,6 +1838,12 @@ static void P_CheckBouncySectors(player_t *player) for (rover = node->m_sector->ffloors; rover; rover = rover->next) { + if (!(rover->flags & FF_EXISTS)) + continue; // FOFs should not be bouncy if they don't even "exist" + + if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 15) + continue; // this sector type is required for FOFs to be bouncy + topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); @@ -1848,7 +1857,6 @@ static void P_CheckBouncySectors(player_t *player) && oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)) top = false; - if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 15) { fixed_t linedist; From a738ef99e323cdefdbd002e6f469718956eabcd6 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 13 May 2018 14:09:20 +0100 Subject: [PATCH 119/212] * DrT's Spincushion hardcoded. * Make the MF_PAIN stuff ONLY depend on mass, using the bottom 8 bits for the type and the custom sound in the upper ones. * A bunch of cleanup of random other stuff, including an unused Deton state and an unused Jetty type's sprite. --- src/dehacked.c | 31 +++++++++++------ src/hardware/hw_light.c | 29 ++++++++-------- src/info.c | 69 +++++++++++++++++++++---------------- src/info.h | 42 ++++++++++++++--------- src/p_enemy.c | 76 ++++++++++++++++++++++++++++------------- src/p_inter.c | 6 ++-- src/p_map.c | 12 +++---- src/p_mobj.c | 4 +++ src/sounds.c | 8 +++-- src/sounds.h | 2 ++ 10 files changed, 172 insertions(+), 107 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b028b9c53..7013c0379 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1704,6 +1704,7 @@ static actionpointer_t actionpointers[] = {{A_SnailerThink}, "A_SNAILERTHINK"}, {{A_SharpChase}, "A_SHARPCHASE"}, {{A_SharpSpin}, "A_SHARPSPIN"}, + {{A_SharpDecel}, "A_SHARPDECEL"}, {{A_VultureVtol}, "A_VULTUREVTOL"}, {{A_VultureCheck}, "A_VULTURECHECK"}, {{A_SkimChase}, "A_SKIMCHASE"}, @@ -3624,7 +3625,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_DETON13", "S_DETON14", "S_DETON15", - "S_DETON16", // Skim Mine Dropper "S_SKIM1", @@ -3666,14 +3666,25 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_TURRETPOPDOWN7", "S_TURRETPOPDOWN8", - // Sharp - "S_SHARP_ROAM1", - "S_SHARP_ROAM2", - "S_SHARP_AIM1", - "S_SHARP_AIM2", - "S_SHARP_AIM3", - "S_SHARP_AIM4", - "S_SHARP_SPIN", + // Spincushion + "S_SPINCUSHION_LOOK", + "S_SPINCUSHION_CHASE1", + "S_SPINCUSHION_CHASE2", + "S_SPINCUSHION_CHASE3", + "S_SPINCUSHION_CHASE4", + "S_SPINCUSHION_AIM1", + "S_SPINCUSHION_AIM2", + "S_SPINCUSHION_AIM3", + "S_SPINCUSHION_AIM4", + "S_SPINCUSHION_AIM5", + "S_SPINCUSHION_SPIN1", + "S_SPINCUSHION_SPIN2", + "S_SPINCUSHION_SPIN3", + "S_SPINCUSHION_SPIN4", + "S_SPINCUSHION_STOP1", + "S_SPINCUSHION_STOP2", + "S_SPINCUSHION_STOP3", + "S_SPINCUSHION_STOP4", // Jet Jaw "S_JETJAW_ROAM1", @@ -6161,7 +6172,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SKIM", // Skim mine dropper "MT_TURRET", "MT_POPUPTURRET", - "MT_SHARP", // Sharp + "MT_SPINCUSHION", // Spincushion "MT_JETJAW", // Jet Jaw "MT_SNAILER", // Snailer "MT_VULTURE", // Vulture diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 1c1f10d59..feb9565b5 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -62,7 +62,7 @@ static dynlights_t *dynlights = &view_dynlights[0]; light_t lspr[NUMLIGHTS] = { // type offset x, y coronas color, c_size,light color,l_radius, sqr radius computed at init - // UNDEFINED: 0 + // NOLIGHT: 0 { UNDEFINED_SPR, 0.0f, 0.0f, 0x00000000, 24.0f, 0x00000000, 0.0f, 0.0f}, // weapons // RINGSPARK_L @@ -151,10 +151,9 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_POSS &lspr[NOLIGHT], // SPR_SPOS &lspr[NOLIGHT], // SPR_FISH - &lspr[NOLIGHT], // SPR_BUZZ Graue 03-10-2004 - &lspr[NOLIGHT], // SPR_RBUZ Graue 03-10-2004 + &lspr[NOLIGHT], // SPR_BUZZ + &lspr[NOLIGHT], // SPR_RBUZ &lspr[NOLIGHT], // SPR_JETB - &lspr[NOLIGHT], // SPR_JETW &lspr[NOLIGHT], // SPR_JETG &lspr[NOLIGHT], // SPR_CCOM &lspr[NOLIGHT], // SPR_DETN @@ -226,8 +225,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_RING &lspr[NOLIGHT], // SPR_TRNG &lspr[NOLIGHT], // SPR_TOKE - &lspr[REDBALL_L], // SPR_RFLG - &lspr[BLUEBALL_L], // SPR_BFLG + &lspr[REDBALL_L], // SPR_RFLG + &lspr[BLUEBALL_L], // SPR_BFLG &lspr[NOLIGHT], // SPR_NWNG &lspr[NOLIGHT], // SPR_EMBM &lspr[NOLIGHT], // SPR_CEMG @@ -304,7 +303,7 @@ light_t *t_lspr[NUMSPRITES] = // Techno Hill Scenery &lspr[NOLIGHT], // SPR_THZP &lspr[NOLIGHT], // SPR_FWR5 - &lspr[REDBALL_L], // SPR_ALRM + &lspr[REDBALL_L], // SPR_ALRM // Deep Sea Scenery &lspr[NOLIGHT], // SPR_GARG @@ -381,8 +380,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_FIRS &lspr[NOLIGHT], // SPR_BUBS &lspr[NOLIGHT], // SPR_ZAPS - &lspr[INVINCIBLE_L], // SPR_IVSP - &lspr[SUPERSPARK_L], // SPR_SSPK + &lspr[INVINCIBLE_L], // SPR_IVSP + &lspr[SUPERSPARK_L], // SPR_SSPK &lspr[NOLIGHT], // SPR_GOAL @@ -410,7 +409,7 @@ light_t *t_lspr[NUMSPRITES] = // Springs &lspr[NOLIGHT], // SPR_SPRY &lspr[NOLIGHT], // SPR_SPRR - &lspr[NOLIGHT], // SPR_SPRB Graue + &lspr[NOLIGHT], // SPR_SPRB &lspr[NOLIGHT], // SPR_YSPR &lspr[NOLIGHT], // SPR_RSPR &lspr[NOLIGHT], // SPR_SSWY @@ -428,7 +427,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_DUST &lspr[NOLIGHT], // SPR_FPRT &lspr[SUPERSPARK_L], // SPR_TFOG - &lspr[NIGHTSLIGHT_L], // SPR_SEED // Sonic CD flower seed + &lspr[NIGHTSLIGHT_L], // SPR_SEED &lspr[NOLIGHT], // SPR_PRTL // Game Indicators @@ -467,19 +466,19 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_GOOM &lspr[NOLIGHT], // SPR_BGOM &lspr[REDBALL_L], // SPR_FFWR - &lspr[SMALLREDBALL_L], // SPR_FBLL + &lspr[SMALLREDBALL_L], // SPR_FBLL &lspr[NOLIGHT], // SPR_SHLL - &lspr[REDBALL_L], // SPR_PUMA + &lspr[REDBALL_L], // SPR_PUMA &lspr[NOLIGHT], // SPR_HAMM &lspr[NOLIGHT], // SPR_KOOP - &lspr[REDBALL_L], // SPR_BFLM + &lspr[REDBALL_L], // SPR_BFLM &lspr[NOLIGHT], // SPR_MAXE &lspr[NOLIGHT], // SPR_MUS1 &lspr[NOLIGHT], // SPR_MUS2 &lspr[NOLIGHT], // SPR_TOAD // NiGHTS Stuff - &lspr[SUPERSONIC_L], // SPR_NDRN // NiGHTS drone + &lspr[SUPERSONIC_L], // SPR_NDRN // NiGHTS drone &lspr[NOLIGHT], // SPR_NSPK &lspr[NOLIGHT], // SPR_NBMP &lspr[NOLIGHT], // SPR_HOOP diff --git a/src/info.c b/src/info.c index 91b8a2025..9c546e370 100644 --- a/src/info.c +++ b/src/info.c @@ -36,18 +36,17 @@ char sprnames[NUMSPRITES + 1][5] = "PLAY", // Enemies - "POSS", - "SPOS", - "FISH", // Greenflower Fish + "POSS", // Crawla (Blue) + "SPOS", // Crawla (Red) + "FISH", // SDURF "BUZZ", // Buzz (Gold) "RBUZ", // Buzz (Red) "JETB", // Jetty-Syn Bomber - "JETW", // Jetty-Syn Water Bomber "JETG", // Jetty-Syn Gunner "CCOM", // Crawla Commander "DETN", // Deton "SKIM", // Skim mine dropper - "TRET", + "TRET", // Industrial Turret "TURR", // Pop-Up Turret "SHRP", // Sharp "JJAW", // Jet Jaw @@ -55,7 +54,7 @@ char sprnames[NUMSPRITES + 1][5] = "VLTR", // Vulture "PNTY", // Pointy "ARCH", // Robo-Hood - "CBFS", // CastleBot FaceStabber (Egg Knight?) + "CBFS", // Castlebot Facestabber "SPSH", // Egg Guard "ESHI", // Egg Shield for Egg Guard "GSNP", // Green Snapper @@ -845,7 +844,6 @@ state_t states[NUMSTATES] = {SPR_DETN, 3, 1, {A_DetonChase}, 0, 0, S_DETON14}, // S_DETON13 {SPR_DETN, 2, 1, {A_DetonChase}, 0, 0, S_DETON15}, // S_DETON14 {SPR_DETN, 1, 1, {A_DetonChase}, 0, 0, S_DETON2}, // S_DETON15 - {SPR_DETN, 0, -1, {NULL}, 0, 0, S_DETON16}, // S_DETON16 // Skim Mine Dropper {SPR_SKIM, 0, 1, {A_SkimChase}, 0, 0, S_SKIM2}, // S_SKIM1 @@ -886,14 +884,25 @@ state_t states[NUMSTATES] = {SPR_TURR, 1, 2, {NULL}, 0, 0, S_TURRETPOPDOWN8}, // S_TURRETPOPDOWN7 {SPR_TURR, 0, 69,{A_SetTics}, 0, 1, S_TURRETLOOK}, // S_TURRETPOPDOWN8 - // Sharp - {SPR_SHRP, 0, 1, {A_Look}, 0, 0, S_SHARP_ROAM1}, // S_SHARP_ROAM1, - {SPR_SHRP, 0, 1, {A_SharpChase}, 0, 0, S_SHARP_ROAM2}, // S_SHARP_ROAM2, - {SPR_SHRP, 1, 2, {A_FaceTarget}, 0, 0, S_SHARP_AIM2}, // S_SHARP_AIM1, - {SPR_SHRP, 2, 2, {A_FaceTarget}, 0, 0, S_SHARP_AIM3}, // S_SHARP_AIM2, - {SPR_SHRP, 3, 2, {A_FaceTarget}, 0, 0, S_SHARP_AIM4}, // S_SHARP_AIM3, - {SPR_SHRP, 4, 7, {A_FaceTarget}, 0, 0, S_SHARP_SPIN}, // S_SHARP_AIM4, - {SPR_SHRP, 4, 1, {A_SharpSpin}, 0, 0, S_SHARP_SPIN}, // S_SHARP_SPIN, + // Spincushion + {SPR_SHRP, 0, 2, {A_Look}, 0, 0, S_SPINCUSHION_LOOK}, // S_SPINCUSHION_LOOK + {SPR_SHRP, 1, 2, {A_SharpChase}, 0, 0, S_SPINCUSHION_CHASE2}, // S_SPINCUSHION_CHASE1 + {SPR_SHRP, 2, 2, {A_SharpChase}, 0, 0, S_SPINCUSHION_CHASE3}, // S_SPINCUSHION_CHASE2 + {SPR_SHRP, 3, 2, {A_SharpChase}, 0, 0, S_SPINCUSHION_CHASE4}, // S_SPINCUSHION_CHASE3 + {SPR_SHRP, 0, 2, {A_SharpChase}, 0, 0, S_SPINCUSHION_CHASE1}, // S_SPINCUSHION_CHASE4 + {SPR_SHRP, 0, 2, {NULL}, 0, 0, S_SPINCUSHION_AIM2}, // S_SPINCUSHION_AIM1 + {SPR_SHRP, 4, 2, {NULL}, 0, 0, S_SPINCUSHION_AIM3}, // S_SPINCUSHION_AIM2 + {SPR_SHRP, 5, 2, {A_SetObjectFlags}, MF_PAIN, 2, S_SPINCUSHION_AIM4}, // S_SPINCUSHION_AIM3 + {SPR_SHRP, 6, 16, {A_MultiShotDist}, (MT_DUST<<16)|6, -32, S_SPINCUSHION_AIM5}, // S_SPINCUSHION_AIM4 + {SPR_SHRP, 6, 0, {A_PlaySound}, sfx_shrpgo, 1, S_SPINCUSHION_SPIN1}, // S_SPINCUSHION_AIM5 + {SPR_SHRP, 6, 1, {A_SharpSpin}, 0, 0, S_SPINCUSHION_SPIN2}, // S_SPINCUSHION_SPIN1 + {SPR_SHRP, 8, 1, {A_SharpSpin}, 0, 0, S_SPINCUSHION_SPIN3}, // S_SPINCUSHION_SPIN2 + {SPR_SHRP, 7, 1, {A_SharpSpin}, 0, 0, S_SPINCUSHION_SPIN4}, // S_SPINCUSHION_SPIN3 + {SPR_SHRP, 8, 1, {A_SharpSpin}, MT_SPINDUST, 0, S_SPINCUSHION_SPIN1}, // S_SPINCUSHION_SPIN4 + {SPR_SHRP, 6, 1, {A_PlaySound}, sfx_s3k69, 1, S_SPINCUSHION_STOP2}, // S_SPINCUSHION_STOP1 + {SPR_SHRP, 6, 4, {A_SharpDecel}, 0, 0, S_SPINCUSHION_STOP2}, // S_SPINCUSHION_STOP2 + {SPR_SHRP, 5, 4, {A_FaceTarget}, 0, 0, S_SPINCUSHION_STOP4}, // S_SPINCUSHION_STOP3 + {SPR_SHRP, 4, 4, {A_SetObjectFlags}, MF_PAIN, 1, S_SPINCUSHION_LOOK}, // S_SPINCUSHION_STOP4 // Jet Jaw {SPR_JJAW, 0, 1, {A_JetJawRoam}, 0, 0, S_JETJAW_ROAM2}, // S_JETJAW_ROAM1 @@ -3402,7 +3411,7 @@ state_t states[NUMSTATES] = {SPR_DUST, FF_TRANS40, 4, {NULL}, 0, 0, S_DUST2}, // S_DUST1 {SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_DUST3}, // S_DUST2 {SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4}, // S_DUST3 - {SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL}, // S_DUST4 + {SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL}, // S_DUST4 {SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN @@ -3795,7 +3804,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // meleestate S_NULL, // missilestate S_XPLD_FLICKY, // deathstate - S_DETON16, // xdeathstate + S_NULL, // xdeathstate sfx_pop, // deathsound 1*FRACUNIT, // speed 20*FRACUNIT, // radius @@ -3889,29 +3898,29 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = (statenum_t)MT_JETTBULLET// raisestate }, - { // MT_SHARP + { // MT_SPINCUSHION 112, // doomednum - S_SHARP_ROAM1, // spawnstate + S_SPINCUSHION_LOOK, // spawnstate 1, // spawnhealth - S_SHARP_ROAM2, // seestate + S_SPINCUSHION_CHASE1, // seestate sfx_None, // seesound 3*TICRATE, // reactiontime sfx_s3kd8s, // attacksound S_NULL, // painstate 5*TICRATE, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_SHARP_AIM1, // missilestate + sfx_shrpsp, // painsound + S_SPINCUSHION_STOP1, // meleestate + S_SPINCUSHION_AIM1, // missilestate S_XPLD_FLICKY, // deathstate - S_SHARP_SPIN, // xdeathstate + S_SPINCUSHION_STOP3, // xdeathstate sfx_pop, // deathsound 2, // speed 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage - sfx_None, // activesound + sfx_s3kaa, // activesound MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_BOUNCE, // flags S_NULL // raisestate }, @@ -15866,7 +15875,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // seestate sfx_None, // seesound 8, // reactiontime - sfx_ghosty, // attacksound + sfx_None, // attacksound S_NULL, // painstate 200, // painchance sfx_None, // painsound @@ -15879,7 +15888,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 16*FRACUNIT, // height 0, // display offset - 0, // mass + (sfx_ghosty<<8),// mass 20, // damage sfx_None, // activesound MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags @@ -15893,7 +15902,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // seestate sfx_None, // seesound 8, // reactiontime - sfx_ghosty, // attacksound + sfx_None, // attacksound S_NULL, // painstate 200, // painchance sfx_None, // painsound @@ -15906,7 +15915,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 16*FRACUNIT, // height 0, // display offset - 0, // mass + (sfx_ghosty<<8),// mass 20, // damage sfx_None, // activesound MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags diff --git a/src/info.h b/src/info.h index 0acaf6775..436cfc29c 100644 --- a/src/info.h +++ b/src/info.h @@ -103,6 +103,7 @@ void A_ArrowCheck(); void A_SnailerThink(); void A_SharpChase(); void A_SharpSpin(); +void A_SharpDecel(); void A_VultureVtol(); void A_VultureCheck(); void A_SkimChase(); @@ -243,18 +244,17 @@ typedef enum sprite SPR_PLAY, // Enemies - SPR_POSS, - SPR_SPOS, - SPR_FISH, // Greenflower Fish + SPR_POSS, // Crawla (Blue) + SPR_SPOS, // Crawla (Red) + SPR_FISH, // SDURF SPR_BUZZ, // Buzz (Gold) SPR_RBUZ, // Buzz (Red) SPR_JETB, // Jetty-Syn Bomber - SPR_JETW, // Jetty-Syn Water Bomber SPR_JETG, // Jetty-Syn Gunner SPR_CCOM, // Crawla Commander SPR_DETN, // Deton SPR_SKIM, // Skim mine dropper - SPR_TRET, + SPR_TRET, // Industrial Turret SPR_TURR, // Pop-Up Turret SPR_SHRP, // Sharp SPR_JJAW, // Jet Jaw @@ -262,7 +262,7 @@ typedef enum sprite SPR_VLTR, // Vulture SPR_PNTY, // Pointy SPR_ARCH, // Robo-Hood - SPR_CBFS, // CastleBot FaceStabber (Egg Knight?) + SPR_CBFS, // Castlebot Facestabber SPR_SPSH, // Egg Guard SPR_ESHI, // Egg Shield for Egg Guard SPR_GSNP, // Green Snapper @@ -961,7 +961,6 @@ typedef enum state S_DETON13, S_DETON14, S_DETON15, - S_DETON16, // Skim Mine Dropper S_SKIM1, @@ -1003,14 +1002,25 @@ typedef enum state S_TURRETPOPDOWN7, S_TURRETPOPDOWN8, - // Sharp - S_SHARP_ROAM1, - S_SHARP_ROAM2, - S_SHARP_AIM1, - S_SHARP_AIM2, - S_SHARP_AIM3, - S_SHARP_AIM4, - S_SHARP_SPIN, + // Spincushion + S_SPINCUSHION_LOOK, + S_SPINCUSHION_CHASE1, + S_SPINCUSHION_CHASE2, + S_SPINCUSHION_CHASE3, + S_SPINCUSHION_CHASE4, + S_SPINCUSHION_AIM1, + S_SPINCUSHION_AIM2, + S_SPINCUSHION_AIM3, + S_SPINCUSHION_AIM4, + S_SPINCUSHION_AIM5, + S_SPINCUSHION_SPIN1, + S_SPINCUSHION_SPIN2, + S_SPINCUSHION_SPIN3, + S_SPINCUSHION_SPIN4, + S_SPINCUSHION_STOP1, + S_SPINCUSHION_STOP2, + S_SPINCUSHION_STOP3, + S_SPINCUSHION_STOP4, // Jet Jaw S_JETJAW_ROAM1, @@ -3520,7 +3530,7 @@ typedef enum mobj_type MT_SKIM, // Skim mine dropper MT_TURRET, MT_POPUPTURRET, - MT_SHARP, // Sharp + MT_SPINCUSHION, // Spincushion MT_JETJAW, // Jet Jaw MT_SNAILER, // Snailer MT_VULTURE, // Vulture diff --git a/src/p_enemy.c b/src/p_enemy.c index 5cf045454..12c9d8dec 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -64,6 +64,7 @@ void A_ArrowCheck(mobj_t *actor); void A_SnailerThink(mobj_t *actor); void A_SharpChase(mobj_t *actor); void A_SharpSpin(mobj_t *actor); +void A_SharpDecel(mobj_t *actor); void A_VultureVtol(mobj_t *actor); void A_VultureCheck(mobj_t *actor); void A_SkimChase(mobj_t *actor); @@ -1491,7 +1492,7 @@ void A_SnailerThink(mobj_t *actor) // Function: A_SharpChase // -// Description: Thinker/Chase routine for Sharps +// Description: Thinker/Chase routine for Spincushions // // var1 = unused // var2 = unused @@ -1503,12 +1504,6 @@ void A_SharpChase(mobj_t *actor) return; #endif - if (!actor->health) - { - P_SetMobjState(actor, actor->info->deathstate); - return; - } - if (actor->reactiontime) { INT32 delta; @@ -1551,40 +1546,73 @@ void A_SharpChase(mobj_t *actor) // Function: A_SharpSpin // -// Description: Spin chase routine for Sharps +// Description: Spin chase routine for Spincushions // -// var1 = unused -// var2 = unused +// var1 = object # to spawn as dust (if not provided not done) +// var2 = if nonzero, do the old-style spinning using this as the angle difference // void A_SharpSpin(mobj_t *actor) { + INT32 locvar1 = var1; + INT32 locvar2 = var2; + angle_t oldang = actor->angle; + #ifdef HAVE_BLUA if (LUA_CallAction("A_SharpSpin", actor)) return; #endif - if (!actor->health) - { - P_SetMobjState(actor, actor->info->deathstate); - return; - } - if (actor->threshold && actor->target) { - actor->angle += ANGLE_22h; - P_Thrust(actor, R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y), FixedMul(actor->info->speed*FRACUNIT, actor->scale)); + angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_Thrust(actor, ang, actor->info->speed*actor->scale); + if (locvar2) + actor->angle += locvar2; // ANGLE_22h; + else + actor->angle = ang; actor->threshold--; + if (leveltime & 1) + S_StartSound(actor, actor->info->painsound); } else { actor->reactiontime = actor->info->reactiontime; - P_SetMobjState(actor, actor->info->spawnstate); - - var1 = 1; - A_Look(actor); - if (actor->target) - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_SetMobjState(actor, actor->info->meleestate); } + + if (!locvar1 || !P_IsObjectOnGround(actor)) + return; + + { + mobj_t *dust = P_SpawnMobjFromMobj(actor, + -P_ReturnThrustX(actor, oldang, 16<momx > 2 || actor->momy > 2) + { + actor->momx >>= 1; + actor->momy >>= 1; + } + else + P_SetMobjState(actor, actor->info->xdeathstate); } // Function: A_VultureVtol diff --git a/src/p_inter.c b/src/p_inter.c index 7f712c84a..c8c5a67a8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -396,8 +396,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) && P_DamageMobj(toucher, special, special, 1, DMG_SPIKE)) return; // Can only hit snapper from above - if (special->type == MT_SHARP - && ((special->state == &states[special->info->xdeathstate]) || (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0))) + if (special->type == MT_SPINCUSHION + && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0)) { if (player->pflags & PF_BOUNCING) { @@ -406,7 +406,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } else if (P_DamageMobj(toucher, special, special, 1, DMG_SPIKE)) - return; // Cannot hit sharp from above or when red and angry + return; // Cannot hit sharp from above } if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) diff --git a/src/p_map.c b/src/p_map.c index a9d49a7e1..3834dfb6f 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -683,11 +683,11 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (tmthing->flags & MF_SHOOTABLE && thing->health > 0) { - UINT8 damagetype = thing->info->mass; + UINT8 damagetype = (thing->info->mass & 0xFF); if (!damagetype && thing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; - if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && thing->info->attacksound) - S_StartSound(thing, thing->info->attacksound); + if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8))) + S_StartSound(thing, damagetype); } return true; } @@ -700,11 +700,11 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (thing->flags & MF_SHOOTABLE && tmthing->health > 0) { - UINT8 damagetype = tmthing->info->mass; + UINT8 damagetype = (tmthing->info->mass & 0xFF); if (!damagetype && tmthing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; - if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && tmthing->info->attacksound) - S_StartSound(tmthing, tmthing->info->attacksound); + if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && (damagetype = (tmthing->info->mass>>8))) + S_StartSound(tmthing, damagetype); } return true; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 8e9f39a33..d35237414 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7439,6 +7439,10 @@ void P_MobjThinker(mobj_t *mobj) mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); P_SetThingPosition(mobj); break; + case MT_SPINCUSHION: + if (mobj->target && mobj->state-states >= S_SPINCUSHION_AIM1 && mobj->state-states <= S_SPINCUSHION_AIM5) + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + break; case MT_SMASHINGSPIKEBALL: mobj->momx = mobj->momy = 0; if (mobj->state-states == S_SMASHSPIKE_FALL && P_IsObjectOnGround(mobj)) diff --git a/src/sounds.c b/src/sounds.c index f95256610..e9c9e2995 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -65,7 +65,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"buzz1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric zap"}, {"buzz2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric zap"}, {"buzz3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wacky worksurface"}, - {"buzz4", false, 8, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Buzz"}, + {"buzz4", true, 8, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Buzz"}, {"crumbl", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"}, // Platform Crumble Tails 03-16-2001 {"fire", false, 8, 32, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"}, {"grind", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic grinding"}, @@ -179,15 +179,17 @@ sfxinfo_t S_sfx[NUMSFX] = {"spring", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spring"}, {"statu1", true, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Pushing a statue"}, {"statu2", true, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Pushing a statue"}, - {"strpst", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, // Starpost Sound Tails 07-04-2002 + {"strpst", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, {"supert", true, 127, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"}, {"telept", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dash"}, {"tink" , false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Tink"}, - {"token" , true, 224, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Token"}, // SS token + {"token" , true, 224, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Token"}, {"trfire", true, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Laser fired"}, {"trpowr", true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, {"turhit", false, 40, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Laser hit"}, {"wdjump", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Whirlwind jump"}, + {"shrpsp", true, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spincushion"}, + {"shrpgo", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"}, {"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Spinning out"}, {"mspogo", false, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Breaking through"}, {"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"}, diff --git a/src/sounds.h b/src/sounds.h index ab024c253..56189f55f 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -254,6 +254,8 @@ typedef enum sfx_trpowr, sfx_turhit, sfx_wdjump, + sfx_shrpsp, + sfx_shrpgo, sfx_mswarp, sfx_mspogo, sfx_boingf, From 5c11131230ab2ca3c43de18cb61d28c285ea06aa Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 13 May 2018 17:25:55 +0100 Subject: [PATCH 120/212] Fix inverted chaining condition! --- src/p_inter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index c8c5a67a8..ae39ffe79 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2205,7 +2205,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_SetMobjState(scoremobj, scorestate); // On ground? No chain starts. - if (!source->player->powers[pw_invulnerability] && P_IsObjectOnGround(source)) + if (source->player->powers[pw_invulnerability] || !P_IsObjectOnGround(source)) source->player->scoreadd = locscoreadd; } } From e66e0bb20e7b2f211c5ed5956b2539abcca1f99a Mon Sep 17 00:00:00 2001 From: GoldenTails <39245725+GoldenTails@users.noreply.github.com> Date: Sun, 13 May 2018 14:19:36 -0500 Subject: [PATCH 121/212] Fixed MD2 models not loading correctly on Linux --- src/hardware/hw_md2.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index f59c1d4fc..5d156e1d5 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -288,7 +288,8 @@ static md2_model_t *md2_readModel(const char *filename) if (model == NULL) return 0; - file = fopen(filename, "rb"); + //Filename checking fixed ~Monster Iestyn and Golden + file = fopen(va("%s"PATHSEP"%s", srb2home, filename), "rb"); if (!file) { free(model); @@ -477,7 +478,8 @@ static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ #endif #endif png_FILE_p png_FILE; - char *pngfilename = va("md2/%s", filename); + //Filename checking fixed ~Monster Iestyn and Golden + char *pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); FIL_ForceExtension(pngfilename, ".png"); png_FILE = fopen(pngfilename, "rb"); @@ -605,7 +607,8 @@ static GrTextureFormat_t PCX_Load(const char *filename, int *w, int *h, size_t pw, ph, size, ptr = 0; INT32 ch, rep; FILE *file; - char *pcxfilename = va("md2/%s", filename); + //Filename checking fixed ~Monster Iestyn and Golden + char *pcxfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); FIL_ForceExtension(pcxfilename, ".pcx"); file = fopen(pcxfilename, "rb"); @@ -795,7 +798,8 @@ void HWR_InitMD2(void) } // read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { @@ -861,7 +865,8 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup CONS_Printf("AddPlayerMD2()...\n"); // read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { @@ -906,7 +911,8 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu return; // Read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { From 5f0a45124c8209fb10800ec76261e40a92572006 Mon Sep 17 00:00:00 2001 From: GoldenTails <39245725+GoldenTails@users.noreply.github.com> Date: Sun, 13 May 2018 14:32:33 -0500 Subject: [PATCH 122/212] Update hw_md2.c --- src/hardware/hw_md2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 5d156e1d5..3dc434709 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -26,6 +26,7 @@ #include #include +#include "../d_main.h" #include "../doomdef.h" #include "../doomstat.h" From 7783ddd13443854955a977d70a7fe087edad6d64 Mon Sep 17 00:00:00 2001 From: GoldenTails <39245725+GoldenTails@users.noreply.github.com> Date: Sun, 13 May 2018 14:34:08 -0500 Subject: [PATCH 123/212] Update hw_md2.c --- src/hardware/hw_md2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 3dc434709..be547e5ac 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -26,7 +26,6 @@ #include #include -#include "../d_main.h" #include "../doomdef.h" #include "../doomstat.h" @@ -34,6 +33,7 @@ #include "hw_drv.h" #include "hw_light.h" #include "hw_md2.h" +#include "../d_main.h" #include "../r_bsp.h" #include "../r_main.h" #include "../m_misc.h" From 7f084868b9a84baf9929e153513c9d5e224c9a4e Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sun, 13 May 2018 15:35:38 -0400 Subject: [PATCH 124/212] More helpful error message --- src/hardware/hw_md2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index f59c1d4fc..99018e1e5 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -799,7 +799,7 @@ void HWR_InitMD2(void) if (!f) { - CONS_Printf("%s", M_GetText("Error while loading md2.dat\n")); + CONS_Printf("%s %s\n", M_GetText("Error while loading md2.dat:"), strerror(errno)); nomd2s = true; return; } From b4d479ad9a121bcb4095e7610baaed63c27f6ebe Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sun, 13 May 2018 16:04:34 -0400 Subject: [PATCH 125/212] Include errno if not already included. --- src/hardware/hw_md2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 99018e1e5..d60524451 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -67,6 +67,10 @@ #endif #endif +#ifndef errno +#include "errno.h" +#endif + #define NUMVERTEXNORMALS 162 float avertexnormals[NUMVERTEXNORMALS][3] = { {-0.525731f, 0.000000f, 0.850651f}, From 26d13db548c2f7e2b4f43142cf4337d8fd281857 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 14 May 2018 01:19:24 +0100 Subject: [PATCH 126/212] * Crushtacean! * Behaves a bit differently to the one in DSZres.pk3. * Can now punch DSZ mines! * Also has mapthingnum 126 instead of 610. * Some other mapthingnum changes. * DSZ2 stalagmite is now 1009, formerly 999. * Big DSZ gargoyle is now 1011, formerly 1009. --- src/dehacked.c | 42 +++++-- src/hardware/hw_light.c | 1 + src/info.c | 109 ++++++++++++++++- src/info.h | 47 +++++-- src/p_enemy.c | 262 ++++++++++++++++++++++++++++++++++++++++ src/p_inter.c | 14 +++ src/p_map.c | 63 +++++++--- src/p_mobj.c | 69 ++++++----- src/sounds.c | 4 +- 9 files changed, 534 insertions(+), 77 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 7013c0379..5c5d1004a 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1705,6 +1705,10 @@ static actionpointer_t actionpointers[] = {{A_SharpChase}, "A_SHARPCHASE"}, {{A_SharpSpin}, "A_SHARPSPIN"}, {{A_SharpDecel}, "A_SHARPDECEL"}, + {{A_CrushstaceanWalk}, "A_CRUSHSTACEANWALK"}, + {{A_CrushstaceanPunch}, "A_CRUSHSTACEANPUNCH"}, + {{A_CrushclawAim}, "A_CRUSHCLAWAIM"}, + {{A_CrushclawLaunch}, "A_CRUSHCLAWLAUNCH"}, {{A_VultureVtol}, "A_VULTUREVTOL"}, {{A_VultureCheck}, "A_VULTURECHECK"}, {{A_SkimChase}, "A_SKIMCHASE"}, @@ -3686,6 +3690,21 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SPINCUSHION_STOP3", "S_SPINCUSHION_STOP4", + // Crushstacean + "S_CRUSHSTACEAN_ROAM1", + "S_CRUSHSTACEAN_ROAM2", + "S_CRUSHSTACEAN_ROAM3", + "S_CRUSHSTACEAN_ROAM4", + "S_CRUSHSTACEAN_ROAMPAUSE", + "S_CRUSHSTACEAN_PUNCH1", + "S_CRUSHSTACEAN_PUNCH2", + "S_CRUSHCLAW_AIM", + "S_CRUSHCLAW_OUT", + "S_CRUSHCLAW_STAY", + "S_CRUSHCLAW_IN", + "S_CRUSHCLAW_WAIT", + "S_CRUSHCHAIN", + // Jet Jaw "S_JETJAW_ROAM1", "S_JETJAW_ROAM2", @@ -6160,31 +6179,34 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_TAILSOVERLAY", // c: // Enemies - "MT_BLUECRAWLA", - "MT_REDCRAWLA", - "MT_GFZFISH", // Greenflower Fish - "MT_GOLDBUZZ", - "MT_REDBUZZ", + "MT_BLUECRAWLA", // Crawla (Blue) + "MT_REDCRAWLA", // Crawla (Red) + "MT_GFZFISH", // SDURF + "MT_GOLDBUZZ", // Buzz (Gold) + "MT_REDBUZZ", // Buzz (Red) "MT_JETTBOMBER", // Jetty-Syn Bomber "MT_JETTGUNNER", // Jetty-Syn Gunner "MT_CRAWLACOMMANDER", // Crawla Commander "MT_DETON", // Deton "MT_SKIM", // Skim mine dropper - "MT_TURRET", - "MT_POPUPTURRET", + "MT_TURRET", // Industrial Turret + "MT_POPUPTURRET", // Pop-Up Turret "MT_SPINCUSHION", // Spincushion + "MT_CRUSHSTACEAN", // Crushstacean + "MT_CRUSHCLAW", // Big meaty claw + "MT_CRUSHCHAIN", // Chain "MT_JETJAW", // Jet Jaw "MT_SNAILER", // Snailer - "MT_VULTURE", // Vulture + "MT_VULTURE", // BASH "MT_POINTY", // Pointy "MT_POINTYBALL", // Pointy Ball "MT_ROBOHOOD", // Robo-Hood "MT_FACESTABBER", // CastleBot FaceStabber "MT_EGGGUARD", // Egg Guard - "MT_EGGSHIELD", // Egg Shield for Egg Guard + "MT_EGGSHIELD", // Egg Guard's shield "MT_GSNAPPER", // Green Snapper "MT_MINUS", // Minus - "MT_SPRINGSHELL", // Spring Shell (no drop) + "MT_SPRINGSHELL", // Spring Shell "MT_YELLOWSHELL", // Spring Shell (yellow) "MT_UNIDUS", // Unidus "MT_UNIBALL", // Unidus Ball diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index feb9565b5..870dfb724 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -161,6 +161,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_TRET &lspr[NOLIGHT], // SPR_TURR &lspr[NOLIGHT], // SPR_SHRP + &lspr[NOLIGHT], // SPR_CRAB &lspr[NOLIGHT], // SPR_JJAW &lspr[NOLIGHT], // SPR_SNLR &lspr[NOLIGHT], // SPR_VLTR diff --git a/src/info.c b/src/info.c index 9c546e370..268944318 100644 --- a/src/info.c +++ b/src/info.c @@ -49,14 +49,15 @@ char sprnames[NUMSPRITES + 1][5] = "TRET", // Industrial Turret "TURR", // Pop-Up Turret "SHRP", // Sharp + "CRAB", // Crushstacean "JJAW", // Jet Jaw "SNLR", // Snailer - "VLTR", // Vulture + "VLTR", // BASH "PNTY", // Pointy "ARCH", // Robo-Hood "CBFS", // Castlebot Facestabber "SPSH", // Egg Guard - "ESHI", // Egg Shield for Egg Guard + "ESHI", // Egg Guard's shield "GSNP", // Green Snapper "MNUS", // Minus "SSHL", // Spring Shell @@ -904,6 +905,21 @@ state_t states[NUMSTATES] = {SPR_SHRP, 5, 4, {A_FaceTarget}, 0, 0, S_SPINCUSHION_STOP4}, // S_SPINCUSHION_STOP3 {SPR_SHRP, 4, 4, {A_SetObjectFlags}, MF_PAIN, 1, S_SPINCUSHION_LOOK}, // S_SPINCUSHION_STOP4 + // Crushstacean + {SPR_CRAB, 0, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM2}, // S_CRUSHSTACEAN_ROAM1 + {SPR_CRAB, 1, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM3}, // S_CRUSHSTACEAN_ROAM2 + {SPR_CRAB, 0, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM4}, // S_CRUSHSTACEAN_ROAM3 + {SPR_CRAB, 2, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM1}, // S_CRUSHSTACEAN_ROAM4 + {SPR_CRAB, 0, 40, {NULL}, 0, 0, S_CRUSHSTACEAN_ROAM1}, // S_CRUSHSTACEAN_ROAMPAUSE + {SPR_CRAB, 0, 10, {NULL}, 0, 0, S_CRUSHSTACEAN_PUNCH2}, // S_CRUSHSTACEAN_PUNCH1 + {SPR_CRAB, 0, -1, {A_CrushstaceanPunch}, 0, 0, S_CRUSHSTACEAN_ROAMPAUSE}, // S_CRUSHSTACEAN_PUNCH2 + {SPR_CRAB, 3, 1, {A_CrushclawAim}, 0, 0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_AIM + {SPR_CRAB, 3, 1, {A_CrushclawLaunch}, 0, S_CRUSHCLAW_STAY, S_CRUSHCLAW_OUT}, // S_CRUSHCLAW_OUT + {SPR_CRAB, 3, 10, {NULL}, 0, 0, S_CRUSHCLAW_IN}, // S_CRUSHCLAW_STAY + {SPR_CRAB, 3, 1, {A_CrushclawLaunch}, 1, S_CRUSHCLAW_WAIT, S_CRUSHCLAW_IN}, // S_CRUSHCLAW_IN + {SPR_CRAB, 3, 37, {NULL}, 0, 0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_WAIT + {SPR_CRAB, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CRUSHCHAIN + // Jet Jaw {SPR_JJAW, 0, 1, {A_JetJawRoam}, 0, 0, S_JETJAW_ROAM2}, // S_JETJAW_ROAM1 {SPR_JJAW, 0, 1, {A_JetJawRoam}, 0, 0, S_JETJAW_ROAM3}, // S_JETJAW_ROAM2 @@ -3455,7 +3471,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound - 8, // speed + 0, // speed 0, // radius 0, // height 0, // display offset @@ -3544,7 +3560,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MT_THOK, // damage sfx_None, // activesound MF_SOLID|MF_SHOOTABLE, // flags - (statenum_t)MT_NULL // raisestate + MT_NULL // raisestate }, { // MT_TAILSOVERLAY @@ -3925,6 +3941,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_CRUSHSTACEAN + 126, // doomednum + S_CRUSHSTACEAN_ROAM1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 32, // reactiontime + sfx_s3k6b, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_CRUSHSTACEAN_PUNCH1, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 8, // speed + 24*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_CRUSHCLAW + -1, // doomednum + S_CRUSHCLAW_AIM, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 16, // reactiontime + sfx_s3k6b, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_CRUSHCLAW_OUT,// missilestate + S_XPLD1, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 1, // speed + 32*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + (sfx_s3k49<<8), // mass + 0, // damage + sfx_s3kd2l, // activesound + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MT_CRUSHCHAIN // raisestate + }, + + { // MT_CRUSHCHAIN + -1, // doomednum + S_CRUSHCHAIN, // spawnstate + 0, // 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 + 0, // radius + 0, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_JETJAW 113, // doomednum S_JETJAW_ROAM1, // spawnstate @@ -8997,7 +9094,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIGGARGOYLE - 1009, // doomednum + 1011, // doomednum S_BIGGARGOYLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9267,7 +9364,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_DSZ2STALAGMITE - 999, // doomednum + 1009, // doomednum S_DSZ2STALAGMITE, // spawnstate 1000, // spawnhealth S_NULL, // seestate diff --git a/src/info.h b/src/info.h index 436cfc29c..38ebacadb 100644 --- a/src/info.h +++ b/src/info.h @@ -104,6 +104,10 @@ void A_SnailerThink(); void A_SharpChase(); void A_SharpSpin(); void A_SharpDecel(); +void A_CrushstaceanWalk(); +void A_CrushstaceanPunch(); +void A_CrushclawAim(); +void A_CrushclawLaunch(); void A_VultureVtol(); void A_VultureCheck(); void A_SkimChase(); @@ -257,14 +261,15 @@ typedef enum sprite SPR_TRET, // Industrial Turret SPR_TURR, // Pop-Up Turret SPR_SHRP, // Sharp + SPR_CRAB, // Crushstacean SPR_JJAW, // Jet Jaw SPR_SNLR, // Snailer - SPR_VLTR, // Vulture + SPR_VLTR, // BASH SPR_PNTY, // Pointy SPR_ARCH, // Robo-Hood SPR_CBFS, // Castlebot Facestabber SPR_SPSH, // Egg Guard - SPR_ESHI, // Egg Shield for Egg Guard + SPR_ESHI, // Egg Guard's shield SPR_GSNP, // Green Snapper SPR_MNUS, // Minus SPR_SSHL, // Spring Shell @@ -1022,6 +1027,21 @@ typedef enum state S_SPINCUSHION_STOP3, S_SPINCUSHION_STOP4, + // Crushstacean + S_CRUSHSTACEAN_ROAM1, + S_CRUSHSTACEAN_ROAM2, + S_CRUSHSTACEAN_ROAM3, + S_CRUSHSTACEAN_ROAM4, + S_CRUSHSTACEAN_ROAMPAUSE, + S_CRUSHSTACEAN_PUNCH1, + S_CRUSHSTACEAN_PUNCH2, + S_CRUSHCLAW_AIM, + S_CRUSHCLAW_OUT, + S_CRUSHCLAW_STAY, + S_CRUSHCLAW_IN, + S_CRUSHCLAW_WAIT, + S_CRUSHCHAIN, + // Jet Jaw S_JETJAW_ROAM1, S_JETJAW_ROAM2, @@ -3518,28 +3538,31 @@ typedef enum mobj_type MT_TAILSOVERLAY, // c: // Enemies - MT_BLUECRAWLA, - MT_REDCRAWLA, - MT_GFZFISH, // Greenflower Fish - MT_GOLDBUZZ, - MT_REDBUZZ, + MT_BLUECRAWLA, // Crawla (Blue) + MT_REDCRAWLA, // Crawla (Red) + MT_GFZFISH, // SDURF + MT_GOLDBUZZ, // Buzz (Gold) + MT_REDBUZZ, // Buzz (Red) MT_JETTBOMBER, // Jetty-Syn Bomber MT_JETTGUNNER, // Jetty-Syn Gunner MT_CRAWLACOMMANDER, // Crawla Commander MT_DETON, // Deton MT_SKIM, // Skim mine dropper - MT_TURRET, - MT_POPUPTURRET, + MT_TURRET, // Industrial Turret + MT_POPUPTURRET, // Pop-Up Turret MT_SPINCUSHION, // Spincushion + MT_CRUSHSTACEAN, // Crushstacean + MT_CRUSHCLAW, // Big meaty claw + MT_CRUSHCHAIN, // Chain MT_JETJAW, // Jet Jaw MT_SNAILER, // Snailer - MT_VULTURE, // Vulture + MT_VULTURE, // BASH MT_POINTY, // Pointy MT_POINTYBALL, // Pointy Ball MT_ROBOHOOD, // Robo-Hood - MT_FACESTABBER, // CastleBot FaceStabber + MT_FACESTABBER, // Castlebot Facestabber MT_EGGGUARD, // Egg Guard - MT_EGGSHIELD, // Egg Shield for Egg Guard + MT_EGGSHIELD, // Egg Guard's shield MT_GSNAPPER, // Green Snapper MT_MINUS, // Minus MT_SPRINGSHELL, // Spring Shell diff --git a/src/p_enemy.c b/src/p_enemy.c index 12c9d8dec..5a1257cdd 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -65,6 +65,10 @@ void A_SnailerThink(mobj_t *actor); void A_SharpChase(mobj_t *actor); void A_SharpSpin(mobj_t *actor); void A_SharpDecel(mobj_t *actor); +void A_CrushstaceanWalk(mobj_t *actor); +void A_CrushstaceanPunch(mobj_t *actor); +void A_CrushclawAim(mobj_t *actor); +void A_CrushclawLaunch(mobj_t *actor); void A_VultureVtol(mobj_t *actor); void A_VultureCheck(mobj_t *actor); void A_SkimChase(mobj_t *actor); @@ -1615,6 +1619,264 @@ void A_SharpDecel(mobj_t *actor) P_SetMobjState(actor, actor->info->xdeathstate); } +// Function: A_CrushstaceanWalk +// +// Description: Crushstacean movement +// +// var1 = speed (actor info's speed if 0) +// var2 = state to switch to when blocked (spawnstate if 0) +// +void A_CrushstaceanWalk(mobj_t *actor) +{ + INT32 locvar1 = (var1 ? var1 : (INT32)actor->info->speed); + INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); + angle_t ang = actor->angle + ((actor->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushstaceanWalk", actor)) + return; +#endif + + actor->reactiontime--; + + if (!P_TryMove(actor, + actor->x + P_ReturnThrustX(actor, ang, locvar1*actor->scale), + actor->y + P_ReturnThrustY(actor, ang, locvar1*actor->scale), + false) + || (actor->reactiontime-- <= 0)) + { + actor->flags2 ^= MF2_AMBUSH; + P_SetMobjState(actor, locvar2); + actor->reactiontime = actor->info->reactiontime; + } +} + +// Function: A_CrushstaceanPunch +// +// Description: Crushstacean attack +// +// var1 = unused +// var2 = state to go to if unsuccessful (spawnstate if 0) +// +void A_CrushstaceanPunch(mobj_t *actor) +{ + //INT32 locvar1 = var1; + INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushstaceanPunch", actor)) + return; +#endif + + if (!actor->tracer) + return; + + if (!actor->target) + { + P_SetMobjState(actor, locvar2); + return; + } + + actor->tracer->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_SetMobjState(actor->tracer, actor->tracer->info->missilestate); + actor->tracer->extravalue1 = actor->tracer->extravalue2 = 0; + S_StartSound(actor, actor->info->attacksound); +} + +// Function: A_CrushclawAim +// +// Description: Crushstacean claw aiming +// +// var1 = unused +// var2 = unused +// +void A_CrushclawAim(mobj_t *actor) +{ + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; + mobj_t *crab = actor->tracer; + angle_t ang; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushclawAim", actor)) + return; +#endif + + if (!crab) + { + P_RemoveMobj(actor); + return; // there is only one step and it is crab + } + + if (crab->target || P_LookForPlayers(crab, true, false, 600*crab->scale)) + ang = R_PointToAngle2(crab->x, crab->y, crab->target->x, crab->target->y); + else + ang = crab->angle + ((crab->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); + ang -= actor->angle; + +#define anglimit ANGLE_22h +#define angfactor 5 + if (ang < ANGLE_180) + { + if (ang > anglimit) + ang = anglimit; + ang /= angfactor; + } + else + { + ang = InvAngle(ang); + if (ang > anglimit) + ang = anglimit; + ang = InvAngle(ang/angfactor); + } + actor->angle += ang; +#undef anglimit +#undef angfactor + + P_TeleportMove(actor, + crab->x + P_ReturnThrustX(actor, actor->angle, 40*crab->scale), + crab->y + P_ReturnThrustY(actor, actor->angle, 40*crab->scale), + crab->z + 20*crab->scale); + + if (!crab->target || (statenum_t)(crab->state-states) == crab->info->missilestate) + return; + + if (((ang + ANG1) < ANG2) || P_AproxDistance(crab->x - crab->target->x, crab->y - crab->target->y) < 333*crab->scale) + P_SetMobjState(crab, crab->info->missilestate); +} + +// Function: A_CrushclawLaunch +// +// Description: Crushstacean claw launching +// +// var1: +// 0 - forwards +// anything else - backwards +// var2 = state to change to when done +// +void A_CrushclawLaunch(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *crab = actor->tracer; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushclawLaunch", actor)) + return; +#endif + + if (!crab) + { + mobj_t *chainnext; + while (actor) + { + chainnext = actor->target; + P_RemoveMobj(actor); + actor = chainnext; + } + return; // there is only one step and it is crab + } + + if (!actor->extravalue1) + { + S_StartSound(actor, actor->info->activesound); + actor->extravalue1 = ((locvar1) ? -1 : 32); + } + else if (actor->extravalue1 != 1) + actor->extravalue1 -= 1; + +#define CSEGS 5 + if (!actor->target) + { + mobj_t *prevchain = actor; + UINT8 i = 0; + for (i = 0; (i < CSEGS); i++) + { + mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate); + prevchain->target = newchain; + prevchain = newchain; + } + actor->target->angle = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y); + } + + if ((!locvar1) && crab->target) + { +#define anglimit ANGLE_22h +#define angfactor 7 + angle_t ang = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y) - actor->target->angle; + if (ang < ANGLE_180) + { + if (ang > anglimit) + ang = anglimit; + ang /= angfactor; + } + else + { + ang = InvAngle(ang); + if (ang > anglimit) + ang = anglimit; + ang /= angfactor; + ang = InvAngle(ang); + } + actor->target->angle += ang; + actor->angle = actor->target->angle; + } + + actor->extravalue2 += actor->extravalue1; + + if (!P_TryMove(actor, + actor->target->x + P_ReturnThrustX(actor, actor->target->angle, actor->extravalue2*actor->scale), + actor->target->y + P_ReturnThrustY(actor, actor->target->angle, actor->extravalue2*actor->scale), + true) + && !locvar1) + { + actor->extravalue1 = 0; + actor->extravalue2 = FixedHypot(actor->x - actor->target->x, actor->y - actor->target->y)>>FRACBITS; + P_SetMobjState(actor, locvar2); + S_StopSound(actor); + S_StartSound(actor, sfx_s3k49); + } + else + { + actor->z = actor->target->z; + if ((!locvar1 && (actor->extravalue2 > 256)) || (locvar1 && (actor->extravalue2 < 16))) + { + if (locvar1) // In case of retracting, resume crab and remove the chain. + { + mobj_t *chain = actor->target, *chainnext; + while (chain) + { + chainnext = chain->target; + P_RemoveMobj(chain); + chain = chainnext; + } + actor->extravalue2 = 0; + actor->angle = R_PointToAngle2(crab->x, crab->y, actor->x, actor->y); + P_SetTarget(&actor->target, NULL); + P_SetTarget(&crab->target, NULL); + P_SetMobjState(crab, crab->state->nextstate); + } + actor->extravalue1 = 0; + P_SetMobjState(actor, locvar2); + S_StopSound(actor); + } + } + + if (!actor->target) + return; + + { + mobj_t *chain = actor->target->target; + fixed_t dx = (actor->x - actor->target->x)/CSEGS, dy = (actor->y - actor->target->y)/CSEGS, dz = (actor->z - actor->target->z)/CSEGS; + fixed_t idx = dx, idy = dy, idz = dz; + while (chain) + { + P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz); + idx += dx; + idy += dy; + idz += dz; + chain = chain->target; + } + } +#undef CSEGS +} + // Function: A_VultureVtol // // Description: Vulture rising up to match target's height diff --git a/src/p_inter.c b/src/p_inter.c index ae39ffe79..8de008570 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2354,6 +2354,20 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->momx = target->momy = target->momz = 0; break; + case MT_CRUSHSTACEAN: + if (target->tracer) + { + mobj_t *chain = target->tracer->target, *chainnext; + while (chain) + { + chainnext = chain->target; + P_RemoveMobj(chain); + chain = chainnext; + } + P_KillMobj(target->tracer, inflictor, source, damagetype); + } + break; + case MT_EGGMOBILE3: { thinker_t *th; diff --git a/src/p_map.c b/src/p_map.c index 3834dfb6f..a7a12c2ec 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -633,28 +633,51 @@ static boolean PIT_CheckThing(mobj_t *thing) #endif // Billiards mines! - if (thing->type == MT_BIGMINE && tmthing->type == MT_BIGMINE) + if (thing->type == MT_BIGMINE) { - if (!tmthing->momx && !tmthing->momy) - return true; - if ((statenum_t)(thing->state-states) != thing->info->spawnstate) - return true; - if (thing->z > tmthing->z + tmthing->height) - return true; // overhead - if (thing->z + thing->height < tmthing->z) - return true; // underneath + if (tmthing->type == MT_BIGMINE) + { + if (!tmthing->momx && !tmthing->momy) + return true; + if ((statenum_t)(thing->state-states) >= thing->info->meleestate) + return true; + if (thing->z > tmthing->z + tmthing->height) + return true; // overhead + if (thing->z + thing->height < tmthing->z) + return true; // underneath - thing->momx = tmthing->momx/3; - thing->momy = tmthing->momy/3; - thing->momz = tmthing->momz/3; - tmthing->momx /= -8; - tmthing->momy /= -8; - tmthing->momz /= -8; - if (thing->info->activesound) - S_StartSound(thing, thing->info->activesound); - P_SetMobjState(thing, thing->info->meleestate); - P_SetTarget(&thing->tracer, tmthing->tracer); - return true; + thing->momx = tmthing->momx/3; + thing->momy = tmthing->momy/3; + thing->momz = tmthing->momz/3; + tmthing->momx /= -8; + tmthing->momy /= -8; + tmthing->momz /= -8; + if (thing->info->activesound) + S_StartSound(thing, thing->info->activesound); + P_SetMobjState(thing, thing->info->meleestate); + P_SetTarget(&thing->tracer, tmthing->tracer); + return true; + } + else if (tmthing->type == MT_CRUSHCLAW) + { + if (tmthing->extravalue1 <= 0) + return true; + if ((statenum_t)(thing->state-states) >= thing->info->meleestate) + return true; + if (thing->z > tmthing->z + tmthing->height) + return true; // overhead + if (thing->z + thing->height < tmthing->z) + return true; // underneath + + thing->momx = P_ReturnThrustX(tmthing, tmthing->angle, 2*tmthing->extravalue1*tmthing->scale/3); + thing->momy = P_ReturnThrustY(tmthing, tmthing->angle, 2*tmthing->extravalue1*tmthing->scale/3); + if (thing->info->activesound) + S_StartSound(thing, thing->info->activesound); + P_SetMobjState(thing, thing->info->meleestate); + if (tmthing->tracer) + P_SetTarget(&thing->tracer, tmthing->tracer->target); + return false; + } } // When solid spikes move, assume they just popped up and teleport things on top of them to hurt. diff --git a/src/p_mobj.c b/src/p_mobj.c index d35237414..095892c96 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8514,41 +8514,56 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } break; case MT_UNIDUS: - { - INT32 i; - mobj_t *ball; - // Spawn "damage" number of "painchance" spikeball mobjs - // threshold is the distance they should keep from the MT_UNIDUS (touching radius + ball painchance) - for (i = 0; i < mobj->info->damage; i++) { - ball = P_SpawnMobj(x, y, z, mobj->info->painchance); - ball->destscale = mobj->scale; - P_SetScale(ball, mobj->scale); - P_SetTarget(&ball->target, mobj); - ball->movedir = FixedAngle(FixedMul(FixedDiv(i<info->damage<threshold = ball->radius + mobj->radius + FixedMul(ball->info->painchance, ball->scale); + INT32 i; + mobj_t *ball; + // Spawn "damage" number of "painchance" spikeball mobjs + // threshold is the distance they should keep from the MT_UNIDUS (touching radius + ball painchance) + for (i = 0; i < mobj->info->damage; i++) + { + ball = P_SpawnMobj(x, y, z, mobj->info->painchance); + ball->destscale = mobj->scale; + P_SetScale(ball, mobj->scale); + P_SetTarget(&ball->target, mobj); + ball->movedir = FixedAngle(FixedMul(FixedDiv(i<info->damage<threshold = ball->radius + mobj->radius + FixedMul(ball->info->painchance, ball->scale); - var1 = ball->state->var1, var2 = ball->state->var2; - ball->state->action.acp1(ball); + var1 = ball->state->var1, var2 = ball->state->var2; + ball->state->action.acp1(ball); + } } break; - } case MT_POINTY: - { - INT32 q; - mobj_t *ball, *lastball = mobj; - - for (q = 0; q < mobj->info->painchance; q++) { - ball = P_SpawnMobj(x, y, z, mobj->info->mass); - ball->destscale = mobj->scale; - P_SetScale(ball, mobj->scale); - P_SetTarget(&lastball->tracer, ball); - P_SetTarget(&ball->target, mobj); - lastball = ball; + INT32 q; + mobj_t *ball, *lastball = mobj; + + for (q = 0; q < mobj->info->painchance; q++) + { + ball = P_SpawnMobj(x, y, z, mobj->info->mass); + ball->destscale = mobj->scale; + P_SetScale(ball, mobj->scale); + P_SetTarget(&lastball->tracer, ball); + P_SetTarget(&ball->target, mobj); + lastball = ball; + } + } + break; + case MT_CRUSHSTACEAN: + { + mobj_t *bigmeatyclaw; + angle_t ang = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); + bigmeatyclaw = P_SpawnMobjFromMobj(mobj, + P_ReturnThrustX(mobj, ang, 40<angle = ang; + P_SetTarget(&mobj->tracer, bigmeatyclaw); + P_SetTarget(&bigmeatyclaw->tracer, mobj); + mobj->reactiontime >>= 1; } break; - } case MT_BIGMINE: mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; break; diff --git a/src/sounds.c b/src/sounds.c index e9c9e2995..d4ec46d90 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -340,7 +340,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Unknown possibilities"}, {"s3k69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Switch click"}, {"s3k6a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage clear"}, - {"s3k6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s3k6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Punch"}, {"s3k6c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, {"s3k6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3k6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical damage"}, @@ -465,7 +465,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kd1s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3kd1l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto {"s3kd2s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turning"}, - {"s3kd2l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turning"}, // ditto + {"s3kd2l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Moving chain"}, // ditto {"s3kd3s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3kd3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto {"s3kd4s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Engine"}, From 3c50acd1bff7ce0d44f2edb77fb63eac6c1573e5 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 14 May 2018 13:19:52 +0100 Subject: [PATCH 127/212] * Minor changes to make A_CrushclawAim more useful. * Some fun with the chain. https://cdn.discordapp.com/attachments/402861856219463681/445539938633515018/srb20022.gif * More corrections to closed captions. --- src/info.c | 24 ++++++++++++------------ src/p_enemy.c | 19 +++++++++++-------- src/p_mobj.c | 23 +++++++++++++++-------- src/sounds.c | 2 +- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/info.c b/src/info.c index 268944318..74013c1b2 100644 --- a/src/info.c +++ b/src/info.c @@ -906,18 +906,18 @@ state_t states[NUMSTATES] = {SPR_SHRP, 4, 4, {A_SetObjectFlags}, MF_PAIN, 1, S_SPINCUSHION_LOOK}, // S_SPINCUSHION_STOP4 // Crushstacean - {SPR_CRAB, 0, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM2}, // S_CRUSHSTACEAN_ROAM1 - {SPR_CRAB, 1, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM3}, // S_CRUSHSTACEAN_ROAM2 - {SPR_CRAB, 0, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM4}, // S_CRUSHSTACEAN_ROAM3 - {SPR_CRAB, 2, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM1}, // S_CRUSHSTACEAN_ROAM4 - {SPR_CRAB, 0, 40, {NULL}, 0, 0, S_CRUSHSTACEAN_ROAM1}, // S_CRUSHSTACEAN_ROAMPAUSE - {SPR_CRAB, 0, 10, {NULL}, 0, 0, S_CRUSHSTACEAN_PUNCH2}, // S_CRUSHSTACEAN_PUNCH1 - {SPR_CRAB, 0, -1, {A_CrushstaceanPunch}, 0, 0, S_CRUSHSTACEAN_ROAMPAUSE}, // S_CRUSHSTACEAN_PUNCH2 - {SPR_CRAB, 3, 1, {A_CrushclawAim}, 0, 0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_AIM + {SPR_CRAB, 0, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM2}, // S_CRUSHSTACEAN_ROAM1 + {SPR_CRAB, 1, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM3}, // S_CRUSHSTACEAN_ROAM2 + {SPR_CRAB, 0, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM4}, // S_CRUSHSTACEAN_ROAM3 + {SPR_CRAB, 2, 3, {A_CrushstaceanWalk}, 0, S_CRUSHSTACEAN_ROAMPAUSE, S_CRUSHSTACEAN_ROAM1}, // S_CRUSHSTACEAN_ROAM4 + {SPR_CRAB, 0, 40, {NULL}, 0, 0, S_CRUSHSTACEAN_ROAM1}, // S_CRUSHSTACEAN_ROAMPAUSE + {SPR_CRAB, 0, 10, {NULL}, 0, 0, S_CRUSHSTACEAN_PUNCH2}, // S_CRUSHSTACEAN_PUNCH1 + {SPR_CRAB, 0, -1, {A_CrushstaceanPunch}, 0, 0, S_CRUSHSTACEAN_ROAMPAUSE}, // S_CRUSHSTACEAN_PUNCH2 + {SPR_CRAB, 3, 1, {A_CrushclawAim}, 40, 20, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_AIM {SPR_CRAB, 3, 1, {A_CrushclawLaunch}, 0, S_CRUSHCLAW_STAY, S_CRUSHCLAW_OUT}, // S_CRUSHCLAW_OUT - {SPR_CRAB, 3, 10, {NULL}, 0, 0, S_CRUSHCLAW_IN}, // S_CRUSHCLAW_STAY - {SPR_CRAB, 3, 1, {A_CrushclawLaunch}, 1, S_CRUSHCLAW_WAIT, S_CRUSHCLAW_IN}, // S_CRUSHCLAW_IN - {SPR_CRAB, 3, 37, {NULL}, 0, 0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_WAIT + {SPR_CRAB, 3, 10, {NULL}, 0, 0, S_CRUSHCLAW_IN}, // S_CRUSHCLAW_STAY + {SPR_CRAB, 3, 1, {A_CrushclawLaunch}, 1, S_CRUSHCLAW_WAIT, S_CRUSHCLAW_IN}, // S_CRUSHCLAW_IN + {SPR_CRAB, 3, 37, {NULL}, 0, 0, S_CRUSHCLAW_AIM}, // S_CRUSHCLAW_WAIT {SPR_CRAB, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CRUSHCHAIN // Jet Jaw @@ -4018,7 +4018,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate }, diff --git a/src/p_enemy.c b/src/p_enemy.c index 5a1257cdd..db4fd8f04 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1685,13 +1685,13 @@ void A_CrushstaceanPunch(mobj_t *actor) // // Description: Crushstacean claw aiming // -// var1 = unused -// var2 = unused +// var1 = sideways offset +// var2 = vertical offset // void A_CrushclawAim(mobj_t *actor) { - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; + INT32 locvar1 = var1; + INT32 locvar2 = var2; mobj_t *crab = actor->tracer; angle_t ang; #ifdef HAVE_BLUA @@ -1731,11 +1731,11 @@ void A_CrushclawAim(mobj_t *actor) #undef angfactor P_TeleportMove(actor, - crab->x + P_ReturnThrustX(actor, actor->angle, 40*crab->scale), - crab->y + P_ReturnThrustY(actor, actor->angle, 40*crab->scale), - crab->z + 20*crab->scale); + crab->x + P_ReturnThrustX(actor, actor->angle, locvar1*crab->scale), + crab->y + P_ReturnThrustY(actor, actor->angle, locvar1*crab->scale), + crab->z + locvar2*crab->scale); - if (!crab->target || (statenum_t)(crab->state-states) == crab->info->missilestate) + if (!crab->target || !crab->info->missilestate || (statenum_t)(crab->state-states) == crab->info->missilestate) return; if (((ang + ANG1) < ANG2) || P_AproxDistance(crab->x - crab->target->x, crab->y - crab->target->y) < 333*crab->scale) @@ -1855,6 +1855,8 @@ void A_CrushclawLaunch(mobj_t *actor) actor->extravalue1 = 0; P_SetMobjState(actor, locvar2); S_StopSound(actor); + if (!locvar1) + S_StartSound(actor, sfx_s3k64); } } @@ -1868,6 +1870,7 @@ void A_CrushclawLaunch(mobj_t *actor) while (chain) { P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz); + chain->watertop = chain->z; idx += dx; idy += dy; idz += dz; diff --git a/src/p_mobj.c b/src/p_mobj.c index 095892c96..a6daf29ba 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7443,6 +7443,19 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && mobj->state-states >= S_SPINCUSHION_AIM1 && mobj->state-states <= S_SPINCUSHION_AIM5) mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); break; + case MT_CRUSHCLAW: + if (mobj->state-states == S_CRUSHCLAW_STAY && mobj->target) + { + mobj_t *chain = mobj->target->target; + SINT8 sign = ((mobj->tics & 1) ? mobj->tics : -(SINT8)(mobj->tics)); + while (chain) + { + chain->z = chain->watertop + sign*mobj->scale; + sign = -sign; + chain = chain->target; + } + } + break; case MT_SMASHINGSPIKEBALL: mobj->momx = mobj->momy = 0; if (mobj->state-states == S_SMASHSPIKE_FALL && P_IsObjectOnGround(mobj)) @@ -8551,14 +8564,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_CRUSHSTACEAN: { - mobj_t *bigmeatyclaw; - angle_t ang = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); - bigmeatyclaw = P_SpawnMobjFromMobj(mobj, - P_ReturnThrustX(mobj, ang, 40<angle = ang; + mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CRUSHCLAW); + bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; P_SetTarget(&mobj->tracer, bigmeatyclaw); P_SetTarget(&bigmeatyclaw->tracer, mobj); mobj->reactiontime >>= 1; diff --git a/src/sounds.c b/src/sounds.c index d4ec46d90..8f2b805a9 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -306,7 +306,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"}, {"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising dust"}, {"s3k48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pulse"}, - {"s3k49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling rock"}, + {"s3k49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"}, {"s3k4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Grab"}, {"s3k4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Water splash"}, {"s3k4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"}, From 975a318460710576bee86ea66af68a0573bf5b31 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 14 May 2018 19:34:22 +0200 Subject: [PATCH 128/212] Change to linedef type 7 (flat alignment): If no tag is given, affect front sector. --- src/p_spec.c | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 595473a5c..faec226ad 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5527,6 +5527,30 @@ void P_InitSpecials(void) P_InitTagLists(); // Create xref tables for tags } +static void P_ApplyFlatAlignment(line_t* master, sector_t* sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs) +{ + if (!(master->flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set + { + sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle; + sector->floor_xoffs += xoffs; + sector->floor_yoffs += yoffs; + // saved for netgames + sector->spawn_flr_xoffs = sector->floor_xoffs; + sector->spawn_flr_yoffs = sector->floor_yoffs; + } + + if (!(master->flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set + { + sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle; + sector->ceiling_xoffs += xoffs; + sector->ceiling_yoffs += yoffs; + // saved for netgames + sector->spawn_ceil_xoffs = sector->ceiling_xoffs; + sector->spawn_ceil_yoffs = sector->ceiling_yoffs; + } + +} + /** After the map has loaded, scans for specials that spawn 3Dfloors and * thinkers. * @@ -5730,27 +5754,13 @@ void P_SpawnSpecials(INT32 fromnetsave) yoffs = lines[i].v1->y; } - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + //If no tag is given, apply to front sector + if (lines[i].tag == 0) + P_ApplyFlatAlignment(lines + i, lines[i].frontsector, flatangle, xoffs, yoffs); + else { - if (!(lines[i].flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set - { - sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = flatangle; - sectors[s].floor_xoffs += xoffs; - sectors[s].floor_yoffs += yoffs; - // saved for netgames - sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs; - sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs; - } - - if (!(lines[i].flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set - { - sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = flatangle; - sectors[s].ceiling_xoffs += xoffs; - sectors[s].ceiling_yoffs += yoffs; - // saved for netgames - sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs; - sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs; - } + for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0;) + P_ApplyFlatAlignment(lines + i, sectors + s, flatangle, xoffs, yoffs); } } else // Otherwise, print a helpful warning. Can I do no less? From 2e8cb9582afc081c36695f5099f6bcf32a4c52a6 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 15 May 2018 09:39:52 +0200 Subject: [PATCH 129/212] Consistency: Pointer declarations next to the variable name instead of the type --- src/p_spec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_spec.c b/src/p_spec.c index faec226ad..e77a783e9 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5527,7 +5527,7 @@ void P_InitSpecials(void) P_InitTagLists(); // Create xref tables for tags } -static void P_ApplyFlatAlignment(line_t* master, sector_t* sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs) +static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs) { if (!(master->flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set { From 720de810bdfc54a8bd510d3211c260ba8852c9a0 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 15 May 2018 16:10:42 +0100 Subject: [PATCH 130/212] The start of implementing FuriousFox's bumpers/balloons! No hardcoding of states, but the test .wad they're stored in right now is predominantly state, object, and sprite definitions/assets right now - the only hook is for setting the colour of the balloons!! --- src/p_enemy.c | 12 +++- src/p_map.c | 195 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 169 insertions(+), 38 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index db4fd8f04..ad9159a1d 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -225,7 +225,6 @@ void A_SetScale(mobj_t *actor); void A_RemoteDamage(mobj_t *actor); void A_HomingChase(mobj_t *actor); void A_TrapShot(mobj_t *actor); -//for p_enemy.c void A_Boss1Chase(mobj_t *actor); void A_Boss2Chase(mobj_t *actor); void A_Boss2Pogo(mobj_t *actor); @@ -260,6 +259,7 @@ void A_MultiShotDist(mobj_t *actor); void A_WhoCaresIfYourSonIsABee(mobj_t *actor); void A_ParentTriesToSleep(mobj_t *actor); void A_CryingToMomma(mobj_t *actor); +//for p_enemy.c // // ENEMY THINKING @@ -10385,6 +10385,8 @@ void A_SpawnFreshCopy(mobj_t *actor) newObject = P_SpawnMobj(actor->x, actor->y, actor->z, actor->type); newObject->angle = actor->angle; + newObject->flags2 |= (actor->flags2 & (MF2_AMBUSH|MF2_OBJECTFLIP)); + newObject->eflags |= (actor->eflags & MFE_VERTICALFLIP); P_SetScale(newObject, actor->scale); newObject->destscale = actor->destscale; P_SetTarget(&newObject->target, actor->target); @@ -10392,6 +10394,14 @@ void A_SpawnFreshCopy(mobj_t *actor) if (newObject->info->seesound) S_StartSound(newObject, newObject->info->seesound); + + + if (actor->spawnpoint) + { + newObject->spawnpoint = actor->spawnpoint; + actor->spawnpoint->mobj = newObject; + actor->spawnpoint = NULL; + } } // Internal Flicky spawning function. diff --git a/src/p_map.c b/src/p_map.c index a7a12c2ec..578c5325c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -109,13 +109,27 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) // MOVEMENT ITERATOR FUNCTIONS // ========================================================================= +// P_DoSpring +// +// MF_SPRING does some weird, mildly hacky stuff sometimes. +// mass = vertical speed +// damage = horizontal speed +// raisestate = state to change spring to on collision +// painchance = spring mode: +// 0 = standard vanilla spring behaviour +// Positive spring modes are minor variants of vanilla spring behaviour. +// 1 = launch players in jump +// 2 = don't modify player at all, just add momentum +// Negative spring modes are mildly-related gimmicks with customisation. +// -1 = pinball bumper +// Any other spring mode defaults to standard vanilla spring behaviour, +// ***** but forward compatibility is not guaranteed for these. ***** +// + boolean P_DoSpring(mobj_t *spring, mobj_t *object) { - INT32 pflags; - fixed_t offx, offy; fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; - UINT8 secondjump; // Does nothing? if (!vertispeed && !horizspeed) @@ -129,19 +143,109 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (object->player && object->player->spectator) return false; + // "Even in Death" is a song from Volume 8, not a command. + if (!spring->health || !object->health) + return false; + + if (spring->info->painchance == -1) // Pinball bumper mode. + { + // The first of the entirely different spring modes! + // Some of the attributes mean different things here. + // mass = default strength (can be controlled by mapthing's spawnangle) + // damage = unused + // reactiontime = number of times it can give points + angle_t horizangle, vertiangle; + if (object->player && object->player->homing) // Sonic Heroes, the only game to contain homing-attackable bumpers! + { + horizangle = 0; + vertiangle = ((object->eflags & MFE_VERTICALFLIP) ? ANGLE_270 : ANGLE_90) >> ANGLETOFINESHIFT; + object->player->pflags &= ~PF_THOKKED; + if (spring->eflags & MFE_VERTICALFLIP) + object->z = spring->z - object->height - 1; + else + object->z = spring->z + spring->height + 1; + } + else + { + horizangle = R_PointToAngle2(spring->x, spring->y, object->x, object->y); + vertiangle = (R_PointToAngle2( + 0, + spring->z + spring->height/2, + FixedHypot(object->x - spring->x, object->y - spring->y), + object->z + object->height/2) + >> ANGLETOFINESHIFT) & FINEMASK; + } + + if (spring->spawnpoint && spring->spawnpoint->angle > 0) + vertispeed = (spring->spawnpoint->angle<<(FRACBITS-1))/5; + vertispeed = FixedMul(vertispeed, FixedMul(object->scale, spring->scale)); + + if (object->player) + { + fixed_t playervelocity; + + if (!(object->player->pflags & PF_THOKKED) && !(object->player->homing) + && ((playervelocity = FixedDiv(9*FixedHypot(object->player->speed, object->momz), 10< vertispeed)) + vertispeed = playervelocity; + + if (object->player->powers[pw_carry] == CR_NIGHTSMODE) // THIS has NiGHTS support, at least... + { + if (object->player->bumpertime >= TICRATE/4) + return false; + + object->player->flyangle = AngleFixed(R_PointToAngle2( + 0, + spring->z + spring->height/2, + FixedMul( + FINECOSINE((object->angle >> ANGLETOFINESHIFT) & FINEMASK), + FixedHypot(object->x - spring->x, object->y - spring->y)), + object->z + object->height/2))>>FRACBITS; + object->player->bumpertime = TICRATE/2; + } + else + { + INT32 pflags = object->player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // Not identical to below... + UINT8 secondjump = object->player->secondjump; + if (object->player->pflags & PF_GLIDING) + P_SetPlayerMobjState(object, S_PLAY_FALL); + P_ResetPlayer(object->player); + object->player->pflags |= pflags; + object->player->secondjump = secondjump; + } + } + + object->eflags |= MFE_SPRUNG; // apply this flag asap! + + object->momz = FixedMul(vertispeed, FINESINE(vertiangle)); + P_InstaThrust(object, horizangle, FixedMul(vertispeed, FINECOSINE(vertiangle))); + + if ((statenum_t)(spring->state-states) == spring->info->spawnstate) + { + P_SetMobjState(spring, spring->info->raisestate); + if (object->player && spring->reactiontime) + { + mobj_t *scoremobj = P_SpawnMobj(spring->x, spring->y, spring->z + (spring->height/2), MT_SCORE); + P_SetMobjState(scoremobj, mobjinfo[MT_SCORE].spawnstate);//+11); -- 10 points state not hardcoded yet + P_AddPlayerScore(object->player, 10); + spring->reactiontime--; + } + } + return false; + } + if (object->player && (object->player->powers[pw_carry] == CR_NIGHTSMODE)) { /*Someone want to make these work like bumpers?*/ return false; } - if (spring->eflags & MFE_VERTICALFLIP) - vertispeed *= -1; - #ifdef ESLOPE object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. #endif + if (spring->eflags & MFE_VERTICALFLIP) + vertispeed *= -1; + if (object->player && ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) || (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2))) @@ -156,38 +260,42 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) object->eflags |= MFE_SPRUNG; // apply this flag asap! spring->flags &= ~(MF_SPRING|MF_SPECIAL); // De-solidify - if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA + if (spring->info->painchance != 2) { - object->momx = object->momy = 0; - P_TryMove(object, spring->x, spring->y, true); - } + if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA + { + object->momx = object->momy = 0; + P_TryMove(object, spring->x, spring->y, true); + } - if (vertispeed > 0) - object->z = spring->z + spring->height + 1; - else if (vertispeed < 0) - object->z = spring->z - object->height - 1; - else - { - // Horizontal springs teleport you in FRONT of them. - object->momx = object->momy = 0; + if (vertispeed > 0) + object->z = spring->z + spring->height + 1; + else if (vertispeed < 0) + object->z = spring->z - object->height - 1; + else + { + fixed_t offx, offy; + // Horizontal springs teleport you in FRONT of them. + object->momx = object->momy = 0; - // Overestimate the distance to position you at - offx = P_ReturnThrustX(spring, spring->angle, (spring->radius + object->radius + 1) * 2); - offy = P_ReturnThrustY(spring, spring->angle, (spring->radius + object->radius + 1) * 2); + // Overestimate the distance to position you at + offx = P_ReturnThrustX(spring, spring->angle, (spring->radius + object->radius + 1) * 2); + offy = P_ReturnThrustY(spring, spring->angle, (spring->radius + object->radius + 1) * 2); - // Make it square by clipping - if (offx > (spring->radius + object->radius + 1)) - offx = spring->radius + object->radius + 1; - else if (offx < -(spring->radius + object->radius + 1)) - offx = -(spring->radius + object->radius + 1); + // Make it square by clipping + if (offx > (spring->radius + object->radius + 1)) + offx = spring->radius + object->radius + 1; + else if (offx < -(spring->radius + object->radius + 1)) + offx = -(spring->radius + object->radius + 1); - if (offy > (spring->radius + object->radius + 1)) - offy = spring->radius + object->radius + 1; - else if (offy < -(spring->radius + object->radius + 1)) - offy = -(spring->radius + object->radius + 1); + if (offy > (spring->radius + object->radius + 1)) + offy = spring->radius + object->radius + 1; + else if (offy < -(spring->radius + object->radius + 1)) + offy = -(spring->radius + object->radius + 1); - // Set position! - P_TryMove(object, spring->x + offx, spring->y + offy, true); + // Set position! + P_TryMove(object, spring->x + offx, spring->y + offy, true); + } } if (vertispeed) @@ -203,6 +311,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (object->player) { + INT32 pflags; + UINT8 secondjump; + boolean washoming; + if (spring->flags & MF_ENEMY) // Spring shells P_SetTarget(&spring->target, object); @@ -223,19 +335,28 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) } } - pflags = object->player->pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_SHIELDABILITY|PF_BOUNCING); // I still need these. + pflags = object->player->pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // I still need these. secondjump = object->player->secondjump; + washoming = object->player->homing; + if (object->player->pflags & PF_GLIDING) + P_SetPlayerMobjState(object, S_PLAY_FALL); P_ResetPlayer(object->player); - if (spring->info->painchance) + if (spring->info->painchance == 1) // For all those ancient, SOC'd abilities. { object->player->pflags |= P_GetJumpFlags(object->player); P_SetPlayerMobjState(object, S_PLAY_JUMP); } - else if (!vertispeed || (pflags & PF_BOUNCING)) // horizontal spring or bouncing + else if ((spring->info->painchance == 2) || (pflags & PF_BOUNCING)) // Adding momentum only. { - if ((pflags & PF_BOUNCING) - || (pflags & (PF_JUMPED|PF_SPINNING) && (object->player->panim == PA_ROLL || object->player->panim == PA_JUMP || object->player->panim == PA_FALL))) + object->player->pflags |= (pflags &~ PF_STARTJUMP); + object->player->secondjump = secondjump; + if (washoming) + object->player->pflags &= ~PF_THOKKED; + } + else if (!vertispeed) + { + if (pflags & (PF_JUMPED|PF_SPINNING)) { object->player->pflags |= pflags; object->player->secondjump = secondjump; From badbb4324eb3f0b29ba0462753de45f5a9743dd3 Mon Sep 17 00:00:00 2001 From: Sryder Date: Wed, 16 May 2018 21:04:57 +0100 Subject: [PATCH 131/212] Fix FF_FULLBRIGHT not working in sectors with multiple light levels in OpenGL --- src/hardware/hw_main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 81021ef7f..b758c828e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4228,6 +4228,9 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) i = 0; temp = FLOAT_TO_FIXED(realtop); + if (spr->mobj->frame & FF_FULLBRIGHT) + lightlevel = 255; + #ifdef ESLOPE for (i = 1; i < sector->numlights; i++) { @@ -4235,14 +4238,16 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) : sector->lightlist[i].height; if (h <= temp) { - lightlevel = *list[i-1].lightlevel; + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = *list[i-1].lightlevel; colormap = list[i-1].extra_colormap; break; } } #else i = R_GetPlaneLight(sector, temp, false); - lightlevel = *list[i].lightlevel; + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = *list[i].lightlevel; colormap = list[i].extra_colormap; #endif @@ -4257,7 +4262,8 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) // even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) { - lightlevel = *list[i].lightlevel; + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = *list[i].lightlevel; colormap = list[i].extra_colormap; } From 0bef99f5666ca80bdbcf867814a9e0c75d89fca4 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Thu, 17 May 2018 13:57:19 -0400 Subject: [PATCH 132/212] Fix console typo --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 52cd6ddbb..362e0966d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3003,7 +3003,7 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX) { - CONS_Printf(M_GetText("Errors occured while loading %s; not added.\n"), wadfilename); + CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename); return false; } else wadnum = (UINT16)(numwadfiles-1); From 092e70923573cf365a4035fc1c10148f5d9becb1 Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 17 May 2018 22:17:20 +0100 Subject: [PATCH 133/212] OpenGL Map Specific palettes working This makes OpenGL stop using a specific function that doesn't really do anything for it anymore. It looks like it was used for a hack that would change the colour of polygons for the flashpal equivalent in DOOM. I made it so ST_DoPaletteStuff doesn't set the flashpal in OpenGL as it already does its own hacky overlay and doing that would cause all the textures to be flushed more mid-level, it could be enabled for more correct flashpals, but they still wouldn't effect fog or lighting. This means the palette will be set when going to the title screen, and twice when starting a map, (causing the OpenGL cached textures to also be flushed at those times) --- src/d_main.c | 7 +------ src/p_setup.c | 5 ----- src/st_stuff.c | 10 +++++----- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 4cdfb13d9..fbec5f7d8 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -730,11 +730,6 @@ void D_StartTitle(void) CON_ToggleOff(); // Reset the palette -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_SetPaletteColor(0); - else -#endif if (rendermode != render_none) V_SetPaletteLump("PLAYPAL"); } @@ -1223,7 +1218,7 @@ void D_SRB2Main(void) CONS_Printf("R_Init(): Init SRB2 refresh daemon.\n"); R_Init(); - // setting up sound + // setting up sound if (dedicated) { nosound = true; diff --git a/src/p_setup.c b/src/p_setup.c index 52cd6ddbb..c3aa9884d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2503,11 +2503,6 @@ boolean P_SetupLevel(boolean skipprecip) // Reset the palette -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_SetPaletteColor(0); - else -#endif if (rendermode != render_none) V_SetPaletteLump("PLAYPAL"); diff --git a/src/st_stuff.c b/src/st_stuff.c index 3562a9b71..72e0b6b94 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -210,17 +210,17 @@ void ST_doPaletteStuff(void) else palette = 0; +#ifdef HWRENDER + if (rendermode == render_opengl) + palette = 0; // No flashpals here in OpenGL +#endif + palette = min(max(palette, 0), 13); if (palette != st_palette) { st_palette = palette; -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_SetPaletteColor(0); - else -#endif if (rendermode != render_none) { V_SetPaletteLump(GetPalette()); // Reset the palette From ee42132ed121b66578b194f1a1f0976c9c481bc2 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 20 May 2018 00:04:39 +0100 Subject: [PATCH 134/212] * Bumpers and Balloons in a more final state. * Blue diagonal springs, because that gap is very, very odd. * Improved A_SpawnFreshCopy. * Tweaked P_LookForEnemies for consistency's sake. (Previously, it was impossible to make a spring that could neither be homing-attacked or attraction-shotted.) --- src/dehacked.c | 80 ++++++++++----- src/hardware/hw_light.c | 9 +- src/info.c | 212 ++++++++++++++++++++++++++++++---------- src/info.h | 97 ++++++++++++------ src/p_enemy.c | 43 +++++--- src/p_map.c | 84 ++++++++++------ src/p_mobj.c | 7 ++ src/p_user.c | 8 +- src/r_draw.c | 2 +- 9 files changed, 385 insertions(+), 157 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 5c5d1004a..e07fdb89d 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1826,6 +1826,7 @@ static actionpointer_t actionpointers[] = {{A_WhoCaresIfYourSonIsABee},"A_WHOCARESIFYOURSONISABEE"}, {{A_ParentTriesToSleep}, "A_PARENTTRIESTOSLEEP"}, {{A_CryingToMomma}, "A_CRYINGTOMOMMA"}, + {{A_CheckFlags2}, "A_CHECKFLAGS2"}, {{NULL}, "NONE"}, @@ -4420,12 +4421,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Emeralds (for hunt) "S_EMER1", - "S_FAN", - "S_FAN2", - "S_FAN3", - "S_FAN4", - "S_FAN5", - // Bubble Source "S_BUBBLES1", "S_BUBBLES2", @@ -4487,16 +4482,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SIGN52", // Eggman "S_SIGN53", - // Steam Riser - "S_STEAM1", - "S_STEAM2", - "S_STEAM3", - "S_STEAM4", - "S_STEAM5", - "S_STEAM6", - "S_STEAM7", - "S_STEAM8", - // Spike Ball "S_SPIKEBALL1", "S_SPIKEBALL2", @@ -5503,19 +5488,51 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SECRETFLICKY_02_FLAP2", "S_SECRETFLICKY_02_FLAP3", + // Fan + "S_FAN", + "S_FAN2", + "S_FAN3", + "S_FAN4", + "S_FAN5", + + // Steam Riser + "S_STEAM1", + "S_STEAM2", + "S_STEAM3", + "S_STEAM4", + "S_STEAM5", + "S_STEAM6", + "S_STEAM7", + "S_STEAM8", + + // Bumpers + "S_BUMPER", + "S_BUMPERHIT", + + // Balloons + "S_BALLOON", + "S_BALLOONPOP1", + "S_BALLOONPOP2", + "S_BALLOONPOP3", + "S_BALLOONPOP4", + "S_BALLOONPOP5", + "S_BALLOONPOP6", + + // Yellow Spring "S_YELLOWSPRING", "S_YELLOWSPRING2", "S_YELLOWSPRING3", "S_YELLOWSPRING4", "S_YELLOWSPRING5", + // Red Spring "S_REDSPRING", "S_REDSPRING2", "S_REDSPRING3", "S_REDSPRING4", "S_REDSPRING5", - // Blue Springs + // Blue Spring "S_BLUESPRING", "S_BLUESPRING2", "S_BLUESPRING3", @@ -5542,6 +5559,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_RDIAG7", "S_RDIAG8", + // Blue Diagonal Spring + "S_BDIAG1", + "S_BDIAG2", + "S_BDIAG3", + "S_BDIAG4", + "S_BDIAG5", + "S_BDIAG6", + "S_BDIAG7", + "S_BDIAG8", + // Yellow Side Spring "S_YHORIZ1", "S_YHORIZ2", @@ -5661,6 +5688,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SCRI", // 4000 (mario) "S_SCRJ", // 8000 (mario) "S_SCRK", // 1UP (mario) + "S_SCRL", // 10 // Drowning Timer Numbers "S_ZERO1", @@ -6293,15 +6321,19 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Springs and others "MT_FAN", - "MT_STEAM", // Steam riser - "MT_BLUESPRING", + "MT_STEAM", + "MT_BUMPER", + "MT_BALLOON", + "MT_YELLOWSPRING", "MT_REDSPRING", - "MT_YELLOWDIAG", // Yellow Diagonal Spring - "MT_REDDIAG", // Red Diagonal Spring - "MT_YELLOWHORIZ", // Yellow Side Spring - "MT_REDHORIZ", // Red Side Spring - "MT_BLUEHORIZ", // Blue Side Spring + "MT_BLUESPRING", + "MT_YELLOWDIAG", + "MT_REDDIAG", + "MT_BLUEDIAG", + "MT_YELLOWHORIZ", + "MT_REDHORIZ", + "MT_BLUEHORIZ", // Interactive Objects "MT_BUBBLES", // Bubble source diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 870dfb724..2f8ab99cb 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -234,10 +234,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_EMER // Interactive Objects - &lspr[NOLIGHT], // SPR_FANS &lspr[NOLIGHT], // SPR_BBLS &lspr[NOLIGHT], // SPR_SIGN - &lspr[NOLIGHT], // SPR_STEM &lspr[NOLIGHT], // SPR_SPIK &lspr[NOLIGHT], // SPR_SFLM &lspr[NOLIGHT], // SPR_USPK @@ -245,7 +243,6 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_WSPB &lspr[NOLIGHT], // SPR_STPT &lspr[NOLIGHT], // SPR_BMNE - &lspr[REDBALL_L], // SPR_BMNB // Monitor Boxes &lspr[NOLIGHT], // SPR_MSTV @@ -408,11 +405,16 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_FS02 // Springs + &lspr[NOLIGHT], // SPR_FANS + &lspr[NOLIGHT], // SPR_STEM + &lspr[NOLIGHT], // SPR_BUMP + &lspr[NOLIGHT], // SPR_BLON &lspr[NOLIGHT], // SPR_SPRY &lspr[NOLIGHT], // SPR_SPRR &lspr[NOLIGHT], // SPR_SPRB &lspr[NOLIGHT], // SPR_YSPR &lspr[NOLIGHT], // SPR_RSPR + &lspr[NOLIGHT], // SPR_BSPR &lspr[NOLIGHT], // SPR_SSWY &lspr[NOLIGHT], // SPR_SSWR &lspr[NOLIGHT], // SPR_SSWB @@ -506,6 +508,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[SUPERSPARK_L], // SPR_BOM2 &lspr[SUPERSPARK_L], // SPR_BOM3 &lspr[NOLIGHT], // SPR_BOM4 + &lspr[REDBALL_L], // SPR_BMNB // Crumbly rocks &lspr[NOLIGHT], // SPR_ROIA diff --git a/src/info.c b/src/info.c index 74013c1b2..cd26421ca 100644 --- a/src/info.c +++ b/src/info.c @@ -123,10 +123,8 @@ char sprnames[NUMSPRITES + 1][5] = "EMER", // Emerald Hunt // Interactive Objects - "FANS", "BBLS", // water bubble source "SIGN", // Level end sign - "STEM", // Steam riser "SPIK", // Spike Ball "SFLM", // Spin fire "USPK", // Floor spike @@ -134,7 +132,6 @@ char sprnames[NUMSPRITES + 1][5] = "WSPB", // Wall spike base "STPT", // Starpost "BMNE", // Big floating mine - "BMNB", // Monitor Boxes "MSTV", // MiSc TV sprites @@ -302,11 +299,16 @@ char sprnames[NUMSPRITES + 1][5] = "FS02", // Bat // Springs - "SPRY", // yellow spring - "SPRR", // red spring - "SPRB", // Blue springs + "FANS", // Fan + "STEM", // Steam riser + "BUMP", // Bumpers + "BLON", // Balloons + "SPRY", // Yellow spring + "SPRR", // Red spring + "SPRB", // Blue spring "YSPR", // Yellow Diagonal Spring "RSPR", // Red Diagonal Spring + "BSPR", // Blue Diagonal Spring "SSWY", // Yellow Side Spring "SSWR", // Red Side Spring "SSWB", // Blue Side Spring @@ -395,11 +397,12 @@ char sprnames[NUMSPRITES + 1][5] = "HBAT", // Debris - "SPRK", // spark + "SPRK", // Sparkle "BOM1", // Robot Explosion "BOM2", // Boss Explosion 1 "BOM3", // Boss Explosion 2 "BOM4", // Underwater Explosion + "BMNB", // Mine Explosion // Crumbly rocks "ROIA", @@ -1639,13 +1642,6 @@ state_t states[NUMSTATES] = // Emeralds (for hunt) {SPR_EMER, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EMER1 - // Fan - {SPR_FANS, 0, 1, {A_FanBubbleSpawn}, 2048, 0, S_FAN2}, // S_FAN - {SPR_FANS, 1, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN3}, // S_FAN2 - {SPR_FANS, 2, 1, {A_FanBubbleSpawn}, 512, 0, S_FAN4}, // S_FAN3 - {SPR_FANS, 3, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN5}, // S_FAN4 - {SPR_FANS, 4, 1, {A_FanBubbleSpawn}, 512, 0, S_FAN}, // S_FAN5 - // Bubble Source {SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2}, // S_BUBBLES1 {SPR_BBLS, 1, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES3}, // S_BUBBLES2 @@ -1707,16 +1703,6 @@ state_t states[NUMSTATES] = {SPR_SIGN, 3, -1, {NULL}, 0, 0, S_NULL}, // S_SIGN52 Eggman {SPR_SIGN, 7, -1, {A_SignPlayer}, 0, 0, S_NULL}, // S_SIGN53 Blank - // Steam Riser - {SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2}, // S_STEAM1 - {SPR_STEM, 1, 2, {A_UnsetSolidSteam}, 0, 0, S_STEAM3}, // S_STEAM2 - {SPR_STEM, 2, 2, {NULL}, 0, 0, S_STEAM4}, // S_STEAM3 - {SPR_STEM, 3, 2, {NULL}, 0, 0, S_STEAM5}, // S_STEAM4 - {SPR_STEM, 4, 2, {NULL}, 0, 0, S_STEAM6}, // S_STEAM5 - {SPR_STEM, 5, 2, {NULL}, 0, 0, S_STEAM7}, // S_STEAM6 - {SPR_STEM, 6, 2, {NULL}, 0, 0, S_STEAM8}, // S_STEAM7 - {SPR_STEM, 7, 18, {NULL}, 0, 0, S_STEAM1}, // S_STEAM8 - // Spike Ball {SPR_SPIK, 0, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL2}, // S_SPIKEBALL1 {SPR_SPIK, 1, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL3}, // S_SPIKEBALL2 @@ -2733,6 +2719,36 @@ state_t states[NUMSTATES] = {SPR_FS02, 2, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP3}, // S_SECRETFLICKY_02_FLAP2 {SPR_FS02, 3, 3, {A_FlickyFly}, 4*FRACUNIT, 16*FRACUNIT, S_SECRETFLICKY_02_FLAP1}, // S_SECRETFLICKY_02_FLAP3 + // Fan + {SPR_FANS, 0, 1, {A_FanBubbleSpawn}, 2048, 0, S_FAN2}, // S_FAN + {SPR_FANS, 1, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN3}, // S_FAN2 + {SPR_FANS, 2, 1, {A_FanBubbleSpawn}, 512, 0, S_FAN4}, // S_FAN3 + {SPR_FANS, 3, 1, {A_FanBubbleSpawn}, 1024, 0, S_FAN5}, // S_FAN4 + {SPR_FANS, 4, 1, {A_FanBubbleSpawn}, 512, 0, S_FAN}, // S_FAN5 + + // Steam Riser + {SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2}, // S_STEAM1 + {SPR_STEM, 1, 2, {A_UnsetSolidSteam}, 0, 0, S_STEAM3}, // S_STEAM2 + {SPR_STEM, 2, 2, {NULL}, 0, 0, S_STEAM4}, // S_STEAM3 + {SPR_STEM, 3, 2, {NULL}, 0, 0, S_STEAM5}, // S_STEAM4 + {SPR_STEM, 4, 2, {NULL}, 0, 0, S_STEAM6}, // S_STEAM5 + {SPR_STEM, 5, 2, {NULL}, 0, 0, S_STEAM7}, // S_STEAM6 + {SPR_STEM, 6, 2, {NULL}, 0, 0, S_STEAM8}, // S_STEAM7 + {SPR_STEM, 7, 18, {NULL}, 0, 0, S_STEAM1}, // S_STEAM8 + + // Bumpers + {SPR_BUMP, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BUMPER + {SPR_BUMP, FF_ANIMATE|4, 12, {A_Pain}, 1, 3, S_BUMPER}, //S_BUMPERHIT + + // Balloons + {SPR_BLON, FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_BALLOON + {SPR_BLON, 3, 0, {A_RemoteDamage}, 0, 1, S_BALLOONPOP2}, // S_BALLOONPOP1 + {SPR_BLON, 3, 1, {A_Pain}, 0, 0, S_BALLOONPOP3}, // S_BALLOONPOP2 + {SPR_BLON, 4, 1, {NULL}, 0, 0, S_BALLOONPOP4}, // S_BALLOONPOP3 + {SPR_NULL, 0, TICRATE, {A_CheckFlags2}, MF2_AMBUSH, S_BALLOONPOP5, S_NULL}, // S_BALLOONPOP4 + {SPR_NULL, 0, 15*TICRATE, {NULL}, 0, 0, S_BALLOONPOP6}, // S_BALLOONPOP5 + {SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_NULL}, // S_BALLOONPOP6 + // Yellow Spring {SPR_SPRY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWSPRING {SPR_SPRY, 4, 4, {A_Pain}, 0, 0, S_YELLOWSPRING3}, // S_YELLOWSPRING2 @@ -2774,6 +2790,16 @@ state_t states[NUMSTATES] = {SPR_RSPR, 2, 1, {NULL}, 0, 0, S_RDIAG8}, // S_RDIAG7 {SPR_RSPR, 1, 1, {NULL}, 0, 0, S_RDIAG1}, // S_RDIAG8 + // Blue Diagonal Spring + {SPR_BSPR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BDIAG1 + {SPR_BSPR, 1, 1, {A_Pain}, 0, 0, S_BDIAG3}, // S_BDIAG2 + {SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG4}, // S_BDIAG3 + {SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG5}, // S_BDIAG4 + {SPR_BSPR, 4, 1, {NULL}, 0, 0, S_BDIAG6}, // S_BDIAG5 + {SPR_BSPR, 3, 1, {NULL}, 0, 0, S_BDIAG7}, // S_BDIAG6 + {SPR_BSPR, 2, 1, {NULL}, 0, 0, S_BDIAG8}, // S_BDIAG7 + {SPR_BSPR, 1, 1, {NULL}, 0, 0, S_BDIAG1}, // S_BDIAG8 + // Yellow Side Spring {SPR_SSWY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YHORIZ1 {SPR_SSWY, 1, 1, {A_Pain}, 0, 0, S_YHORIZ3}, // S_YHORIZ2 @@ -2898,6 +2924,7 @@ state_t states[NUMSTATES] = {SPR_SCOR, 8, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRI - 4000 (mario mode) {SPR_SCOR, 9, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRJ - 8000 (mario mode) {SPR_SCOR, 10, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRK - 1UP (mario mode) + {SPR_SCOR, 11, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRL - 10 // Drowning Timer Numbers {SPR_DRWN, 0, 40, {NULL}, 0, 0, S_NULL}, // S_ZERO1 @@ -6150,40 +6177,67 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_BLUESPRING - 552, // doomednum - S_BLUESPRING, // spawnstate + { // MT_BUMPER + 542, // doomednum + S_BUMPER, // spawnstate 1000, // spawnhealth - S_BLUESPRING2, // seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 5, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance - sfx_spring, // painsound + -1, // painchance + sfx_s3kaa, // painsound S_NULL, // meleestate S_NULL, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 20*FRACUNIT, // radius - 16*FRACUNIT, // height + 32*FRACUNIT, // radius + 64*FRACUNIT, // height 0, // display offset - 11*FRACUNIT, // mass + 16*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SPRING, // flags - S_BLUESPRING2 // raisestate + MF_SPRING|MF_NOGRAVITY, // flags + S_BUMPERHIT // raisestate + }, + + { // MT_BALLOON + 543, // doomednum + S_BALLOON, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 2, // painchance + sfx_s3k77, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BALLOONPOP2, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 20*FRACUNIT, // mass + 0, // damage + sfx_None, // activesound + MF_SPRING|MF_NOGRAVITY, // flags + S_BALLOONPOP1 // raisestate }, { // MT_YELLOWSPRING 550, // doomednum S_YELLOWSPRING, // spawnstate 1000, // spawnhealth - S_YELLOWSPRING2,// seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -6208,9 +6262,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 551, // doomednum S_REDSPRING, // spawnstate 1000, // spawnhealth - S_REDSPRING2, // seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -6231,13 +6285,40 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_REDSPRING2 // raisestate }, + { // MT_BLUESPRING + 552, // doomednum + S_BLUESPRING, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_spring, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 11*FRACUNIT, // mass + 0, // damage + sfx_None, // activesound + MF_SPRING, // flags + S_BLUESPRING2 // raisestate + }, + { // MT_YELLOWDIAG 555, // doomednum S_YDIAG1, // spawnstate 1, // spawnhealth - S_YDIAG2, // seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -6262,9 +6343,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 556, // doomednum S_RDIAG1, // spawnstate 1, // spawnhealth - S_RDIAG2, // seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -6285,13 +6366,40 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_RDIAG2 // raisestate }, + { // MT_BLUEDIAG + 557, // doomednum + S_BDIAG1, // spawnstate + 1, // spawnhealth + S_BDIAG2, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_spring, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 11*FRACUNIT, // mass + 11*FRACUNIT, // damage + sfx_None, // activesound + MF_SPRING, // flags + S_BDIAG2 // raisestate + }, + { // MT_YELLOWHORIZ 558, // doomednum S_YHORIZ1, // spawnstate 1, // spawnhealth - S_YHORIZ2, // seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -6316,9 +6424,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 559, // doomednum S_RHORIZ1, // spawnstate 1, // spawnhealth - S_RHORIZ2, // seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -6343,9 +6451,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 560, // doomednum S_BHORIZ1, // spawnstate 1, // spawnhealth - S_BHORIZ2, // seestate + S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -6360,7 +6468,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // height 0, // display offset 0, // mass - 4*FRACUNIT, // damage + 1*FRACUNIT, // damage sfx_None, // activesound MF_SPRING|MF_NOGRAVITY, // flags S_BHORIZ2 // raisestate @@ -13760,7 +13868,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 3*FRACUNIT, // speed 8*FRACUNIT, // radius 8*FRACUNIT, // height - 0, // display offset + 1, // display offset 100, // mass 0, // damage sfx_None, // activesound diff --git a/src/info.h b/src/info.h index 38ebacadb..fc2c7b9c8 100644 --- a/src/info.h +++ b/src/info.h @@ -232,6 +232,7 @@ void A_MultiShotDist(); void A_WhoCaresIfYourSonIsABee(); void A_ParentTriesToSleep(); void A_CryingToMomma(); +void A_CheckFlags2(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 256 @@ -335,10 +336,8 @@ typedef enum sprite SPR_EMER, // Emerald Hunt // Interactive Objects - SPR_FANS, SPR_BBLS, // water bubble source SPR_SIGN, // Level end sign - SPR_STEM, // Steam riser SPR_SPIK, // Spike Ball SPR_SFLM, // Spin fire SPR_USPK, // Floor spike @@ -346,7 +345,6 @@ typedef enum sprite SPR_WSPB, // Wall spike base SPR_STPT, // Starpost SPR_BMNE, // Big floating mine - SPR_BMNB, // Monitor Boxes SPR_MSTV, // MiSc TV sprites @@ -514,11 +512,16 @@ typedef enum sprite SPR_FS02, // Bat // Springs - SPR_SPRY, // yellow spring - SPR_SPRR, // red spring - SPR_SPRB, // Blue springs + SPR_FANS, // Fan + SPR_STEM, // Steam riser + SPR_BUMP, // Bumpers + SPR_BLON, // Balloons + SPR_SPRY, // Yellow spring + SPR_SPRR, // Red spring + SPR_SPRB, // Blue spring SPR_YSPR, // Yellow Diagonal Spring SPR_RSPR, // Red Diagonal Spring + SPR_BSPR, // Blue Diagonal Spring SPR_SSWY, // Yellow Side Spring SPR_SSWR, // Red Side Spring SPR_SSWB, // Blue Side Spring @@ -607,11 +610,12 @@ typedef enum sprite SPR_HBAT, // Debris - SPR_SPRK, // spark + SPR_SPRK, // Sparkle SPR_BOM1, // Robot Explosion SPR_BOM2, // Boss Explosion 1 SPR_BOM3, // Boss Explosion 2 SPR_BOM4, // Underwater Explosion + SPR_BMNB, // Mine Explosion // Crumbly rocks SPR_ROIA, @@ -1757,12 +1761,6 @@ typedef enum state // Emeralds (for hunt) S_EMER1, - S_FAN, - S_FAN2, - S_FAN3, - S_FAN4, - S_FAN5, - // Bubble Source S_BUBBLES1, S_BUBBLES2, @@ -1824,16 +1822,6 @@ typedef enum state S_SIGN52, // Eggman S_SIGN53, - // Steam Riser - S_STEAM1, - S_STEAM2, - S_STEAM3, - S_STEAM4, - S_STEAM5, - S_STEAM6, - S_STEAM7, - S_STEAM8, - // Spike Ball S_SPIKEBALL1, S_SPIKEBALL2, @@ -2842,19 +2830,51 @@ typedef enum state S_SECRETFLICKY_02_FLAP2, S_SECRETFLICKY_02_FLAP3, + // Fan + S_FAN, + S_FAN2, + S_FAN3, + S_FAN4, + S_FAN5, + + // Steam Riser + S_STEAM1, + S_STEAM2, + S_STEAM3, + S_STEAM4, + S_STEAM5, + S_STEAM6, + S_STEAM7, + S_STEAM8, + + // Bumpers + S_BUMPER, + S_BUMPERHIT, + + // Balloons + S_BALLOON, + S_BALLOONPOP1, + S_BALLOONPOP2, + S_BALLOONPOP3, + S_BALLOONPOP4, + S_BALLOONPOP5, + S_BALLOONPOP6, + + // Yellow Spring S_YELLOWSPRING, S_YELLOWSPRING2, S_YELLOWSPRING3, S_YELLOWSPRING4, S_YELLOWSPRING5, + // Red Spring S_REDSPRING, S_REDSPRING2, S_REDSPRING3, S_REDSPRING4, S_REDSPRING5, - // Blue Springs + // Blue Spring S_BLUESPRING, S_BLUESPRING2, S_BLUESPRING3, @@ -2881,6 +2901,16 @@ typedef enum state S_RDIAG7, S_RDIAG8, + // Blue Diagonal Spring + S_BDIAG1, + S_BDIAG2, + S_BDIAG3, + S_BDIAG4, + S_BDIAG5, + S_BDIAG6, + S_BDIAG7, + S_BDIAG8, + // Yellow Side Spring S_YHORIZ1, S_YHORIZ2, @@ -3000,6 +3030,7 @@ typedef enum state S_SCRI, // 4000 (mario) S_SCRJ, // 8000 (mario) S_SCRK, // 1UP (mario) + S_SCRL, // 10 // Drowning Timer Numbers S_ZERO1, @@ -3652,15 +3683,19 @@ typedef enum mobj_type // Springs and others MT_FAN, - MT_STEAM, // Steam riser - MT_BLUESPRING, + MT_STEAM, + MT_BUMPER, + MT_BALLOON, + MT_YELLOWSPRING, MT_REDSPRING, - MT_YELLOWDIAG, // Yellow Diagonal Spring - MT_REDDIAG, // Red Diagonal Spring - MT_YELLOWHORIZ, // Yellow Side Spring - MT_REDHORIZ, // Red Side Spring - MT_BLUEHORIZ, // Blue Side Spring + MT_BLUESPRING, + MT_YELLOWDIAG, + MT_REDDIAG, + MT_BLUEDIAG, + MT_YELLOWHORIZ, + MT_REDHORIZ, + MT_BLUEHORIZ, // Interactive Objects MT_BUBBLES, // Bubble source diff --git a/src/p_enemy.c b/src/p_enemy.c index ad9159a1d..b4a75b9de 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -259,6 +259,7 @@ void A_MultiShotDist(mobj_t *actor); void A_WhoCaresIfYourSonIsABee(mobj_t *actor); void A_ParentTriesToSleep(mobj_t *actor); void A_CryingToMomma(mobj_t *actor); +void A_CheckFlags2(mobj_t *actor); //for p_enemy.c // @@ -763,6 +764,12 @@ static boolean P_LookForShield(mobj_t *actor) && (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale))) { P_SetTarget(&actor->tracer, player->mo); + + if (actor->hnext) + P_SetTarget(&actor->hnext->hprev, actor->hprev); + if (actor->hprev) + P_SetTarget(&actor->hprev->hnext, actor->hnext); + return true; } } @@ -10383,25 +10390,15 @@ void A_SpawnFreshCopy(mobj_t *actor) return; #endif - newObject = P_SpawnMobj(actor->x, actor->y, actor->z, actor->type); + newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); + newObject->flags2 = actor->flags2 & MF2_AMBUSH; newObject->angle = actor->angle; - newObject->flags2 |= (actor->flags2 & (MF2_AMBUSH|MF2_OBJECTFLIP)); - newObject->eflags |= (actor->eflags & MFE_VERTICALFLIP); - P_SetScale(newObject, actor->scale); - newObject->destscale = actor->destscale; + newObject->color = actor->color; P_SetTarget(&newObject->target, actor->target); P_SetTarget(&newObject->tracer, actor->tracer); if (newObject->info->seesound) S_StartSound(newObject, newObject->info->seesound); - - - if (actor->spawnpoint) - { - newObject->spawnpoint = actor->spawnpoint; - actor->spawnpoint->mobj = newObject; - actor->spawnpoint = NULL; - } } // Internal Flicky spawning function. @@ -11314,3 +11311,23 @@ void A_CryingToMomma(mobj_t *actor) actor->flags = MF_NOBLOCKMAP|MF_NOCLIPTHING; P_SetThingPosition(actor); } + +// Function: A_CheckFlags2 +// +// Description: If actor->flags2 & var1, goto var2. +// +// var1 = mask +// var2 = state to go +// +void A_CheckFlags2(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckFlags2", actor)) + return; +#endif + + if (actor->flags2 & locvar1) + P_SetMobjState(actor, (statenum_t)locvar2); +} diff --git a/src/p_map.c b/src/p_map.c index 578c5325c..c24dd6791 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -115,6 +115,7 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) // mass = vertical speed // damage = horizontal speed // raisestate = state to change spring to on collision +// reactiontime = number of times it can give 10 points (0 is standard) // painchance = spring mode: // 0 = standard vanilla spring behaviour // Positive spring modes are minor variants of vanilla spring behaviour. @@ -123,17 +124,14 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) // Negative spring modes are mildly-related gimmicks with customisation. // -1 = pinball bumper // Any other spring mode defaults to standard vanilla spring behaviour, -// ***** but forward compatibility is not guaranteed for these. ***** +// ****** but forward compatibility is not guaranteed for these. ****** // boolean P_DoSpring(mobj_t *spring, mobj_t *object) { fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; - - // Does nothing? - if (!vertispeed && !horizspeed) - return false; + boolean final; // Object was already sprung this tic if (object->eflags & MFE_SPRUNG) @@ -153,9 +151,12 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) // Some of the attributes mean different things here. // mass = default strength (can be controlled by mapthing's spawnangle) // damage = unused - // reactiontime = number of times it can give points angle_t horizangle, vertiangle; - if (object->player && object->player->homing) // Sonic Heroes, the only game to contain homing-attackable bumpers! + + if (!vertispeed) + return false; + + if (object->player && object->player->homing) // Sonic Heroes and Shadow the Hedgehog are the only games to contain homing-attackable bumpers! { horizangle = 0; vertiangle = ((object->eflags & MFE_VERTICALFLIP) ? ANGLE_270 : ANGLE_90) >> ANGLETOFINESHIFT; @@ -190,16 +191,32 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (object->player->powers[pw_carry] == CR_NIGHTSMODE) // THIS has NiGHTS support, at least... { + angle_t nightsangle = 0; + if (object->player->bumpertime >= TICRATE/4) return false; + if ((object->player->pflags & PF_TRANSFERTOCLOSEST) && object->player->axis1 && object->player->axis2) + { + nightsangle = R_PointToAngle2(object->player->axis1->x, object->player->axis1->y, object->player->axis2->x, object->player->axis2->y); + nightsangle += ANGLE_90; + } + else if (object->target) + { + if (object->target->flags2 & MF2_AMBUSH) + nightsangle = R_PointToAngle2(object->target->x, object->target->y, object->x, object->y); + else + nightsangle = R_PointToAngle2(object->x, object->y, object->target->x, object->target->y); + } + object->player->flyangle = AngleFixed(R_PointToAngle2( 0, spring->z + spring->height/2, FixedMul( - FINECOSINE((object->angle >> ANGLETOFINESHIFT) & FINEMASK), + FINESINE(((nightsangle - horizangle) >> ANGLETOFINESHIFT) & FINEMASK), FixedHypot(object->x - spring->x, object->y - spring->y)), object->z + object->height/2))>>FRACBITS; + object->player->bumpertime = TICRATE/2; } else @@ -214,30 +231,18 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) } } - object->eflags |= MFE_SPRUNG; // apply this flag asap! - - object->momz = FixedMul(vertispeed, FINESINE(vertiangle)); + if (!P_IsObjectOnGround(object)) // prevents uncurling when spinning due to "landing" + object->momz = FixedMul(vertispeed, FINESINE(vertiangle)); P_InstaThrust(object, horizangle, FixedMul(vertispeed, FINECOSINE(vertiangle))); - if ((statenum_t)(spring->state-states) == spring->info->spawnstate) - { - P_SetMobjState(spring, spring->info->raisestate); - if (object->player && spring->reactiontime) - { - mobj_t *scoremobj = P_SpawnMobj(spring->x, spring->y, spring->z + (spring->height/2), MT_SCORE); - P_SetMobjState(scoremobj, mobjinfo[MT_SCORE].spawnstate);//+11); -- 10 points state not hardcoded yet - P_AddPlayerScore(object->player, 10); - spring->reactiontime--; - } - } - return false; + object->eflags |= MFE_SPRUNG; // apply this flag asap! + + goto springstate; } - if (object->player && (object->player->powers[pw_carry] == CR_NIGHTSMODE)) - { - /*Someone want to make these work like bumpers?*/ + // Does nothing? + if (!vertispeed && !horizspeed) return false; - } #ifdef ESLOPE object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. @@ -246,6 +251,12 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (spring->eflags & MFE_VERTICALFLIP) vertispeed *= -1; + if (object->player && (object->player->powers[pw_carry] == CR_NIGHTSMODE)) + { + /*Someone want to make these work like bumpers?*/ + return false; + } + if (object->player && ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) || (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2))) @@ -307,8 +318,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) // Re-solidify spring->flags |= (spring->info->flags & (MF_SPRING|MF_SPECIAL)); - P_SetMobjState(spring, spring->info->raisestate); - if (object->player) { INT32 pflags; @@ -374,7 +383,22 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) object->standingslope = NULL; // And again. #endif - return true; + final = true; + +springstate: + if ((statenum_t)(spring->state-states) < spring->info->raisestate) + { + P_SetMobjState(spring, spring->info->raisestate); + if (object->player && spring->reactiontime && !(spring->info->flags & MF_ENEMY)) + { + mobj_t *scoremobj = P_SpawnMobj(spring->x, spring->y, spring->z + (spring->height/2), MT_SCORE); + P_SetMobjState(scoremobj, mobjinfo[MT_SCORE].spawnstate+11); + P_AddPlayerScore(object->player, 10); + spring->reactiontime--; + } + } + + return final; } static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) diff --git a/src/p_mobj.c b/src/p_mobj.c index a6daf29ba..9db80624e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8581,6 +8581,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_FLICKY_08: mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUA); break; + case MT_BALLOON: + mobj->color = SKINCOLOR_RED; + break; case MT_HIVEELEMENTAL: mobj->extravalue1 = 5; break; @@ -9873,6 +9876,10 @@ void P_SpawnMapThing(mapthing_t *mthing) else mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS; break; + case MT_BALLOON: + if (mthing->angle > 0) + mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1; + break; case MT_WATERDRIP: if (mthing->angle) mobj->tics = 3*TICRATE + mthing->angle; diff --git a/src/p_user.c b/src/p_user.c index 475079825..a28c8f445 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8163,7 +8163,6 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) mobj_t *mo; thinker_t *think; mobj_t *closestmo = NULL; - const UINT32 targetmask = (MF_ENEMY|MF_BOSS|(nonenemies ? (MF_MONITOR|MF_SPRING) : 0)); const fixed_t maxdist = FixedMul((bullet ? RING_DIST*2 : RING_DIST), player->mo->scale); const angle_t span = (bullet ? ANG30 : ANGLE_90); fixed_t dist, closestdist = 0; @@ -8174,7 +8173,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; // not a mobj thinker mo = (mobj_t *)think; - if (!(mo->flags & targetmask) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag continue; // not a valid target if (mo->health <= 0) // dead @@ -8189,6 +8188,9 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus) continue; + if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING)) + continue; + if (!bullet && mo->type == MT_DETON) // Don't be STUPID, Sonic! continue; @@ -8226,7 +8228,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) if (closestmo && dist > closestdist) continue; - if ((R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y) - player->mo->angle + span) > span*2) + if ((R_PointToAngle2(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius), mo->x, mo->y) - player->mo->angle + span) > span*2) continue; // behind back if (!P_CheckSight(player->mo, mo)) diff --git a/src/r_draw.c b/src/r_draw.c index e06d43f67..40945f4e0 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -257,7 +257,7 @@ const UINT8 Color_Index[MAXTRANSLATIONS-1][16] = { {0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, // SKINCOLOR_SUPERTAN2 {0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, // SKINCOLOR_SUPERTAN3 {0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, // SKINCOLOR_SUPERTAN4 - {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef} // SKINCOLOR_SUPERTAN5 + {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef} // SKINCOLOR_SUPERTAN5 }; // See also the enum skincolors_t From 001e4e11ca1dfd0ded1bbc29e26f71be50c86aac Mon Sep 17 00:00:00 2001 From: Tasos Sahanidis Date: Thu, 17 May 2018 17:55:38 +0300 Subject: [PATCH 135/212] Correct C FixedMul() off-by-one errors The FixedMul() C implementation would produce off by one results, causing constant desyncs on 64 bit builds and builds without an ASM implementation of the function. This is fixed by shifting instead of dividing, possibly avoiding rounding errors. --- src/m_fixed.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/m_fixed.c b/src/m_fixed.c index ce7471a28..014457386 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -33,7 +33,9 @@ */ fixed_t FixedMul(fixed_t a, fixed_t b) { - return (fixed_t)((((INT64)a * b) ) / FRACUNIT); + // Need to cast to unsigned before shifting to avoid undefined behaviour + // for negative integers + return (fixed_t)(((UINT64)((INT64)a * b)) >> FRACBITS); } #endif //__USE_C_FIXEDMUL__ From f061ffa00ebb6bf748505666c98623794e588df3 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 21 May 2018 20:02:30 +0100 Subject: [PATCH 136/212] Stop Each Time trigger linedefs and object-carrying scrollers from doing anything with FOFs without FF_EXISTS --- src/p_floor.c | 14 ++++++++++++++ src/p_spec.c | 27 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/p_floor.c b/src/p_floor.c index 35c743a07..f30637659 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2103,6 +2103,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) boolean floortouch = false; fixed_t bottomheight, topheight; msecnode_t *node; + ffloor_t *rover; for (i = 0; i < MAXPLAYERS; i++) { @@ -2150,6 +2151,19 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) { targetsec = §ors[targetsecnum]; + // Find the FOF corresponding to the control linedef + for (rover = targetsec->ffloors; rover; rover = rover->next) + { + if (rover->master == sec->lines[i]) + break; + } + + if (!rover) // This should be impossible, but don't complain if it is the case somehow + continue; + + if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there + continue; + for (j = 0; j < MAXPLAYERS; j++) { if (!playeringame[j]) diff --git a/src/p_spec.c b/src/p_spec.c index c62c3b209..d308a9b3f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6628,6 +6628,7 @@ void T_Scroll(scroll_t *s) line_t *line; size_t i; INT32 sect; + ffloor_t *rover; case sc_side: // scroll wall texture side = sides + s->affectee; @@ -6669,6 +6670,19 @@ void T_Scroll(scroll_t *s) sector_t *psec; psec = sectors + sect; + // Find the FOF corresponding to the control linedef + for (rover = psec->ffloors; rover; rover = rover->next) + { + if (rover->master == sec->lines[i]) + break; + } + + if (!rover) // This should be impossible, but don't complain if it is the case somehow + continue; + + if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there + continue; + for (node = psec->touching_thinglist; node; node = node->m_thinglist_next) { thing = node->m_thing; @@ -6732,6 +6746,19 @@ void T_Scroll(scroll_t *s) sector_t *psec; psec = sectors + sect; + // Find the FOF corresponding to the control linedef + for (rover = psec->ffloors; rover; rover = rover->next) + { + if (rover->master == sec->lines[i]) + break; + } + + if (!rover) // This should be impossible, but don't complain if it is the case somehow + continue; + + if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there + continue; + for (node = psec->touching_thinglist; node; node = node->m_thinglist_next) { thing = node->m_thing; From 847f8b4ef0e195ed826be4b2ec0370bad047d337 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 22 May 2018 11:04:28 +0100 Subject: [PATCH 137/212] * CEZ decorations! * Moved a bunch of stuff that had no business being in mapthing spawns into mobj spawns. --- src/dehacked.c | 36 +++- src/hardware/hw_light.c | 8 + src/info.c | 442 +++++++++++++++++++++++++++++++++++----- src/info.h | 44 +++- src/p_enemy.c | 15 +- src/p_mobj.c | 112 +++++++--- 6 files changed, 548 insertions(+), 109 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index e07fdb89d..bfcde5f50 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4814,14 +4814,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CEZCHAIN", // Flame - "S_FLAME1", - "S_FLAME2", - "S_FLAME3", - "S_FLAME4", - "S_FLAME5", - "S_FLAME6", + "S_FLAME", "S_FLAMEPARTICLE", - "S_FLAMEREST", // Eggman Statue @@ -4887,7 +4881,19 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BIGFIREBAR15", "S_BIGFIREBAR16", - "S_CEZFLOWER1", + "S_CEZFLOWER", + "S_CEZPOLE", + "S_CEZBANNER", + "S_PINETREE", + "S_CEZBUSH1", + "S_CEZBUSH2", + "S_CANDLE", + "S_CANDLEPRICKET", + "S_FLAMEHOLDER", + "S_FIRETORCH", + "S_WAVINGFLAG", + "S_WAVINGFLAGSEG", + "S_CRAWLASTATUE", // Big Tumbleweed "S_BIGTUMBLEWEED", @@ -6489,7 +6495,19 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_REDSPRINGBALL", // Red spring on a ball "MT_SMALLFIREBAR", // Small Firebar "MT_BIGFIREBAR", // Big Firebar - "MT_CEZFLOWER", + "MT_CEZFLOWER", // Flower + "MT_CEZPOLE", // Pole + "MT_CEZBANNER", // Banner + "MT_PINETREE", // Pine Tree + "MT_CEZBUSH1", // Bush 1 + "MT_CEZBUSH2", // Bush 2 + "MT_CANDLE", // Candle + "MT_CANDLEPRICKET", // Candle pricket + "MT_FLAMEHOLDER", // Flame holder + "MT_FIRETORCH", // Fire torch + "MT_WAVINGFLAG", // Waving flag + "MT_WAVINGFLAGSEG", // Waving flag segment + "MT_CRAWLASTATUE", // Crawla statue // Arid Canyon Scenery "MT_BIGTUMBLEWEED", diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 2f8ab99cb..133ff96cb 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -324,6 +324,14 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_RSPB &lspr[REDBALL_L], // SPR_SFBR &lspr[REDBALL_L], // SPR_BFBR + &lspr[NOLIGHT], // SPR_BANR + &lspr[NOLIGHT], // SPR_PINE + &lspr[NOLIGHT], // SPR_CEZB + &lspr[REDBALL_L], // SPR_CNDL + &lspr[NOLIGHT], // SPR_FLMH + &lspr[REDBALL_L], // SPR_CTRC + &lspr[NOLIGHT], // SPR_CFLG + &lspr[NOLIGHT], // SPR_CSTA // Arid Canyon Scenery &lspr[NOLIGHT], // SPR_BTBL diff --git a/src/info.c b/src/info.c index cd26421ca..6525d8789 100644 --- a/src/info.c +++ b/src/info.c @@ -218,6 +218,14 @@ char sprnames[NUMSPRITES + 1][5] = "RSPB", // Red spring on a ball "SFBR", // Small Firebar "BFBR", // Big Firebar + "BANR", // Banner + "PINE", // Pine Tree + "CEZB", // Bush + "CNDL", // Candle/pricket + "FLMH", // Flame holder + "CTRC", // Fire torch + "CFLG", // Waving flag/segment + "CSTA", // Crawla statue // Arid Canyon Scenery "BTBL", // Big tumbleweed @@ -2034,15 +2042,9 @@ state_t states[NUMSTATES] = {SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN // Flame - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20, 3, {A_FlameParticle}, 3, FRACUNIT/2, S_FLAME2}, // S_FLAME1 - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|1, 3, {NULL}, 0, 0 , S_FLAME3}, // S_FLAME2 - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|2, 3, {A_FlameParticle}, 3, FRACUNIT/2, S_FLAME4}, // S_FLAME3 - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|3, 3, {NULL}, 0, 0 , S_FLAME5}, // S_FLAME4 - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|4, 3, {A_FlameParticle}, 3, FRACUNIT/2, S_FLAME6}, // S_FLAME5 - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|5, 3, {NULL}, 0, 0 , S_FLAME1}, // S_FLAME6 - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS10|6, 24, {NULL}, 0, 0 , S_NULL}, // S_FLAMEPARTICLE - - {SPR_FLAM, FF_FULLBRIGHT|FF_TRANS20|FF_ANIMATE, -1, {NULL}, 5, 3, S_FLAME2}, // S_FLAMEREST + {SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE, 3*8, {A_FlameParticle}, 7, 3, S_FLAME}, // S_FLAME + {SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE|8, TICRATE, {NULL}, 3, 3, S_NULL}, // S_FLAMEPARTICLE + {SPR_FLAM, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 7, 3, S_NULL}, // S_FLAMEREST // Eggman statue {SPR_ESTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGSTATUE1 @@ -2072,43 +2074,61 @@ state_t states[NUMSTATES] = {SPR_RSPB, 1, 1, {NULL}, 0, 0, S_REDSPRINGBALL}, // S_REDSPRINGBALL5 // Small Firebar - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR2}, // S_SMALLFIREBAR1 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 1, 1, {NULL}, 0, 0, S_SMALLFIREBAR3}, // S_SMALLFIREBAR2 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 2, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR4}, // S_SMALLFIREBAR3 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 3, 1, {NULL}, 0, 0, S_SMALLFIREBAR5}, // S_SMALLFIREBAR4 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 4, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR6}, // S_SMALLFIREBAR5 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 5, 1, {NULL}, 0, 0, S_SMALLFIREBAR7}, // S_SMALLFIREBAR6 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 6, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR8}, // S_SMALLFIREBAR7 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 7, 1, {NULL}, 0, 0, S_SMALLFIREBAR9}, // S_SMALLFIREBAR8 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 8, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR10}, // S_SMALLFIREBAR9 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20| 9, 1, {NULL}, 0, 0, S_SMALLFIREBAR11}, // S_SMALLFIREBAR10 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20|10, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR12}, // S_SMALLFIREBAR11 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20|11, 1, {NULL}, 0, 0, S_SMALLFIREBAR13}, // S_SMALLFIREBAR12 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20|12, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR14}, // S_SMALLFIREBAR13 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20|13, 1, {NULL}, 0, 0, S_SMALLFIREBAR15}, // S_SMALLFIREBAR14 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20|14, 1, {A_FlameParticle}, 3, FRACUNIT/3, S_SMALLFIREBAR16}, // S_SMALLFIREBAR15 - {SPR_SFBR, FF_FULLBRIGHT|FF_TRANS20|15, 1, {NULL}, 0, 0, S_SMALLFIREBAR1}, // S_SMALLFIREBAR16 + {SPR_SFBR, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SMALLFIREBAR2}, // S_SMALLFIREBAR1 + {SPR_SFBR, FF_FULLBRIGHT| 1, 1, {NULL}, 0, 0, S_SMALLFIREBAR3}, // S_SMALLFIREBAR2 + {SPR_SFBR, FF_FULLBRIGHT| 2, 1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR4}, // S_SMALLFIREBAR3 + {SPR_SFBR, FF_FULLBRIGHT| 3, 1, {NULL}, 0, 0, S_SMALLFIREBAR5}, // S_SMALLFIREBAR4 + {SPR_SFBR, FF_FULLBRIGHT| 4, 1, {NULL}, 0, 0, S_SMALLFIREBAR6}, // S_SMALLFIREBAR5 + {SPR_SFBR, FF_FULLBRIGHT| 5, 1, {NULL}, 0, 0, S_SMALLFIREBAR7}, // S_SMALLFIREBAR6 + {SPR_SFBR, FF_FULLBRIGHT| 6, 1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR8}, // S_SMALLFIREBAR7 + {SPR_SFBR, FF_FULLBRIGHT| 7, 1, {NULL}, 0, 0, S_SMALLFIREBAR9}, // S_SMALLFIREBAR8 + {SPR_SFBR, FF_FULLBRIGHT| 8, 1, {NULL}, 0, 0, S_SMALLFIREBAR10}, // S_SMALLFIREBAR9 + {SPR_SFBR, FF_FULLBRIGHT| 9, 1, {NULL}, 0, 0, S_SMALLFIREBAR11}, // S_SMALLFIREBAR10 + {SPR_SFBR, FF_FULLBRIGHT|10, 1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR12}, // S_SMALLFIREBAR11 + {SPR_SFBR, FF_FULLBRIGHT|11, 1, {NULL}, 0, 0, S_SMALLFIREBAR13}, // S_SMALLFIREBAR12 + {SPR_SFBR, FF_FULLBRIGHT|12, 1, {NULL}, 0, 0, S_SMALLFIREBAR14}, // S_SMALLFIREBAR13 + {SPR_SFBR, FF_FULLBRIGHT|13, 1, {NULL}, 0, 0, S_SMALLFIREBAR15}, // S_SMALLFIREBAR14 + {SPR_SFBR, FF_FULLBRIGHT|14, 1, {A_FlameParticle}, 0, 0, S_SMALLFIREBAR16}, // S_SMALLFIREBAR15 + {SPR_SFBR, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_SMALLFIREBAR1}, // S_SMALLFIREBAR16 // Big Firebar - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR2}, // S_BIGFIREBAR1 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 1, 1, {NULL}, 0, 0, S_BIGFIREBAR3}, // S_BIGFIREBAR2 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 2, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR4}, // S_BIGFIREBAR3 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 3, 1, {NULL}, 0, 0, S_BIGFIREBAR5}, // S_BIGFIREBAR4 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 4, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR6}, // S_BIGFIREBAR5 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 5, 1, {NULL}, 0, 0, S_BIGFIREBAR7}, // S_BIGFIREBAR6 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 6, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR8}, // S_BIGFIREBAR7 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 7, 1, {NULL}, 0, 0, S_BIGFIREBAR9}, // S_BIGFIREBAR8 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 8, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR10}, // S_BIGFIREBAR9 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20| 9, 1, {NULL}, 0, 0, S_BIGFIREBAR11}, // S_BIGFIREBAR10 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20|10, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR12}, // S_BIGFIREBAR11 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20|11, 1, {NULL}, 0, 0, S_BIGFIREBAR13}, // S_BIGFIREBAR12 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20|12, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR14}, // S_BIGFIREBAR13 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20|13, 1, {NULL}, 0, 0, S_BIGFIREBAR15}, // S_BIGFIREBAR14 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20|14, 1, {A_FlameParticle}, 3, FRACUNIT/2, S_BIGFIREBAR16}, // S_BIGFIREBAR15 - {SPR_BFBR, FF_FULLBRIGHT|FF_TRANS20|15, 1, {NULL}, 0, 0, S_BIGFIREBAR1}, // S_BIGFIREBAR16 + {SPR_BFBR, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGFIREBAR2}, // S_BIGFIREBAR1 + {SPR_BFBR, FF_FULLBRIGHT| 1, 1, {NULL}, 0, 0, S_BIGFIREBAR3}, // S_BIGFIREBAR2 + {SPR_BFBR, FF_FULLBRIGHT| 2, 1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR4}, // S_BIGFIREBAR3 + {SPR_BFBR, FF_FULLBRIGHT| 3, 1, {NULL}, 0, 0, S_BIGFIREBAR5}, // S_BIGFIREBAR4 + {SPR_BFBR, FF_FULLBRIGHT| 4, 1, {NULL}, 0, 0, S_BIGFIREBAR6}, // S_BIGFIREBAR5 + {SPR_BFBR, FF_FULLBRIGHT| 5, 1, {NULL}, 0, 0, S_BIGFIREBAR7}, // S_BIGFIREBAR6 + {SPR_BFBR, FF_FULLBRIGHT| 6, 1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR8}, // S_BIGFIREBAR7 + {SPR_BFBR, FF_FULLBRIGHT| 7, 1, {NULL}, 0, 0, S_BIGFIREBAR9}, // S_BIGFIREBAR8 + {SPR_BFBR, FF_FULLBRIGHT| 8, 1, {NULL}, 0, 0, S_BIGFIREBAR10}, // S_BIGFIREBAR9 + {SPR_BFBR, FF_FULLBRIGHT| 9, 1, {NULL}, 0, 0, S_BIGFIREBAR11}, // S_BIGFIREBAR10 + {SPR_BFBR, FF_FULLBRIGHT|10, 1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR12}, // S_BIGFIREBAR11 + {SPR_BFBR, FF_FULLBRIGHT|11, 1, {NULL}, 0, 0, S_BIGFIREBAR13}, // S_BIGFIREBAR12 + {SPR_BFBR, FF_FULLBRIGHT|12, 1, {NULL}, 0, 0, S_BIGFIREBAR14}, // S_BIGFIREBAR13 + {SPR_BFBR, FF_FULLBRIGHT|13, 1, {NULL}, 0, 0, S_BIGFIREBAR15}, // S_BIGFIREBAR14 + {SPR_BFBR, FF_FULLBRIGHT|14, 1, {A_FlameParticle}, 0, 0, S_BIGFIREBAR16}, // S_BIGFIREBAR15 + {SPR_BFBR, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_BIGFIREBAR1}, // S_BIGFIREBAR16 - // CEZ Flower - {SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER1 + {SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER + {SPR_BANR, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE + + {SPR_BANR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER + + {SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE + {SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH1 + {SPR_CEZB, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH2 + + {SPR_CNDL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_CANDLE + {SPR_CNDL, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_CANDLEPRICKET + + {SPR_FLMH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FLAMEHOLDER + + {SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_NULL}, // S_FIRETORCH + + {SPR_CFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG + {SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG + + {SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE // Big Tumbleweed {SPR_BTBL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGTUMBLEWEED @@ -9554,7 +9574,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FLAME 1101, // doomednum - S_FLAME1, // spawnstate + S_FLAME, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -9839,8 +9859,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 24*FRACUNIT, // speed - 24*FRACUNIT, // radius - 32*FRACUNIT, // height + 17*FRACUNIT, // radius + 34*FRACUNIT, // height 0, // display offset 100, // mass 1, // damage @@ -9866,8 +9886,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 48*FRACUNIT, // speed - 48*FRACUNIT, // radius - 96*FRACUNIT, // height + 34*FRACUNIT, // radius + 68*FRACUNIT, // height 0, // display offset 100, // mass 1, // damage @@ -10040,7 +10060,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_CEZFLOWER 1103, // doomednum - S_CEZFLOWER1, // spawnstate + S_CEZFLOWER, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10065,6 +10085,330 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_CEZPOLE + 1113, // doomednum + S_CEZPOLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 40*FRACUNIT, // radius + 224*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CEZBANNER + -1, // doomednum + S_CEZBANNER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 40*FRACUNIT, // radius + 224*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PINETREE + 1041, // doomednum + S_PINETREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 628*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_SOLID|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CEZBUSH1 + 1042, // doomednum + S_CEZBUSH1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CEZBUSH2 + 1043, // doomednum + S_CEZBUSH2, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 3*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CANDLE + 3330, // doomednum + S_CANDLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CANDLEPRICKET + 3332, // doomednum + S_CANDLEPRICKET, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8*FRACUNIT, // radius + 176*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_FLAMEHOLDER + 3335, // doomednum + S_FLAMEHOLDER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 24*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_FIRETORCH + 3336, // doomednum + S_FIRETORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 24*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_WAVINGFLAG + 1329, // doomednum + S_WAVINGFLAG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 4*FRACUNIT, // radius + 104*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_PUSHABLE, // flags + S_NULL // raisestate + }, + + { // MT_WAVINGFLAGSEG + -1, // doomednum + S_WAVINGFLAGSEG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 4*FRACUNIT, // radius + 1, // height -- this is not a typo + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CRAWLASTATUE + 1120, // doomednum + S_CRAWLASTATUE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SOLID|MF_PUSHABLE, // flags + S_NULL // raisestate + }, + { // MT_BIGTUMBLEWEED 1200, // doomednum S_BIGTUMBLEWEED,// spawnstate diff --git a/src/info.h b/src/info.h index fc2c7b9c8..b72a5b392 100644 --- a/src/info.h +++ b/src/info.h @@ -431,6 +431,14 @@ typedef enum sprite SPR_RSPB, // Red spring on a ball SPR_SFBR, // Small Firebar SPR_BFBR, // Big Firebar + SPR_BANR, // Banner/pole + SPR_PINE, // Pine Tree + SPR_CEZB, // Bush + SPR_CNDL, // Candle/pricket + SPR_FLMH, // Flame holder + SPR_CTRC, // Fire torch + SPR_CFLG, // Waving flag/segment + SPR_CSTA, // Crawla statue // Arid Canyon Scenery SPR_BTBL, // Big tumbleweed @@ -2156,14 +2164,8 @@ typedef enum state S_CEZCHAIN, // Flame - S_FLAME1, - S_FLAME2, - S_FLAME3, - S_FLAME4, - S_FLAME5, - S_FLAME6, + S_FLAME, S_FLAMEPARTICLE, - S_FLAMEREST, // Eggman Statue @@ -2229,7 +2231,19 @@ typedef enum state S_BIGFIREBAR15, S_BIGFIREBAR16, - S_CEZFLOWER1, + S_CEZFLOWER, + S_CEZPOLE, + S_CEZBANNER, + S_PINETREE, + S_CEZBUSH1, + S_CEZBUSH2, + S_CANDLE, + S_CANDLEPRICKET, + S_FLAMEHOLDER, + S_FIRETORCH, + S_WAVINGFLAG, + S_WAVINGFLAGSEG, + S_CRAWLASTATUE, // Big Tumbleweed S_BIGTUMBLEWEED, @@ -3851,7 +3865,19 @@ typedef enum mobj_type MT_REDSPRINGBALL, // Red spring on a ball MT_SMALLFIREBAR, // Small Firebar MT_BIGFIREBAR, // Big Firebar - MT_CEZFLOWER, + MT_CEZFLOWER, // Flower + MT_CEZPOLE, // Pole + MT_CEZBANNER, // Banner + MT_PINETREE, // Pine Tree + MT_CEZBUSH1, // Bush 1 + MT_CEZBUSH2, // Bush 2 + MT_CANDLE, // Candle + MT_CANDLEPRICKET, // Candle pricket + MT_FLAMEHOLDER, // Flame holder + MT_FIRETORCH, // Fire torch + MT_WAVINGFLAG, // Waving flag + MT_WAVINGFLAGSEG, // Waving flag segment + MT_CRAWLASTATUE, // Crawla statue // Arid Canyon Scenery MT_BIGTUMBLEWEED, diff --git a/src/p_enemy.c b/src/p_enemy.c index b4a75b9de..71b15473c 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -10794,36 +10794,33 @@ void A_FlickyFlutter(mobj_t *actor) // // Description: Creates the mobj's painchance at a random position around the object's radius. // -// var1 = momz of particle. -// var2 = chance of particle spawn +// var1 = unused +// var2 = unused // void A_FlameParticle(mobj_t *actor) { mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance); fixed_t rad, hei; mobj_t *particle; - INT32 locvar1 = var1; - INT32 locvar2 = var2; + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; #ifdef HAVE_BLUA if (LUA_CallAction("A_FlameParticle", actor)) return; #endif - if (!P_RandomChance(locvar2)) - return; - if (!type) return; - rad = 2*actor->radius>>FRACBITS; + rad = actor->radius>>FRACBITS; hei = actor->height>>FRACBITS; particle = P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); P_SetThingPosition(mobj); break; + case MT_WAVINGFLAG: + { + fixed_t base = (leveltime<<(FRACBITS+1)); + mobj_t *seg = mobj->tracer, *prev = mobj; + mobj->movedir = mobj->angle + + ((((FINESINE((FixedAngle(base<<1)>>ANGLETOFINESHIFT) & FINEMASK) + + FINESINE((FixedAngle(base<<4)>>ANGLETOFINESHIFT) & FINEMASK))>>1) + + FINESINE((FixedAngle(base*9)>>ANGLETOFINESHIFT) & FINEMASK) + + FINECOSINE(((FixedAngle(base*9))>>ANGLETOFINESHIFT) & FINEMASK))<<12); //*2^12 + while (seg) + { + seg->movedir = seg->angle; + seg->angle = prev->movedir; + P_UnsetThingPosition(seg); + seg->x = prev->x + P_ReturnThrustX(prev, prev->angle, prev->radius); + seg->y = prev->y + P_ReturnThrustY(prev, prev->angle, prev->radius); + seg->z = prev->z + prev->height - (seg->scale>>1); + P_SetThingPosition(seg); + prev = seg; + seg = seg->tracer; + } + } + break; case MT_SPINCUSHION: if (mobj->target && mobj->state-states >= S_SPINCUSHION_AIM1 && mobj->state-states <= S_SPINCUSHION_AIM5) mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); @@ -8571,9 +8594,62 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->reactiontime >>= 1; } break; + case MT_THZTREE: + // Spawn the branches + P_SpawnMobjFromMobj(mobj, 1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobj->angle + ANGLE_22h; + P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobj->angle + ANGLE_157h; + P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobj->angle + ANGLE_270; + break; case MT_BIGMINE: mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; break; + case MT_CEZPOLE: + // Spawn the banner + P_SpawnMobjFromMobj(mobj, + P_ReturnThrustX(mobj, mobj->angle, 4<angle, 4<angle = mobj->angle + ANGLE_90; + break; + case MT_WAVINGFLAG: + { + mobj_t *prev = mobj, *cur; + UINT8 i; + mobj->destscale <<= 2; + P_SetScale(mobj, mobj->destscale); + for (i = 0; i <= 16; i++) // probably should be < but staying authentic to the Lua version + { + cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_WAVINGFLAGSEG); + P_SetTarget(&prev->tracer, cur); + cur->extravalue1 = i; + prev = cur; + } + } + break; + case MT_HHZTREE_TOP: + { // Spawn the branches + angle_t mobjangle = mobj->angle & (ANGLE_90-1); + mobj_t *leaf; +#define doleaf(x, y) \ + leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ + leaf->angle = mobjangle;\ + P_SetMobjState(leaf, leaf->info->seestate);\ + mobjangle += ANGLE_90 + doleaf(1*FRACUNIT, 0); + doleaf(0, 1*FRACUNIT); + doleaf(-1*FRACUNIT, 0); + doleaf(0, -1*FRACUNIT); +#undef doleaf + } + break; + case MT_JACKO1: + case MT_JACKO2: + case MT_JACKO3: + { + mobj_t *overlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, mobj); + P_SetMobjState(overlay, mobj->info->raisestate); + } + break; case MT_EGGMOBILE2: // Special condition for the 2nd boss. mobj->watertop = mobj->info->speed; @@ -10334,39 +10410,9 @@ ML_EFFECT4 : Don't clip inside the ground mobj->destscale = mobj->scale; } break; - case MT_THZTREE: - { // Spawn the branches - angle_t mobjangle = FixedAngle((mthing->angle % 113)*FRACUNIT); - P_SpawnMobjFromMobj(mobj, 1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; - P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; - P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; - } - break; - case MT_HHZTREE_TOP: - { // Spawn the branches - angle_t mobjangle; - mobj_t *leaf; - mobjangle = FixedAngle((mthing->angle % 90)*FRACUNIT); -#define doleaf(x, y) \ - leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ - leaf->angle = mobjangle;\ - P_SetMobjState(leaf, leaf->info->seestate);\ - mobjangle += ANGLE_90 - doleaf(1*FRACUNIT, 0); - doleaf(0, 1*FRACUNIT); - doleaf(-1*FRACUNIT, 0); - doleaf(0, -1*FRACUNIT); -#undef doleaf - } - break; - case MT_JACKO1: - case MT_JACKO2: - case MT_JACKO3: - { - mobj_t *overlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&overlay->target, mobj); - P_SetMobjState(overlay, mobj->info->raisestate); - } + case MT_FLAMEHOLDER: + if (!(mthing->options & MTF_OBJECTSPECIAL)) // Spawn the fire + P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); break; case MT_SMASHINGSPIKEBALL: if (mthing->angle > 0) From dbcd259bd6225b31ea81c3adb8b4b2820a7d4e48 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 22 May 2018 23:02:54 +0100 Subject: [PATCH 138/212] * New Egg Guard behaviour! * Fix the thing I mistakenly messed up with all of the things I moved out of P_SpawnMapThing without good reason to. --- src/p_enemy.c | 98 +++++++++++++++++++++++++++++++++------------------ src/p_inter.c | 25 +++++-------- src/p_mobj.c | 68 ++++++++++++++++++----------------- 3 files changed, 108 insertions(+), 83 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 71b15473c..cb6559e7b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -6862,47 +6862,77 @@ void A_GuardChase(mobj_t *actor) if (actor->reactiontime) actor->reactiontime--; - if ((!actor->tracer || !actor->tracer->health) && actor->threshold != 42) + if (actor->threshold != 42) // In formation... { - P_SetTarget(&actor->tracer, NULL); - actor->threshold = 42; - P_SetMobjState(actor, actor->info->painstate); - actor->flags |= MF_SPECIAL|MF_SHOOTABLE; - return; + fixed_t speed; + + if (!actor->tracer || !actor->tracer->health) + { + P_SetTarget(&actor->tracer, NULL); + actor->threshold = 42; + P_SetMobjState(actor, actor->info->painstate); + actor->flags |= MF_SPECIAL|MF_SHOOTABLE; + return; + } + + speed = actor->extravalue1*actor->scale; + + if (actor->flags2 & MF2_AMBUSH) + speed <<= 1; + + if (speed + && !P_TryMove(actor, + actor->x + P_ReturnThrustX(actor, actor->angle, speed), + actor->y + P_ReturnThrustY(actor, actor->angle, speed), + false) + && speed > 0) // can't be the same check as previous so that P_TryMove gets to happen. + { + if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_OBJECTSPECIAL)) + actor->angle += ANGLE_90; + else if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_EXTRA)) + actor->angle -= ANGLE_90; + else + actor->angle += ANGLE_180; + } + + if (actor->extravalue1 < actor->info->speed) + actor->extravalue1++; } - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) + else // Break ranks! { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjStateNF(actor, actor->info->spawnstate); + return; + } + + // possibly choose another target + if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + && P_LookForPlayers(actor, true, false, 0)) return; // got a new target - P_SetMobjStateNF(actor, actor->info->spawnstate); - return; - } - - // possibly choose another target - if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - && P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) - { - P_NewChaseDir(actor); - actor->movecount += 5; // Increase tics before change in direction allowed. + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) + { + P_NewChaseDir(actor); + actor->movecount += 5; // Increase tics before change in direction allowed. + } } // Now that we've moved, its time for our shield to move! diff --git a/src/p_inter.c b/src/p_inter.c index 8de008570..cb55fa04e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1406,23 +1406,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; case MT_EGGSHIELD: { - fixed_t touchx, touchy, touchspeed; - angle_t angle; - - if (P_AproxDistance(toucher->x-special->x, toucher->y-special->y) > - P_AproxDistance((toucher->x-toucher->momx)-special->x, (toucher->y-toucher->momy)-special->y)) - { - touchx = toucher->x + toucher->momx; - touchy = toucher->y + toucher->momy; - } - else - { - touchx = toucher->x; - touchy = toucher->y; - } - - angle = R_PointToAngle2(special->x, special->y, touchx, touchy) - special->angle; - touchspeed = P_AproxDistance(toucher->momx, toucher->momy); + angle_t angle = R_PointToAngle2(special->x, special->y, toucher->x, toucher->y) - special->angle; + fixed_t touchspeed = P_AproxDistance(toucher->momx, toucher->momy); + if (touchspeed < special->scale) + touchspeed = special->scale; // Blocked by the shield? if (!(angle > ANGLE_90 && angle < ANGLE_270)) @@ -1439,6 +1426,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Play a bounce sound? S_StartSound(toucher, special->info->painsound); + + // experimental bounce + if (special->target) + special->target->extravalue1 = -special->target->info->speed; return; } else if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) diff --git a/src/p_mobj.c b/src/p_mobj.c index 6c9ecf516..af61a8896 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8594,22 +8594,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->reactiontime >>= 1; } break; - case MT_THZTREE: - // Spawn the branches - P_SpawnMobjFromMobj(mobj, 1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobj->angle + ANGLE_22h; - P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobj->angle + ANGLE_157h; - P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobj->angle + ANGLE_270; - break; case MT_BIGMINE: mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; break; - case MT_CEZPOLE: - // Spawn the banner - P_SpawnMobjFromMobj(mobj, - P_ReturnThrustX(mobj, mobj->angle, 4<angle, 4<angle = mobj->angle + ANGLE_90; - break; case MT_WAVINGFLAG: { mobj_t *prev = mobj, *cur; @@ -8625,22 +8612,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } } break; - case MT_HHZTREE_TOP: - { // Spawn the branches - angle_t mobjangle = mobj->angle & (ANGLE_90-1); - mobj_t *leaf; -#define doleaf(x, y) \ - leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ - leaf->angle = mobjangle;\ - P_SetMobjState(leaf, leaf->info->seestate);\ - mobjangle += ANGLE_90 - doleaf(1*FRACUNIT, 0); - doleaf(0, 1*FRACUNIT); - doleaf(-1*FRACUNIT, 0); - doleaf(0, -1*FRACUNIT); -#undef doleaf - } - break; case MT_JACKO1: case MT_JACKO2: case MT_JACKO3: @@ -10410,6 +10381,39 @@ ML_EFFECT4 : Don't clip inside the ground mobj->destscale = mobj->scale; } break; + case MT_THZTREE: + { // Spawn the branches + angle_t mobjangle = FixedAngle((mthing->angle % 113)<angle = mobjangle + ANGLE_22h; + P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; + P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; + } + break; + case MT_CEZPOLE: + { // Spawn the banner + angle_t mobjangle = FixedAngle(mthing->angle<angle = mobjangle + ANGLE_90; + } + break; + case MT_HHZTREE_TOP: + { // Spawn the branches + angle_t mobjangle = FixedAngle(mthing->angle<angle = mobjangle;\ + P_SetMobjState(leaf, leaf->info->seestate);\ + mobjangle += ANGLE_90 + doleaf(1*FRACUNIT, 0); + doleaf(0, 1*FRACUNIT); + doleaf(-1*FRACUNIT, 0); + doleaf(0, -1*FRACUNIT); +#undef doleaf + } + break; case MT_FLAMEHOLDER: if (!(mthing->options & MTF_OBJECTSPECIAL)) // Spawn the fire P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); @@ -10459,7 +10463,7 @@ ML_EFFECT4 : Don't clip inside the ground mobj_t *elecmobj; elecmobj = P_SpawnMobj(x, y, z, MT_CYBRAKDEMON_ELECTRIC_BARRIER); P_SetTarget(&elecmobj->target, mobj); - elecmobj->angle = FixedAngle(mthing->angle*FRACUNIT);; + elecmobj->angle = FixedAngle(mthing->angle<destscale = mobj->scale*2; P_SetScale(elecmobj, elecmobj->destscale); } @@ -10531,7 +10535,7 @@ ML_EFFECT4 : Don't clip inside the ground // spawn base { - const angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); // the mobj's own angle hasn't been set quite yet so... + const angle_t mobjangle = FixedAngle(mthing->angle<radius - mobj->scale; mobj_t *base = P_SpawnMobj( mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), @@ -10599,7 +10603,7 @@ ML_EFFECT4 : Don't clip inside the ground } if (doangle) - mobj->angle = FixedAngle(mthing->angle*FRACUNIT); + mobj->angle = FixedAngle(mthing->angle< Date: Thu, 24 May 2018 01:40:57 +0100 Subject: [PATCH 139/212] * Castlebot Facestabbers. * Facestabber statues, of both the suspicious and non-suspicious kind. * New object type for the end of grabbable chains. * I moved my compilation .bat file to my Releases folder, so it should .gitignore .bat's. * Random extra stuff. --- bin/Mingw/Release/.gitignore | 1 + src/dehacked.c | 18 +- src/hardware/hw_light.c | 2 + src/info.c | 220 +- src/info.h | 20 +- src/p_enemy.c | 22949 +++++++++++++++++---------------- src/p_inter.c | 7 +- src/p_mobj.c | 49 +- src/sounds.c | 4 +- 9 files changed, 11846 insertions(+), 11424 deletions(-) diff --git a/bin/Mingw/Release/.gitignore b/bin/Mingw/Release/.gitignore index 834f313e3..3458ff764 100644 --- a/bin/Mingw/Release/.gitignore +++ b/bin/Mingw/Release/.gitignore @@ -1,3 +1,4 @@ *.exe *.mo r_opengl.dll +*.bat diff --git a/src/dehacked.c b/src/dehacked.c index bfcde5f50..b52c79461 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1628,6 +1628,10 @@ static actionpointer_t actionpointers[] = {{A_Look}, "A_LOOK"}, {{A_Chase}, "A_CHASE"}, {{A_FaceStabChase}, "A_FACESTABCHASE"}, + {{A_FaceStabRev}, "A_FACESTABREV"}, + {{A_FaceStabHurl}, "A_FACESTABHURL"}, + {{A_FaceStabMiss}, "A_FACESTABMISS"}, + {{A_StatueBurst}, "A_STATUEBURST"}, {{A_FaceTarget}, "A_FACETARGET"}, {{A_FaceTracer}, "A_FACETRACER"}, {{A_Scream}, "A_SCREAM"}, @@ -3774,6 +3778,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FACESTABBER_DIE1", "S_FACESTABBER_DIE2", "S_FACESTABBER_DIE3", + "S_FACESTABBERSPEAR", // Egg Guard "S_EGGGUARD_STND", @@ -4830,6 +4835,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BIGMACECHAIN", "S_SMALLMACE", "S_BIGMACE", + "S_SMALLGRABCHAIN", + "S_BIGGRABCHAIN", // Yellow spring on a ball "S_YELLOWSPRINGBALL", @@ -4894,6 +4901,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_WAVINGFLAG", "S_WAVINGFLAGSEG", "S_CRAWLASTATUE", + "S_FACESTABBERSTATUE", + "S_SUSPICIOUSFACESTABBERSTATUE_WAIT", + "S_SUSPICIOUSFACESTABBERSTATUE_BURST1", + "S_SUSPICIOUSFACESTABBERSTATUE_BURST2", // Big Tumbleweed "S_BIGTUMBLEWEED", @@ -6235,7 +6246,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_POINTY", // Pointy "MT_POINTYBALL", // Pointy Ball "MT_ROBOHOOD", // Robo-Hood - "MT_FACESTABBER", // CastleBot FaceStabber + "MT_FACESTABBER", // Castlebot Facestabber + "MT_FACESTABBERSPEAR", // Castlebot Facestabber spear aura "MT_EGGGUARD", // Egg Guard "MT_EGGSHIELD", // Egg Guard's shield "MT_GSNAPPER", // Green Snapper @@ -6491,6 +6503,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BIGMACECHAIN", // Big Mace Chain "MT_SMALLMACE", // Small Mace "MT_BIGMACE", // Big Mace + "MT_SMALLGRABCHAIN", // Small Grab Chain + "MT_BIGGRABCHAIN", // Big Grab Chain "MT_YELLOWSPRINGBALL", // Yellow spring on a ball "MT_REDSPRINGBALL", // Red spring on a ball "MT_SMALLFIREBAR", // Small Firebar @@ -6508,6 +6522,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_WAVINGFLAG", // Waving flag "MT_WAVINGFLAGSEG", // Waving flag segment "MT_CRAWLASTATUE", // Crawla statue + "MT_FACESTABBERSTATUE", // Facestabber statue + "MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking: // Arid Canyon Scenery "MT_BIGTUMBLEWEED", diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 133ff96cb..fbec957f7 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -168,6 +168,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_PNTY &lspr[NOLIGHT], // SPR_ARCH &lspr[NOLIGHT], // SPR_CBFS + &lspr[JETLIGHT_L], // SPR_STAB &lspr[NOLIGHT], // SPR_SPSH &lspr[NOLIGHT], // SPR_ESHI &lspr[NOLIGHT], // SPR_GSNP @@ -332,6 +333,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[REDBALL_L], // SPR_CTRC &lspr[NOLIGHT], // SPR_CFLG &lspr[NOLIGHT], // SPR_CSTA + &lspr[NOLIGHT], // SPR_CBBS // Arid Canyon Scenery &lspr[NOLIGHT], // SPR_BTBL diff --git a/src/info.c b/src/info.c index 6525d8789..57c3c0a04 100644 --- a/src/info.c +++ b/src/info.c @@ -56,6 +56,7 @@ char sprnames[NUMSPRITES + 1][5] = "PNTY", // Pointy "ARCH", // Robo-Hood "CBFS", // Castlebot Facestabber + "STAB", // Castlebot Facestabber spear aura "SPSH", // Egg Guard "ESHI", // Egg Guard's shield "GSNP", // Green Snapper @@ -226,6 +227,7 @@ char sprnames[NUMSPRITES + 1][5] = "CTRC", // Fire torch "CFLG", // Waving flag/segment "CSTA", // Crawla statue + "CBBS", // Facestabber statue // Arid Canyon Scenery "BTBL", // Big tumbleweed @@ -986,21 +988,23 @@ state_t states[NUMSTATES] = {SPR_ARCH, 1, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP2 {SPR_ARCH, 0, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_FALL}, // S_ROBOHOOD_FALL - // CastleBot FaceStabber - {SPR_CBFS, 0, 1, {A_FaceStabChase}, 0, 0, S_FACESTABBER_STND2}, // S_FACESTABBER_STND1 - {SPR_CBFS, 1, 1, {A_FaceStabChase}, 0, 0, S_FACESTABBER_STND3}, // S_FACESTABBER_STND2 - {SPR_CBFS, 2, 1, {A_FaceStabChase}, 0, 0, S_FACESTABBER_STND4}, // S_FACESTABBER_STND3 - {SPR_CBFS, 3, 1, {A_FaceStabChase}, 0, 0, S_FACESTABBER_STND5}, // S_FACESTABBER_STND4 - {SPR_CBFS, 4, 1, {A_FaceStabChase}, 0, 0, S_FACESTABBER_STND6}, // S_FACESTABBER_STND5 - {SPR_CBFS, 5, 1, {A_FaceStabChase}, 0, 0, S_FACESTABBER_STND1}, // S_FACESTABBER_STND6 - {SPR_CBFS, 6, 14, {A_PlayActiveSound}, 0, 0, S_FACESTABBER_CHARGE2}, // S_FACESTABBER_CHARGE1 - {SPR_CBFS, 6, 0, {A_PlayAttackSound}, 0, 0, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE2 - {SPR_CBFS, 6, 0, {A_FaceTarget}, 0, 0, S_FACESTABBER_CHARGE4}, // S_FACESTABBER_CHARGE3 - {SPR_CBFS, 7, 35, {A_Thrust}, 20, 1, S_FACESTABBER_STND1}, // S_FACESTABBER_CHARGE4 - {SPR_CBFS, 0, 35, {A_Pain}, 0, 0, S_FACESTABBER_STND1}, // S_FACESTABBER_PAIN - {SPR_CBFS, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE2}, // S_FACESTABBER_DIE1 - {SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE3}, // S_FACESTABBER_DIE2 - {SPR_NULL, 0, 0, {A_Repeat}, 7, S_FACESTABBER_DIE1, S_XPLD_FLICKY}, // S_FACESTABBER_DIE3 + // Castlebot Facestabber + {SPR_CBFS, 0, 1, {A_Chase}, 0, 0, S_FACESTABBER_STND2}, // S_FACESTABBER_STND1 + {SPR_CBFS, 1, 1, {A_Chase}, 0, 0, S_FACESTABBER_STND3}, // S_FACESTABBER_STND2 + {SPR_CBFS, 2, 1, {A_Chase}, 0, 0, S_FACESTABBER_STND4}, // S_FACESTABBER_STND3 + {SPR_CBFS, 3, 1, {A_Chase}, 0, 0, S_FACESTABBER_STND5}, // S_FACESTABBER_STND4 + {SPR_CBFS, 4, 1, {A_Chase}, 0, 0, S_FACESTABBER_STND6}, // S_FACESTABBER_STND5 + {SPR_CBFS, 5, 1, {A_Chase}, 0, 0, S_FACESTABBER_STND1}, // S_FACESTABBER_STND6 + {SPR_CBFS, 0, 1, {A_FaceStabRev}, 20, S_FACESTABBER_CHARGE2, S_FACESTABBER_CHARGE1}, // S_FACESTABBER_CHARGE1 + {SPR_CBFS, 0, 0, {A_FaceTarget}, 0, 0, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE2 + {SPR_CBFS, 7, 1, {A_FaceStabHurl}, 6, S_FACESTABBER_CHARGE4, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE3 + {SPR_CBFS, 7, 1, {A_FaceStabMiss}, 0, S_FACESTABBER_STND1, S_FACESTABBER_CHARGE4}, // S_FACESTABBER_CHARGE4 + {SPR_CBFS, 0, 35, {A_Pain}, 0, 0, S_FACESTABBER_STND1}, // S_FACESTABBER_PAIN + {SPR_CBFS, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE2}, // S_FACESTABBER_DIE1 + {SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE3}, // S_FACESTABBER_DIE2 + {SPR_NULL, 0, 0, {A_Repeat}, 7, S_FACESTABBER_DIE1, S_XPLD_FLICKY}, // S_FACESTABBER_DIE3 + + {SPR_STAB, FF_PAPERSPRITE|FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSPEAR // Egg Guard {SPR_SPSH, 0, 1, {A_Look}, 0, 0, S_EGGGUARD_STND}, // S_EGGGUARD_STND @@ -1016,7 +1020,6 @@ state_t states[NUMSTATES] = {SPR_SPSH, 10, 1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN4}, // S_EGGGUARD_RUN3 {SPR_SPSH, 11, 1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN1}, // S_EGGGUARD_RUN4 - // Egg Shield for Egg Guard {SPR_ESHI, 0, 8, {A_EggShield}, 0, 0, S_EGGSHIELD}, // S_EGGSHIELD // Green Snapper @@ -1435,12 +1438,12 @@ state_t states[NUMSTATES] = {SPR_RCKT, 2 + FF_FULLBRIGHT, 6, {A_NapalmScatter}, MT_CYBRAKDEMON_NAPALM_FLAMES + (6<<16), 32 + (16<<16), S_CYBRAKDEMONMISSILE_EXPLODE3}, // S_CYBRAKDEMONMISSILE_EXPLODE2 {SPR_RCKT, 3 + FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONMISSILE_EXPLODE3 - {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1 - {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2 - {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3 - {SPR_FLME, FF_TRANS20|FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE + {SPR_FLME, FF_FULLBRIGHT , 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY2}, // S_CYBRAKDEMONFLAMESHOT_FLY1 + {SPR_FLME, FF_FULLBRIGHT|1, 15, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY2 + {SPR_FLME, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3 + {SPR_FLME, FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE - {SPR_FLAM, FF_TRANS20|FF_FULLBRIGHT|5, 3, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST + {SPR_FLAM, FF_FULLBRIGHT, 0, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST {SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1 {SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2 @@ -2054,10 +2057,12 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, -1, {A_SlingAppear}, 0, 0, S_NULL}, // S_SLING2 // CEZ maces and chains - {SPR_SMCH, 0, -1, {NULL}, 0, 0, S_SMALLMACECHAIN}, // S_SMALLMACECHAIN - {SPR_BMCH, 0, -1, {NULL}, 0, 0, S_BIGMACECHAIN}, // S_BIGMACECHAIN - {SPR_SMCE, 0, -1, {NULL}, 0, 0, S_SMALLMACE}, // S_SMALLMACE - {SPR_BMCE, 0, -1, {NULL}, 0, 0, S_BIGMACE}, // S_BIGMACE + {SPR_SMCH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLMACECHAIN + {SPR_BMCH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGMACECHAIN + {SPR_SMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLMACE + {SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGMACE + {SPR_SMCH, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SMALLGRABCHAIN + {SPR_BMCH, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGGRABCHAIN // Yellow spring on a ball {SPR_YSPB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YELLOWSPRINGBALL @@ -2130,6 +2135,12 @@ state_t states[NUMSTATES] = {SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE + {SPR_CBBS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSTATUE + + {SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT}, // S_SUSPICIOUSFACESTABBERSTATUE_WAIT + {SPR_CBBS, 0, 23, {NULL}, 0, 0, S_SUSPICIOUSFACESTABBERSTATUE_BURST2}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1 + {SPR_NULL, 0, 40, {A_StatueBurst}, 0, S_FACESTABBER_CHARGE2, S_NULL}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2 + // Big Tumbleweed {SPR_BTBL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGTUMBLEWEED {SPR_BTBL, 0, 5, {NULL}, 0, 0, S_BIGTUMBLEWEED_ROLL2}, // S_BIGTUMBLEWEED_ROLL1 @@ -2162,9 +2173,9 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_FLAMEJETSTART}, // S_FLAMEJETSTND {SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0, S_FLAMEJETSTOP}, // S_FLAMEJETSTART {SPR_NULL, 0, 1, {A_ToggleFlameJet}, 0, 0, S_FLAMEJETSTND}, // S_FLAMEJETSTOP - {SPR_FLME, FF_FULLBRIGHT|FF_TRANS50 , 4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1 - {SPR_FLME, FF_FULLBRIGHT|FF_TRANS60|1, 5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2 - {SPR_FLME, FF_FULLBRIGHT|FF_TRANS70|2, 11, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAME3 + {SPR_FLME, FF_FULLBRIGHT , 4, {NULL}, 0, 0, S_FLAMEJETFLAME2}, // S_FLAMEJETFLAME1 + {SPR_FLME, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_FLAMEJETFLAME3}, // S_FLAMEJETFLAME2 + {SPR_FLME, FF_FULLBRIGHT|2, 11, {NULL}, 0, 0, S_NULL}, // S_FLAMEJETFLAME3 // Spinning flame jets // A: Counter-clockwise @@ -4237,27 +4248,54 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 2, // spawnhealth S_FACESTABBER_STND1, // seestate sfx_None, // seesound - 35, // reactiontime - sfx_None, // attacksound + 70, // reactiontime + sfx_zoom, // attacksound S_FACESTABBER_PAIN, // painstate 0, // painchance sfx_dmpain, // painsound S_FACESTABBER_CHARGE1, // meleestate - S_NULL, // missilestate + S_FACESTABBER_CHARGE1, // missilestate S_FACESTABBER_DIE1, // deathstate S_NULL, // xdeathstate sfx_cybdth, // deathsound 3, // speed - 32*FRACUNIT, // radius - 64*FRACUNIT, // height + 36*FRACUNIT, // radius + 72*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage - sfx_None, // activesound - MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags + sfx_s3kc5s, // activesound + MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_SLIDEME, // flags S_NULL // raisestate }, + { // MT_FACESTABBERSPEAR + -1, // doomednum + S_FACESTABBERSPEAR, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 35, // 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 + 36*FRACUNIT, // radius + 72*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_EGGGUARD 119, // doomednum S_EGGGUARD_STND, // spawnstate @@ -9865,7 +9903,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SCENERY|MF_SPECIAL|MF_NOGRAVITY, // flags + MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -9892,7 +9930,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SCENERY|MF_SPECIAL|MF_NOGRAVITY, // flags + MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -9950,6 +9988,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SMALLGRABCHAIN + -1, // doomednum + S_SMALLGRABCHAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 24*FRACUNIT, // speed + 17*FRACUNIT, // radius + 34*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_SCENERY|MF_SPECIAL|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_BIGGRABCHAIN + -1, // doomednum + S_BIGGRABCHAIN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 48*FRACUNIT, // speed + 34*FRACUNIT, // radius + 68*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_SCENERY|MF_SPECIAL|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_YELLOWSPRINGBALL -1, // doomednum S_YELLOWSPRINGBALL, // spawnstate @@ -10409,6 +10501,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_FACESTABBERSTATUE + 1331, // doomednum + S_FACESTABBERSTATUE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 36*FRACUNIT, // radius + 72*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SOLID|MF_PUSHABLE, // flags + S_NULL // raisestate + }, + + { // MT_SUSPICIOUSFACESTABBERSTATUE + 1332, // doomednum + S_SUSPICIOUSFACESTABBERSTATUE_WAIT, // spawnstate + 1000, // spawnhealth + S_SUSPICIOUSFACESTABBERSTATUE_BURST1, // seestate + sfx_s3k6f, // seesound + 8, // 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 + 36*FRACUNIT, // radius + 72*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SOLID|MF_PUSHABLE, // flags + MT_FACESTABBER // raisestate + }, + { // MT_BIGTUMBLEWEED 1200, // doomednum S_BIGTUMBLEWEED,// spawnstate diff --git a/src/info.h b/src/info.h index b72a5b392..c75ed0e6f 100644 --- a/src/info.h +++ b/src/info.h @@ -34,6 +34,10 @@ void A_GoldMonitorSparkle(); void A_Look(); void A_Chase(); void A_FaceStabChase(); +void A_FaceStabRev(); +void A_FaceStabHurl(); +void A_FaceStabMiss(); +void A_StatueBurst(); void A_FaceTarget(); void A_FaceTracer(); void A_Scream(); @@ -269,6 +273,7 @@ typedef enum sprite SPR_PNTY, // Pointy SPR_ARCH, // Robo-Hood SPR_CBFS, // Castlebot Facestabber + SPR_STAB, // Castlebot Facestabber spear aura SPR_SPSH, // Egg Guard SPR_ESHI, // Egg Guard's shield SPR_GSNP, // Green Snapper @@ -439,6 +444,7 @@ typedef enum sprite SPR_CTRC, // Fire torch SPR_CFLG, // Waving flag/segment SPR_CSTA, // Crawla statue + SPR_CBBS, // Facestabber statue // Arid Canyon Scenery SPR_BTBL, // Big tumbleweed @@ -1107,7 +1113,7 @@ typedef enum state S_ROBOHOOD_JUMP2, S_ROBOHOOD_FALL, - // CastleBot FaceStabber + // Castlebot Facestabber S_FACESTABBER_STND1, S_FACESTABBER_STND2, S_FACESTABBER_STND3, @@ -1122,6 +1128,7 @@ typedef enum state S_FACESTABBER_DIE1, S_FACESTABBER_DIE2, S_FACESTABBER_DIE3, + S_FACESTABBERSPEAR, // Egg Guard S_EGGGUARD_STND, @@ -2180,6 +2187,8 @@ typedef enum state S_BIGMACECHAIN, S_SMALLMACE, S_BIGMACE, + S_SMALLGRABCHAIN, + S_BIGGRABCHAIN, // Yellow spring on a ball S_YELLOWSPRINGBALL, @@ -2244,6 +2253,10 @@ typedef enum state S_WAVINGFLAG, S_WAVINGFLAGSEG, S_CRAWLASTATUE, + S_FACESTABBERSTATUE, + S_SUSPICIOUSFACESTABBERSTATUE_WAIT, + S_SUSPICIOUSFACESTABBERSTATUE_BURST1, + S_SUSPICIOUSFACESTABBERSTATUE_BURST2, // Big Tumbleweed S_BIGTUMBLEWEED, @@ -3606,6 +3619,7 @@ typedef enum mobj_type MT_POINTYBALL, // Pointy Ball MT_ROBOHOOD, // Robo-Hood MT_FACESTABBER, // Castlebot Facestabber + MT_FACESTABBERSPEAR, // Castlebot Facestabber spear aura MT_EGGGUARD, // Egg Guard MT_EGGSHIELD, // Egg Guard's shield MT_GSNAPPER, // Green Snapper @@ -3861,6 +3875,8 @@ typedef enum mobj_type MT_BIGMACECHAIN, // Big Mace Chain MT_SMALLMACE, // Small Mace MT_BIGMACE, // Big Mace + MT_SMALLGRABCHAIN, // Small Grab Chain + MT_BIGGRABCHAIN, // Big Grab Chain MT_YELLOWSPRINGBALL, // Yellow spring on a ball MT_REDSPRINGBALL, // Red spring on a ball MT_SMALLFIREBAR, // Small Firebar @@ -3878,6 +3894,8 @@ typedef enum mobj_type MT_WAVINGFLAG, // Waving flag MT_WAVINGFLAGSEG, // Waving flag segment MT_CRAWLASTATUE, // Crawla statue + MT_FACESTABBERSTATUE, // Facestabber statue + MT_SUSPICIOUSFACESTABBERSTATUE, // :eggthinking: // Arid Canyon Scenery MT_BIGTUMBLEWEED, diff --git a/src/p_enemy.c b/src/p_enemy.c index cb6559e7b..b2f3ffadf 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1,11360 +1,11589 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2016 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file p_enemy.c -/// \brief Enemy thinking, AI -/// Action Pointer Functions that are associated with states/frames - -#include "doomdef.h" -#include "g_game.h" -#include "p_local.h" -#include "r_main.h" -#include "r_state.h" -#include "s_sound.h" -#include "m_random.h" -#include "m_misc.h" -#include "r_things.h" -#include "i_video.h" -#include "lua_hook.h" - -#ifdef HW3SOUND -#include "hardware/hw3sound.h" -#endif - -#ifdef HAVE_BLUA -boolean LUA_CallAction(const char *action, mobj_t *actor); -#endif - -player_t *stplyr; -INT32 var1; -INT32 var2; - -// -// P_NewChaseDir related LUT. -// -static dirtype_t opposite[] = -{ - DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, - DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR -}; - -static dirtype_t diags[] = -{ - DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST -}; - -//Real Prototypes to A_* -void A_Fall(mobj_t *actor); -void A_Look(mobj_t *actor); -void A_Chase(mobj_t *actor); -void A_FaceStabChase(mobj_t *actor); -void A_JetJawRoam(mobj_t *actor); -void A_JetJawChomp(mobj_t *actor); -void A_PointyThink(mobj_t *actor); -void A_CheckBuddy(mobj_t *actor); -void A_HoodThink(mobj_t *actor); -void A_ArrowCheck(mobj_t *actor); -void A_SnailerThink(mobj_t *actor); -void A_SharpChase(mobj_t *actor); -void A_SharpSpin(mobj_t *actor); -void A_SharpDecel(mobj_t *actor); -void A_CrushstaceanWalk(mobj_t *actor); -void A_CrushstaceanPunch(mobj_t *actor); -void A_CrushclawAim(mobj_t *actor); -void A_CrushclawLaunch(mobj_t *actor); -void A_VultureVtol(mobj_t *actor); -void A_VultureCheck(mobj_t *actor); -void A_SkimChase(mobj_t *actor); -void A_FaceTarget(mobj_t *actor); -void A_FaceTracer(mobj_t *actor); -void A_LobShot(mobj_t *actor); -void A_FireShot(mobj_t *actor); -void A_SuperFireShot(mobj_t *actor); -void A_BossFireShot(mobj_t *actor); -void A_Boss7FireMissiles(mobj_t *actor); -void A_Boss1Laser(mobj_t *actor); -void A_FocusTarget(mobj_t *actor); -void A_Boss4Reverse(mobj_t *actor); -void A_Boss4SpeedUp(mobj_t *actor); -void A_Boss4Raise(mobj_t *actor); -void A_SkullAttack(mobj_t *actor); -void A_BossZoom(mobj_t *actor); -void A_BossScream(mobj_t *actor); -void A_Scream(mobj_t *actor); -void A_Pain(mobj_t *actor); -void A_1upThinker(mobj_t *actor); -void A_MonitorPop(mobj_t *actor); -void A_GoldMonitorPop(mobj_t *actor); -void A_GoldMonitorRestore(mobj_t *actor); -void A_GoldMonitorSparkle(mobj_t *actor); -void A_Explode(mobj_t *actor); -void A_BossDeath(mobj_t *actor); -void A_CustomPower(mobj_t *actor); -void A_GiveWeapon(mobj_t *actor); -void A_RingBox(mobj_t *actor); -void A_Invincibility(mobj_t *actor); -void A_SuperSneakers(mobj_t *actor); -void A_AwardScore(mobj_t *actor); -void A_ExtraLife(mobj_t *actor); -void A_GiveShield(mobj_t *actor); -void A_GravityBox(mobj_t *actor); -void A_ScoreRise(mobj_t *actor); -void A_ParticleSpawn(mobj_t *actor); -void A_BunnyHop(mobj_t *actor); -void A_BubbleSpawn(mobj_t *actor); -void A_FanBubbleSpawn(mobj_t *actor); -void A_BubbleRise(mobj_t *actor); -void A_BubbleCheck(mobj_t *actor); -void A_AttractChase(mobj_t *actor); -void A_DropMine(mobj_t *actor); -void A_FishJump(mobj_t *actor); -void A_ThrownRing(mobj_t *actor); -void A_SetSolidSteam(mobj_t *actor); -void A_UnsetSolidSteam(mobj_t *actor); -void A_SignPlayer(mobj_t *actor); -void A_OverlayThink(mobj_t *actor); -void A_JetChase(mobj_t *actor); -void A_JetbThink(mobj_t *actor); -void A_JetgShoot(mobj_t *actor); -void A_JetgThink(mobj_t *actor); -void A_ShootBullet(mobj_t *actor); -void A_MinusDigging(mobj_t *actor); -void A_MinusPopup(mobj_t *actor); -void A_MinusCheck(mobj_t *actor); -void A_ChickenCheck(mobj_t *actor); -void A_MouseThink(mobj_t *actor); -void A_DetonChase(mobj_t *actor); -void A_CapeChase(mobj_t *actor); -void A_RotateSpikeBall(mobj_t *actor); -void A_SlingAppear(mobj_t *actor); -void A_UnidusBall(mobj_t *actor); -void A_RockSpawn(mobj_t *actor); -void A_SetFuse(mobj_t *actor); -void A_CrawlaCommanderThink(mobj_t *actor); -void A_RingExplode(mobj_t *actor); -void A_OldRingExplode(mobj_t *actor); -void A_MixUp(mobj_t *actor); -void A_RecyclePowers(mobj_t *actor); -void A_Boss2TakeDamage(mobj_t *actor); -void A_Boss7Chase(mobj_t *actor); -void A_GoopSplat(mobj_t *actor); -void A_Boss2PogoSFX(mobj_t *actor); -void A_Boss2PogoTarget(mobj_t *actor); -void A_EggmanBox(mobj_t *actor); -void A_TurretFire(mobj_t *actor); -void A_SuperTurretFire(mobj_t *actor); -void A_TurretStop(mobj_t *actor); -void A_SparkFollow(mobj_t *actor); -void A_BuzzFly(mobj_t *actor); -void A_GuardChase(mobj_t *actor); -void A_EggShield(mobj_t *actor); -void A_SetReactionTime(mobj_t *actor); -void A_Boss1Spikeballs(mobj_t *actor); -void A_Boss3TakeDamage(mobj_t *actor); -void A_Boss3Path(mobj_t *actor); -void A_LinedefExecute(mobj_t *actor); -void A_PlaySeeSound(mobj_t *actor); -void A_PlayAttackSound(mobj_t *actor); -void A_PlayActiveSound(mobj_t *actor); -void A_SmokeTrailer(mobj_t *actor); -void A_SpawnObjectAbsolute(mobj_t *actor); -void A_SpawnObjectRelative(mobj_t *actor); -void A_ChangeAngleRelative(mobj_t *actor); -void A_ChangeAngleAbsolute(mobj_t *actor); -void A_PlaySound(mobj_t *actor); -void A_FindTarget(mobj_t *actor); -void A_FindTracer(mobj_t *actor); -void A_SetTics(mobj_t *actor); -void A_SetRandomTics(mobj_t *actor); -void A_ChangeColorRelative(mobj_t *actor); -void A_ChangeColorAbsolute(mobj_t *actor); -void A_MoveRelative(mobj_t *actor); -void A_MoveAbsolute(mobj_t *actor); -void A_Thrust(mobj_t *actor); -void A_ZThrust(mobj_t *actor); -void A_SetTargetsTarget(mobj_t *actor); -void A_SetObjectFlags(mobj_t *actor); -void A_SetObjectFlags2(mobj_t *actor); -void A_RandomState(mobj_t *actor); -void A_RandomStateRange(mobj_t *actor); -void A_DualAction(mobj_t *actor); -void A_RemoteAction(mobj_t *actor); -void A_ToggleFlameJet(mobj_t *actor); -void A_OrbitNights(mobj_t *actor); -void A_GhostMe(mobj_t *actor); -void A_SetObjectState(mobj_t *actor); -void A_SetObjectTypeState(mobj_t *actor); -void A_KnockBack(mobj_t *actor); -void A_PushAway(mobj_t *actor); -void A_RingDrain(mobj_t *actor); -void A_SplitShot(mobj_t *actor); -void A_MissileSplit(mobj_t *actor); -void A_MultiShot(mobj_t *actor); -void A_InstaLoop(mobj_t *actor); -void A_Custom3DRotate(mobj_t *actor); -void A_SearchForPlayers(mobj_t *actor); -void A_CheckRandom(mobj_t *actor); -void A_CheckTargetRings(mobj_t *actor); -void A_CheckRings(mobj_t *actor); -void A_CheckTotalRings(mobj_t *actor); -void A_CheckHealth(mobj_t *actor); -void A_CheckRange(mobj_t *actor); -void A_CheckHeight(mobj_t *actor); -void A_CheckTrueRange(mobj_t *actor); -void A_CheckThingCount(mobj_t *actor); -void A_CheckAmbush(mobj_t *actor); -void A_CheckCustomValue(mobj_t *actor); -void A_CheckCusValMemo(mobj_t *actor); -void A_SetCustomValue(mobj_t *actor); -void A_UseCusValMemo(mobj_t *actor); -void A_RelayCustomValue(mobj_t *actor); -void A_CusValAction(mobj_t *actor); -void A_ForceStop(mobj_t *actor); -void A_ForceWin(mobj_t *actor); -void A_SpikeRetract(mobj_t *actor); -void A_InfoState(mobj_t *actor); -void A_Repeat(mobj_t *actor); -void A_SetScale(mobj_t *actor); -void A_RemoteDamage(mobj_t *actor); -void A_HomingChase(mobj_t *actor); -void A_TrapShot(mobj_t *actor); -void A_Boss1Chase(mobj_t *actor); -void A_Boss2Chase(mobj_t *actor); -void A_Boss2Pogo(mobj_t *actor); -void A_BossJetFume(mobj_t *actor); -void A_VileTarget(mobj_t *actor); -void A_VileAttack(mobj_t *actor); -void A_VileFire(mobj_t *actor); -void A_BrakChase(mobj_t *actor); -void A_BrakFireShot(mobj_t *actor); -void A_BrakLobShot(mobj_t *actor); -void A_NapalmScatter(mobj_t *actor); -void A_SpawnFreshCopy(mobj_t *actor); -void A_FlickySpawn(mobj_t *actor); -void A_FlickyAim(mobj_t *actor); -void A_FlickyFly(mobj_t *actor); -void A_FlickySoar(mobj_t *actor); -void A_FlickyCoast(mobj_t *actor); -void A_FlickyHop(mobj_t *actor); -void A_FlickyFlounder(mobj_t *actor); -void A_FlickyCheck(mobj_t *actor); -void A_FlickyHeightCheck(mobj_t *actor); -void A_FlickyFlutter(mobj_t *actor); -void A_FlameParticle(mobj_t *actor); -void A_FadeOverlay(mobj_t *actor); -void A_Boss5Jump(mobj_t *actor); -void A_LightBeamReset(mobj_t *actor); -void A_MineExplode(mobj_t *actor); -void A_MineRange(mobj_t *actor); -void A_ConnectToGround(mobj_t *actor); -void A_SpawnParticleRelative(mobj_t *actor); -void A_MultiShotDist(mobj_t *actor); -void A_WhoCaresIfYourSonIsABee(mobj_t *actor); -void A_ParentTriesToSleep(mobj_t *actor); -void A_CryingToMomma(mobj_t *actor); -void A_CheckFlags2(mobj_t *actor); -//for p_enemy.c - -// -// ENEMY THINKING -// Enemies are always spawned with targetplayer = -1, threshold = 0 -// Most monsters are spawned unaware of all players, but some can be made preaware. -// - -// -// P_CheckMeleeRange -// -boolean P_CheckMeleeRange(mobj_t *actor) -{ - mobj_t *pl; - fixed_t dist; - - if (!actor->target) - return false; - - pl = actor->target; - dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); - - if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius) - return false; - - // check height now, so that damn crawlas cant attack - // you if you stand on a higher ledge. - if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height)) - return false; - - if (!P_CheckSight(actor, actor->target)) - return false; - - return true; -} - -// P_CheckMeleeRange for Jettysyn Bomber. -boolean P_JetbCheckMeleeRange(mobj_t *actor) -{ - mobj_t *pl; - fixed_t dist; - - if (!actor->target) - return false; - - pl = actor->target; - dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); - - if (dist >= (actor->radius + pl->radius)*2) - return false; - - if (actor->eflags & MFE_VERTICALFLIP) - { - if (pl->z < actor->z + actor->height + FixedMul(40<scale)) - return false; - } - else - { - if (pl->z + pl->height > actor->z - FixedMul(40<scale)) - return false; - } - - return true; -} - -// P_CheckMeleeRange for CastleBot FaceStabber. -boolean P_FaceStabCheckMeleeRange(mobj_t *actor) -{ - mobj_t *pl; - fixed_t dist; - - if (!actor->target) - return false; - - pl = actor->target; - dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); - - if (dist >= (actor->radius + pl->radius)*4) - return false; - - if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height)) - return false; - - if (!P_CheckSight(actor, actor->target)) - return false; - - return true; -} - -// P_CheckMeleeRange for Skim. -boolean P_SkimCheckMeleeRange(mobj_t *actor) -{ - mobj_t *pl; - fixed_t dist; - - if (!actor->target) - return false; - - pl = actor->target; - dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); - - if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius) - return false; - - if (actor->eflags & MFE_VERTICALFLIP) - { - if (pl->z < actor->z + actor->height + FixedMul(24<scale)) - return false; - } - else - { - if (pl->z + pl->height > actor->z - FixedMul(24<scale)) - return false; - } - - return true; -} - -// -// P_CheckMissileRange -// -boolean P_CheckMissileRange(mobj_t *actor) -{ - fixed_t dist; - - if (!actor->target) - return false; - - if (actor->reactiontime) - return false; // do not attack yet - - if (!P_CheckSight(actor, actor->target)) - return false; - - // OPTIMIZE: get this from a global checksight - dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - FixedMul(64*FRACUNIT, actor->scale); - - if (!actor->info->meleestate) - dist -= FixedMul(128*FRACUNIT, actor->scale); // no melee attack, so fire more - - dist >>= FRACBITS; - - if (actor->type == MT_EGGMOBILE) - dist >>= 1; - - if (dist > 200) - dist = 200; - - if (actor->type == MT_EGGMOBILE && dist > 160) - dist = 160; - - if (P_RandomByte() < dist) - return false; - - return true; -} - -/** Checks for water in a sector. - * Used by Skim movements. - * - * \param x X coordinate on the map. - * \param y Y coordinate on the map. - * \return True if there's water at this location, false if not. - * \sa ::MT_SKIM - */ -static boolean P_WaterInSector(mobj_t *mobj, fixed_t x, fixed_t y) -{ - sector_t *sector; - - sector = R_PointInSubsector(x, y)->sector; - - if (sector->ffloors) - { - ffloor_t *rover; - - for (rover = sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE)) - continue; - - if (*rover->topheight >= mobj->floorz && *rover->topheight <= mobj->z) - return true; // we found water!! - } - } - - return false; -} - -static const fixed_t xspeed[NUMDIRS] = {FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS)), 0, 46341>>(16-FRACBITS)}; -static const fixed_t yspeed[NUMDIRS] = {0, 46341>>(16-FRACBITS), FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS))}; - -/** Moves an actor in its current direction. - * - * \param actor Actor object to move. - * \return False if the move is blocked, otherwise true. - */ -boolean P_Move(mobj_t *actor, fixed_t speed) -{ - fixed_t tryx, tryy; - dirtype_t movedir = actor->movedir; - - if (movedir == DI_NODIR || !actor->health) - return false; - - I_Assert(movedir < NUMDIRS); - - tryx = actor->x + FixedMul(speed*xspeed[movedir], actor->scale); - if (twodlevel || actor->flags2 & MF2_TWOD) - tryy = actor->y; - else - tryy = actor->y + FixedMul(speed*yspeed[movedir], actor->scale); - - if (actor->type == MT_SKIM && !P_WaterInSector(actor, tryx, tryy)) // bail out if sector lacks water - return false; - - if (!P_TryMove(actor, tryx, tryy, false)) - { - if (actor->flags & MF_FLOAT && floatok) - { - // must adjust height - if (actor->z < tmfloorz) - actor->z += FixedMul(FLOATSPEED, actor->scale); - else - actor->z -= FixedMul(FLOATSPEED, actor->scale); - - if (actor->type == MT_JETJAW && actor->z + actor->height > actor->watertop) - actor->z = actor->watertop - actor->height; - - actor->flags2 |= MF2_INFLOAT; - return true; - } - - return false; - } - else - actor->flags2 &= ~MF2_INFLOAT; - - return true; -} - -/** Attempts to move an actor on in its current direction. - * If the move succeeds, the actor's move count is reset - * randomly to a value from 0 to 15. - * - * \param actor Actor to move. - * \return True if the move succeeds, false if the move is blocked. - */ -static boolean P_TryWalk(mobj_t *actor) -{ - if (!P_Move(actor, actor->info->speed)) - return false; - actor->movecount = P_RandomByte() & 15; - return true; -} - -void P_NewChaseDir(mobj_t *actor) -{ - fixed_t deltax, deltay; - dirtype_t d[3]; - dirtype_t tdir = DI_NODIR, olddir, turnaround; - - I_Assert(actor->target != NULL); - I_Assert(!P_MobjWasRemoved(actor->target)); - - olddir = actor->movedir; - - if (olddir >= NUMDIRS) - olddir = DI_NODIR; - - if (olddir != DI_NODIR) - turnaround = opposite[olddir]; - else - turnaround = olddir; - - deltax = actor->target->x - actor->x; - deltay = actor->target->y - actor->y; - - if (deltax > FixedMul(10*FRACUNIT, actor->scale)) - d[1] = DI_EAST; - else if (deltax < -FixedMul(10*FRACUNIT, actor->scale)) - d[1] = DI_WEST; - else - d[1] = DI_NODIR; - - if (twodlevel || actor->flags2 & MF2_TWOD) - d[2] = DI_NODIR; - if (deltay < -FixedMul(10*FRACUNIT, actor->scale)) - d[2] = DI_SOUTH; - else if (deltay > FixedMul(10*FRACUNIT, actor->scale)) - d[2] = DI_NORTH; - else - d[2] = DI_NODIR; - - // try direct route - if (d[1] != DI_NODIR && d[2] != DI_NODIR) - { - dirtype_t newdir = diags[((deltay < 0)<<1) + (deltax > 0)]; - - actor->movedir = newdir; - if ((newdir != turnaround) && P_TryWalk(actor)) - return; - } - - // try other directions - if (P_RandomChance(25*FRACUNIT/32) || abs(deltay) > abs(deltax)) - { - tdir = d[1]; - d[1] = d[2]; - d[2] = tdir; - } - - if (d[1] == turnaround) - d[1] = DI_NODIR; - if (d[2] == turnaround) - d[2] = DI_NODIR; - - if (d[1] != DI_NODIR) - { - actor->movedir = d[1]; - - if (P_TryWalk(actor)) - return; // either moved forward or attacked - } - - if (d[2] != DI_NODIR) - { - actor->movedir = d[2]; - - if (P_TryWalk(actor)) - return; - } - - // there is no direct path to the player, so pick another direction. - if (olddir != DI_NODIR) - { - actor->movedir =olddir; - - if (P_TryWalk(actor)) - return; - } - - // randomly determine direction of search - if (P_RandomChance(FRACUNIT/2)) - { - for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++) - { - if (tdir != turnaround) - { - actor->movedir = tdir; - - if (P_TryWalk(actor)) - return; - } - } - } - else - { - for (tdir = DI_SOUTHEAST; tdir >= DI_EAST; tdir--) - { - if (tdir != turnaround) - { - actor->movedir = tdir; - - if (P_TryWalk(actor)) - return; - } - } - } - - if (turnaround != DI_NODIR) - { - actor->movedir = turnaround; - - if (P_TryWalk(actor)) - return; - } - - actor->movedir = (angle_t)DI_NODIR; // cannot move -} - -/** Looks for players to chase after, aim at, or whatever. - * - * \param actor The object looking for flesh. - * \param allaround Look all around? If false, only players in a 180-degree - * range in front will be spotted. - * \param dist If > 0, checks distance - * \return True if a player is found, otherwise false. - * \sa P_SupermanLook4Players - */ -boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist) -{ - INT32 c = 0, stop; - player_t *player; - angle_t an; - - // BP: first time init, this allow minimum lastlook changes - if (actor->lastlook < 0) - actor->lastlook = P_RandomByte(); - - actor->lastlook %= MAXPLAYERS; - - stop = (actor->lastlook - 1) & PLAYERSMASK; - - for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK) - { - // done looking - if (actor->lastlook == stop) - return false; - - if (!playeringame[actor->lastlook]) - continue; - - if (c++ == 2) - return false; - - player = &players[actor->lastlook]; - - if ((netgame || multiplayer) && player->spectator) - continue; - - if (player->pflags & PF_INVIS) - continue; // ignore notarget - - if (!player->mo || P_MobjWasRemoved(player->mo)) - continue; - - if (player->mo->health <= 0) - continue; // dead - - if (dist > 0 - && P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist) - continue; // Too far away - - if (!allaround) - { - an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; - if (an > ANGLE_90 && an < ANGLE_270) - { - dist = P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y); - // if real close, react anyway - if (dist > FixedMul(MELEERANGE, actor->scale)) - continue; // behind back - } - } - - if (!P_CheckSight(actor, player->mo)) - continue; // out of sight - - if (tracer) - P_SetTarget(&actor->tracer, player->mo); - else - P_SetTarget(&actor->target, player->mo); - return true; - } - - //return false; -} - -/** Looks for a player with a ring shield. - * Used by rings. - * - * \param actor Ring looking for a shield to be attracted to. - * \return True if a player with ring shield is found, otherwise false. - * \sa A_AttractChase - */ -static boolean P_LookForShield(mobj_t *actor) -{ - INT32 c = 0, stop; - player_t *player; - - // BP: first time init, this allow minimum lastlook changes - if (actor->lastlook < 0) - actor->lastlook = P_RandomByte(); - - actor->lastlook %= MAXPLAYERS; - - stop = (actor->lastlook - 1) & PLAYERSMASK; - - for (; ; actor->lastlook = ((actor->lastlook + 1) & PLAYERSMASK)) - { - // done looking - if (actor->lastlook == stop) - return false; - - if (!playeringame[actor->lastlook]) - continue; - - if (c++ == 2) - return false; - - player = &players[actor->lastlook]; - - if (!player->mo || player->mo->health <= 0) - continue; // dead - - //When in CTF, don't pull rings that you cannot pick up. - if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) || - (actor->type == MT_BLUETEAMRING && player->ctfteam != 2)) - continue; - - if ((player->powers[pw_shield] & SH_PROTECTELECTRIC) - && (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale))) - { - P_SetTarget(&actor->tracer, player->mo); - - if (actor->hnext) - P_SetTarget(&actor->hnext->hprev, actor->hprev); - if (actor->hprev) - P_SetTarget(&actor->hprev->hnext, actor->hnext); - - return true; - } - } - - //return false; -} - -#ifdef WEIGHTEDRECYCLER -// Compares players to see who currently has the "best" items, etc. -static int P_RecycleCompare(const void *p1, const void *p2) -{ - player_t *player1 = &players[*(const UINT8 *)p1]; - player_t *player2 = &players[*(const UINT8 *)p2]; - - // Non-shooting gametypes - if (!G_PlatformGametype()) - { - // Invincibility. - if (player1->powers[pw_invulnerability] > player2->powers[pw_invulnerability]) return -1; - else if (player2->powers[pw_invulnerability] > player1->powers[pw_invulnerability]) return 1; - - // One has a shield, the other doesn't. - if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1; - else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1; - - // Sneakers. - if (player1->powers[pw_sneakers] > player2->powers[pw_sneakers]) return -1; - else if (player2->powers[pw_sneakers] > player1->powers[pw_sneakers]) return 1; - } - else // Match, Team Match, CTF, Tag, Etc. - { - UINT8 player1_em = M_CountBits((UINT32)player1->powers[pw_emeralds], 7); - UINT8 player2_em = M_CountBits((UINT32)player2->powers[pw_emeralds], 7); - - UINT8 player1_rw = M_CountBits((UINT32)player1->ringweapons, NUM_WEAPONS-1); - UINT8 player2_rw = M_CountBits((UINT32)player2->ringweapons, NUM_WEAPONS-1); - - UINT16 player1_am = player1->powers[pw_infinityring] // max 800 - + player1->powers[pw_automaticring] // max 300 - + (player1->powers[pw_bouncering] * 3) // max 100 - + (player1->powers[pw_explosionring] * 6) // max 50 - + (player1->powers[pw_scatterring] * 3) // max 100 - + (player1->powers[pw_grenadering] * 6) // max 50 - + (player1->powers[pw_railring] * 6); // max 50 - UINT16 player2_am = player2->powers[pw_infinityring] // max 800 - + player2->powers[pw_automaticring] // max 300 - + (player2->powers[pw_bouncering] * 3) // max 100 - + (player2->powers[pw_explosionring] * 6) // max 50 - + (player2->powers[pw_scatterring] * 3) // max 100 - + (player2->powers[pw_grenadering] * 6) // max 50 - + (player2->powers[pw_railring] * 6); // max 50 - - // Super trumps everything. - if (player1->powers[pw_super] && !player2->powers[pw_super]) return -1; - else if (player2->powers[pw_super] && !player1->powers[pw_super]) return 1; - - // Emerald count if neither player is Super. - if (player1_em > player2_em) return -1; - else if (player1_em < player2_em) return 1; - - // One has a shield, the other doesn't. - // (the likelihood of a shielded player being worse off than one without one is low.) - if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1; - else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1; - - // Ring weapons count - if (player1_rw > player2_rw) return -1; - else if (player1_rw < player2_rw) return 1; - - // Ring ammo if they have the same number of weapons - if (player1_am > player2_am) return -1; - else if (player1_am < player2_am) return 1; - } - - // Identical for our purposes - return 0; -} -#endif - -// Handles random monitor weights via console. -static mobjtype_t P_DoRandomBoxChances(void) -{ - mobjtype_t spawnchance[256]; - INT32 numchoices = 0, i = 0; - - if (!(netgame || multiplayer)) - { - switch (P_RandomKey(10)) - { - case 0: - return MT_RING_ICON; - case 1: - return MT_SNEAKERS_ICON; - case 2: - return MT_INVULN_ICON; - case 3: - return MT_WHIRLWIND_ICON; - case 4: - return MT_ELEMENTAL_ICON; - case 5: - return MT_ATTRACT_ICON; - case 6: - return MT_FORCE_ICON; - case 7: - return MT_ARMAGEDDON_ICON; - case 8: - return MT_1UP_ICON; - case 9: - return MT_EGGMAN_ICON; - } - return MT_NULL; - } - -#define QUESTIONBOXCHANCES(type, cvar) \ -for (i = cvar.value; i; --i) spawnchance[numchoices++] = type - QUESTIONBOXCHANCES(MT_RING_ICON, cv_superring); - QUESTIONBOXCHANCES(MT_SNEAKERS_ICON, cv_supersneakers); - QUESTIONBOXCHANCES(MT_INVULN_ICON, cv_invincibility); - QUESTIONBOXCHANCES(MT_WHIRLWIND_ICON, cv_jumpshield); - QUESTIONBOXCHANCES(MT_ELEMENTAL_ICON, cv_watershield); - QUESTIONBOXCHANCES(MT_ATTRACT_ICON, cv_ringshield); - QUESTIONBOXCHANCES(MT_FORCE_ICON, cv_forceshield); - QUESTIONBOXCHANCES(MT_ARMAGEDDON_ICON, cv_bombshield); - QUESTIONBOXCHANCES(MT_1UP_ICON, cv_1up); - QUESTIONBOXCHANCES(MT_EGGMAN_ICON, cv_eggmanbox); - QUESTIONBOXCHANCES(MT_MIXUP_ICON, cv_teleporters); - QUESTIONBOXCHANCES(MT_RECYCLER_ICON, cv_recycler); -#undef QUESTIONBOXCHANCES - - if (numchoices == 0) return MT_NULL; - return spawnchance[P_RandomKey(numchoices)]; -} - -// -// ACTION ROUTINES -// - -// Function: A_Look -// -// Description: Look for a player and set your target to them. -// -// var1: -// lower 16 bits = look all around -// upper 16 bits = distance limit -// var2 = If 1, only change to seestate. If 2, only play seesound. If 0, do both. -// -void A_Look(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Look", actor)) - return; -#endif - - if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale))) - return; - - // go into chase state - if (!locvar2) - { - P_SetMobjState(actor, actor->info->seestate); - A_PlaySeeSound(actor); - } - else if (locvar2 == 1) // Only go into seestate - P_SetMobjState(actor, actor->info->seestate); - else if (locvar2 == 2) // Only play seesound - A_PlaySeeSound(actor); -} - -// Function: A_Chase -// -// Description: Chase after your target. -// -// var1: -// 1 = don't check meleestate -// 2 = don't check missilestate -// 3 = don't check meleestate and missilestate -// var2 = unused -// -void A_Chase(mobj_t *actor) -{ - INT32 delta; - INT32 locvar1 = var1; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Chase", actor)) - return; -#endif - - I_Assert(actor != NULL); - I_Assert(!P_MobjWasRemoved(actor)); - - if (actor->reactiontime) - actor->reactiontime--; - - // modify target threshold - if (actor->threshold) - { - if (!actor->target || actor->target->health <= 0) - actor->threshold = 0; - else - actor->threshold--; - } - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjStateNF(actor, actor->info->spawnstate); - return; - } - - // do not attack twice in a row - if (actor->flags2 & MF2_JUSTATTACKED) - { - actor->flags2 &= ~MF2_JUSTATTACKED; - P_NewChaseDir(actor); - return; - } - - // check for melee attack - if (!(locvar1 & 1) && actor->info->meleestate && P_CheckMeleeRange(actor)) - { - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - - P_SetMobjState(actor, actor->info->meleestate); - return; - } - - // check for missile attack - if (!(locvar1 & 2) && actor->info->missilestate) - { - if (actor->movecount || !P_CheckMissileRange(actor)) - goto nomissile; - - P_SetMobjState(actor, actor->info->missilestate); - actor->flags2 |= MF2_JUSTATTACKED; - return; - } - -nomissile: - // possibly choose another target - if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - && P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); -} - -// Function: A_FaceStabChase -// -// Description: A_Chase for CastleBot FaceStabber. -// -// var1 = unused -// var2 = unused -// -void A_FaceStabChase(mobj_t *actor) -{ - INT32 delta; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FaceStabChase", actor)) - return; -#endif - - if (actor->reactiontime) - actor->reactiontime--; - - // modify target threshold - if (actor->threshold) - { - if (!actor->target || actor->target->health <= 0) - actor->threshold = 0; - else - actor->threshold--; - } - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjStateNF(actor, actor->info->spawnstate); - return; - } - - // do not attack twice in a row - if (actor->flags2 & MF2_JUSTATTACKED) - { - actor->flags2 &= ~MF2_JUSTATTACKED; - P_NewChaseDir(actor); - return; - } - - // check for melee attack - if (actor->info->meleestate && P_FaceStabCheckMeleeRange(actor)) - { - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - - P_SetMobjState(actor, actor->info->meleestate); - return; - } - - // check for missile attack - if (actor->info->missilestate) - { - if (actor->movecount || !P_CheckMissileRange(actor)) - goto nomissile; - - P_SetMobjState(actor, actor->info->missilestate); - actor->flags2 |= MF2_JUSTATTACKED; - return; - } - -nomissile: - // possibly choose another target - if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - && P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); -} - -// Function: A_JetJawRoam -// -// Description: Roaming routine for JetJaw -// -// var1 = unused -// var2 = unused -// -void A_JetJawRoam(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_JetJawRoam", actor)) - return; -#endif - if (actor->reactiontime) - { - actor->reactiontime--; - P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed*FRACUNIT/4, actor->scale)); - } - else - { - actor->reactiontime = actor->info->reactiontime; - actor->angle += ANGLE_180; - } - - if (P_LookForPlayers(actor, false, false, actor->radius * 16)) - P_SetMobjState(actor, actor->info->seestate); -} - -// Function: A_JetJawChomp -// -// Description: Chase and chomp at the target, as long as it is in view -// -// var1 = unused -// var2 = unused -// -void A_JetJawChomp(mobj_t *actor) -{ - INT32 delta; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_JetJawChomp", actor)) - return; -#endif - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - // Stop chomping if target's dead or you can't see it - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) - || actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - { - P_SetMobjStateNF(actor, actor->info->spawnstate); - return; - } - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); -} - -// Function: A_PointyThink -// -// Description: Thinker function for Pointy -// -// var1 = unused -// var2 = unused -// -void A_PointyThink(mobj_t *actor) -{ - INT32 i; - player_t *player = NULL; - mobj_t *ball; - TVector v; - TVector *res; - angle_t fa; - fixed_t radius = FixedMul(actor->info->radius*actor->info->reactiontime, actor->scale); - boolean firsttime = true; - INT32 sign; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_PointyThink", actor)) - return; -#endif - actor->momx = actor->momy = actor->momz = 0; - - // Find nearest player - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - if (!players[i].mo->health) - continue; - - if (!P_CheckSight(actor, players[i].mo)) - continue; - - if (firsttime) - { - firsttime = false; - player = &players[i]; - } - else - { - if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) < - P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y)) - player = &players[i]; - } - } - - if (!player) - return; - - // Okay, we found the closest player. Let's move based on his movement. - P_SetTarget(&actor->target, player->mo); - A_FaceTarget(actor); - - if (P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) < P_AproxDistance(player->mo->x + player->mo->momx - actor->x, player->mo->y + player->mo->momy - actor->y)) - sign = -1; // Player is moving away - else - sign = 1; // Player is moving closer - - if (player->mo->momx || player->mo->momy) - { - P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y), FixedMul(actor->info->speed*sign, actor->scale)); - - // Rotate our spike balls - actor->lastlook += actor->info->damage; - actor->lastlook %= FINEANGLES/4; - } - - if (!actor->tracer) // For some reason we do not have spike balls... - return; - - // Position spike balls relative to the value of 'lastlook'. - ball = actor->tracer; - - i = 0; - while (ball) - { - fa = actor->lastlook+i; - v[0] = FixedMul(FINECOSINE(fa),radius); - v[1] = 0; - v[2] = FixedMul(FINESINE(fa),radius); - v[3] = FRACUNIT; - - res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(actor->lastlook+i))); - M_Memcpy(&v, res, sizeof (v)); - res = VectorMatrixMultiply(v, *RotateZMatrix(actor->angle+ANGLE_180)); - M_Memcpy(&v, res, sizeof (v)); - - P_UnsetThingPosition(ball); - ball->x = actor->x + v[0]; - ball->y = actor->y + v[1]; - ball->z = actor->z + (actor->height>>1) + v[2]; - P_SetThingPosition(ball); - - ball = ball->tracer; - i += ANGLE_90 >> ANGLETOFINESHIFT; - } -} - -// Function: A_CheckBuddy -// -// Description: Checks if target/tracer exists/has health. If not, the object removes itself. -// -// var1: -// 0 = target -// 1 = tracer -// var2 = unused -// -void A_CheckBuddy(mobj_t *actor) -{ - INT32 locvar1 = var1; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckBuddy", actor)) - return; -#endif - if (locvar1 && (!actor->tracer || actor->tracer->health <= 0)) - P_RemoveMobj(actor); - else if (!locvar1 && (!actor->target || actor->target->health <= 0)) - P_RemoveMobj(actor); -} - -// Function: A_HoodThink -// -// Description: Thinker for Robo-Hood -// -// var1 = unused -// var2 = unused -// -void A_HoodThink(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_HoodThink", actor)) - return; -#endif - // Currently in the air... - if (!(actor->eflags & MFE_VERTICALFLIP) && actor->z > actor->floorz) - { - if (actor->momz > 0) - P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising - else - P_SetMobjStateNF(actor, actor->info->raisestate); // Falling - - return; - } - else if ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height < actor->ceilingz) - { - if (actor->momz < 0) - P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising - else - P_SetMobjStateNF(actor, actor->info->raisestate); // Falling - - return; - } - - if (actor->state == &states[actor->info->xdeathstate] - || actor->state == &states[actor->info->raisestate]) - P_SetMobjStateNF(actor, actor->info->seestate); - - if (!actor->target) - { - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - A_FaceTarget(actor); // Aiming... aiming... - - if (--actor->reactiontime > 0) - return; - - // Shoot, if not too close (cheap shots are lame) - if ((P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) > FixedMul(192*FRACUNIT, actor->scale)) - || (actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH))) // If you can't jump, might as well shoot regardless of distance! - P_SetMobjState(actor, actor->info->missilestate); - else if (!(actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH)))// But we WILL jump! - P_SetMobjState(actor, actor->info->painstate); - - actor->reactiontime = actor->info->reactiontime; -} - -// Function: A_ArrowCheck -// -// Description: Checks arrow direction and adjusts sprite accordingly -// -// var1 = unused -// var2 = unused -// -void A_ArrowCheck(mobj_t *actor) -{ - fixed_t x,y,z; - angle_t angle; - fixed_t dist; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ArrowCheck", actor)) - return; -#endif - - // Movement vector - x = actor->momx; - y = actor->momy; - z = actor->momz; - - // Calculate the angle of movement. - /* - Z - / | - / | - / | - 0------dist(X,Y) - */ - - dist = P_AproxDistance(x, y); - - angle = R_PointToAngle2(0, 0, dist, z); - - if (angle > ANG20 && angle <= ANGLE_180) - P_SetMobjStateNF(actor, actor->info->raisestate); - else if (angle < ANG340 && angle > ANGLE_180) - P_SetMobjStateNF(actor, actor->info->xdeathstate); - else - P_SetMobjStateNF(actor, actor->info->spawnstate); -} - -// Function: A_SnailerThink -// -// Description: Thinker function for Snailer -// -// var1 = unused -// var2 = unused -// -void A_SnailerThink(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SnailerThink", actor)) - return; -#endif - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (!P_LookForPlayers(actor, true, false, 0)) - return; - } - - // We now have a target. Oh bliss, rapture, and contentment! - - if (actor->target->z + actor->target->height > actor->z - FixedMul(32*FRACUNIT, actor->scale) - && actor->target->z < actor->z + actor->height + FixedMul(32*FRACUNIT, actor->scale) - && !(leveltime % (TICRATE*2))) - { - angle_t an; - fixed_t z; - - // Actor shouldn't face target, so we'll do things a bit differently here - - an = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle; - - z = actor->z + actor->height/2; - - if (an > ANGLE_45 && an < ANGLE_315) // fire as close as you can to the target, even if too sharp an angle from your front - { - fixed_t dist; - fixed_t dx, dy; - - dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y); - - if (an > ANGLE_45 && an <= ANGLE_90) // fire at 45 degrees to the left - { - dx = actor->x + P_ReturnThrustX(actor, actor->angle + ANGLE_45, dist); - dy = actor->y + P_ReturnThrustY(actor, actor->angle + ANGLE_45, dist); - } - else if (an >= ANGLE_270 && an < ANGLE_315) // fire at 45 degrees to the right - { - dx = actor->x + P_ReturnThrustX(actor, actor->angle - ANGLE_45, dist); - dy = actor->y + P_ReturnThrustY(actor, actor->angle - ANGLE_45, dist); - } - else // fire straight ahead - { - dx = actor->x + P_ReturnThrustX(actor, actor->angle, dist); - dy = actor->y + P_ReturnThrustY(actor, actor->angle, dist); - } - - P_SpawnPointMissile(actor, dx, dy, actor->target->z, MT_ROCKET, actor->x, actor->y, z); - } - else - P_SpawnXYZMissile(actor, actor->target, MT_ROCKET, actor->x, actor->y, z); - } - - if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z > actor->z) - || (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) > (actor->z + actor->height))) - actor->momz += FixedMul(actor->info->speed, actor->scale); - else if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z < actor->z) - || (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) < (actor->z + actor->height))) - actor->momz -= FixedMul(actor->info->speed, actor->scale); - - actor->momz /= 2; -} - -// Function: A_SharpChase -// -// Description: Thinker/Chase routine for Spincushions -// -// var1 = unused -// var2 = unused -// -void A_SharpChase(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SharpChase", actor)) - return; -#endif - - if (actor->reactiontime) - { - INT32 delta; - - actor->reactiontime--; - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); - } - else - { - actor->threshold = actor->info->painchance; - P_SetMobjState(actor, actor->info->missilestate); - S_StartSound(actor, actor->info->attacksound); - } -} - -// Function: A_SharpSpin -// -// Description: Spin chase routine for Spincushions -// -// var1 = object # to spawn as dust (if not provided not done) -// var2 = if nonzero, do the old-style spinning using this as the angle difference -// -void A_SharpSpin(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - angle_t oldang = actor->angle; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SharpSpin", actor)) - return; -#endif - - if (actor->threshold && actor->target) - { - angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_Thrust(actor, ang, actor->info->speed*actor->scale); - if (locvar2) - actor->angle += locvar2; // ANGLE_22h; - else - actor->angle = ang; - actor->threshold--; - if (leveltime & 1) - S_StartSound(actor, actor->info->painsound); - } - else - { - actor->reactiontime = actor->info->reactiontime; - P_SetMobjState(actor, actor->info->meleestate); - } - - if (!locvar1 || !P_IsObjectOnGround(actor)) - return; - - { - mobj_t *dust = P_SpawnMobjFromMobj(actor, - -P_ReturnThrustX(actor, oldang, 16<momx > 2 || actor->momy > 2) - { - actor->momx >>= 1; - actor->momy >>= 1; - } - else - P_SetMobjState(actor, actor->info->xdeathstate); -} - -// Function: A_CrushstaceanWalk -// -// Description: Crushstacean movement -// -// var1 = speed (actor info's speed if 0) -// var2 = state to switch to when blocked (spawnstate if 0) -// -void A_CrushstaceanWalk(mobj_t *actor) -{ - INT32 locvar1 = (var1 ? var1 : (INT32)actor->info->speed); - INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); - angle_t ang = actor->angle + ((actor->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CrushstaceanWalk", actor)) - return; -#endif - - actor->reactiontime--; - - if (!P_TryMove(actor, - actor->x + P_ReturnThrustX(actor, ang, locvar1*actor->scale), - actor->y + P_ReturnThrustY(actor, ang, locvar1*actor->scale), - false) - || (actor->reactiontime-- <= 0)) - { - actor->flags2 ^= MF2_AMBUSH; - P_SetMobjState(actor, locvar2); - actor->reactiontime = actor->info->reactiontime; - } -} - -// Function: A_CrushstaceanPunch -// -// Description: Crushstacean attack -// -// var1 = unused -// var2 = state to go to if unsuccessful (spawnstate if 0) -// -void A_CrushstaceanPunch(mobj_t *actor) -{ - //INT32 locvar1 = var1; - INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CrushstaceanPunch", actor)) - return; -#endif - - if (!actor->tracer) - return; - - if (!actor->target) - { - P_SetMobjState(actor, locvar2); - return; - } - - actor->tracer->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_SetMobjState(actor->tracer, actor->tracer->info->missilestate); - actor->tracer->extravalue1 = actor->tracer->extravalue2 = 0; - S_StartSound(actor, actor->info->attacksound); -} - -// Function: A_CrushclawAim -// -// Description: Crushstacean claw aiming -// -// var1 = sideways offset -// var2 = vertical offset -// -void A_CrushclawAim(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *crab = actor->tracer; - angle_t ang; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CrushclawAim", actor)) - return; -#endif - - if (!crab) - { - P_RemoveMobj(actor); - return; // there is only one step and it is crab - } - - if (crab->target || P_LookForPlayers(crab, true, false, 600*crab->scale)) - ang = R_PointToAngle2(crab->x, crab->y, crab->target->x, crab->target->y); - else - ang = crab->angle + ((crab->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); - ang -= actor->angle; - -#define anglimit ANGLE_22h -#define angfactor 5 - if (ang < ANGLE_180) - { - if (ang > anglimit) - ang = anglimit; - ang /= angfactor; - } - else - { - ang = InvAngle(ang); - if (ang > anglimit) - ang = anglimit; - ang = InvAngle(ang/angfactor); - } - actor->angle += ang; -#undef anglimit -#undef angfactor - - P_TeleportMove(actor, - crab->x + P_ReturnThrustX(actor, actor->angle, locvar1*crab->scale), - crab->y + P_ReturnThrustY(actor, actor->angle, locvar1*crab->scale), - crab->z + locvar2*crab->scale); - - if (!crab->target || !crab->info->missilestate || (statenum_t)(crab->state-states) == crab->info->missilestate) - return; - - if (((ang + ANG1) < ANG2) || P_AproxDistance(crab->x - crab->target->x, crab->y - crab->target->y) < 333*crab->scale) - P_SetMobjState(crab, crab->info->missilestate); -} - -// Function: A_CrushclawLaunch -// -// Description: Crushstacean claw launching -// -// var1: -// 0 - forwards -// anything else - backwards -// var2 = state to change to when done -// -void A_CrushclawLaunch(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *crab = actor->tracer; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CrushclawLaunch", actor)) - return; -#endif - - if (!crab) - { - mobj_t *chainnext; - while (actor) - { - chainnext = actor->target; - P_RemoveMobj(actor); - actor = chainnext; - } - return; // there is only one step and it is crab - } - - if (!actor->extravalue1) - { - S_StartSound(actor, actor->info->activesound); - actor->extravalue1 = ((locvar1) ? -1 : 32); - } - else if (actor->extravalue1 != 1) - actor->extravalue1 -= 1; - -#define CSEGS 5 - if (!actor->target) - { - mobj_t *prevchain = actor; - UINT8 i = 0; - for (i = 0; (i < CSEGS); i++) - { - mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate); - prevchain->target = newchain; - prevchain = newchain; - } - actor->target->angle = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y); - } - - if ((!locvar1) && crab->target) - { -#define anglimit ANGLE_22h -#define angfactor 7 - angle_t ang = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y) - actor->target->angle; - if (ang < ANGLE_180) - { - if (ang > anglimit) - ang = anglimit; - ang /= angfactor; - } - else - { - ang = InvAngle(ang); - if (ang > anglimit) - ang = anglimit; - ang /= angfactor; - ang = InvAngle(ang); - } - actor->target->angle += ang; - actor->angle = actor->target->angle; - } - - actor->extravalue2 += actor->extravalue1; - - if (!P_TryMove(actor, - actor->target->x + P_ReturnThrustX(actor, actor->target->angle, actor->extravalue2*actor->scale), - actor->target->y + P_ReturnThrustY(actor, actor->target->angle, actor->extravalue2*actor->scale), - true) - && !locvar1) - { - actor->extravalue1 = 0; - actor->extravalue2 = FixedHypot(actor->x - actor->target->x, actor->y - actor->target->y)>>FRACBITS; - P_SetMobjState(actor, locvar2); - S_StopSound(actor); - S_StartSound(actor, sfx_s3k49); - } - else - { - actor->z = actor->target->z; - if ((!locvar1 && (actor->extravalue2 > 256)) || (locvar1 && (actor->extravalue2 < 16))) - { - if (locvar1) // In case of retracting, resume crab and remove the chain. - { - mobj_t *chain = actor->target, *chainnext; - while (chain) - { - chainnext = chain->target; - P_RemoveMobj(chain); - chain = chainnext; - } - actor->extravalue2 = 0; - actor->angle = R_PointToAngle2(crab->x, crab->y, actor->x, actor->y); - P_SetTarget(&actor->target, NULL); - P_SetTarget(&crab->target, NULL); - P_SetMobjState(crab, crab->state->nextstate); - } - actor->extravalue1 = 0; - P_SetMobjState(actor, locvar2); - S_StopSound(actor); - if (!locvar1) - S_StartSound(actor, sfx_s3k64); - } - } - - if (!actor->target) - return; - - { - mobj_t *chain = actor->target->target; - fixed_t dx = (actor->x - actor->target->x)/CSEGS, dy = (actor->y - actor->target->y)/CSEGS, dz = (actor->z - actor->target->z)/CSEGS; - fixed_t idx = dx, idy = dy, idz = dz; - while (chain) - { - P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz); - chain->watertop = chain->z; - idx += dx; - idy += dy; - idz += dz; - chain = chain->target; - } - } -#undef CSEGS -} - -// Function: A_VultureVtol -// -// Description: Vulture rising up to match target's height -// -// var1 = unused -// var2 = unused -// -void A_VultureVtol(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_VultureVtol", actor)) - return; -#endif - - if (!actor->target) - return; - - actor->flags |= MF_NOGRAVITY; - actor->flags |= MF_FLOAT; - - A_FaceTarget(actor); - - S_StopSound(actor); - - if (actor->z < actor->target->z+(actor->target->height/4) && actor->z + actor->height < actor->ceilingz) - actor->momz = FixedMul(2*FRACUNIT, actor->scale); - else if (actor->z > (actor->target->z+(actor->target->height/4)*3) && actor->z > actor->floorz) - actor->momz = FixedMul(-2*FRACUNIT, actor->scale); - else - { - // Attack! - actor->momz = 0; - P_SetMobjState(actor, actor->info->missilestate); - S_StartSound(actor, actor->info->activesound); - } -} - -// Function: A_VultureCheck -// -// Description: If the vulture is stopped, look for a new target -// -// var1 = unused -// var2 = unused -// -void A_VultureCheck(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_VultureCheck", actor)) - return; -#endif - - if (actor->momx || actor->momy) - return; - - actor->flags &= ~MF_NOGRAVITY; // Fall down - - if (actor->z <= actor->floorz) - { - actor->angle -= ANGLE_180; // turn around - P_SetMobjState(actor, actor->info->spawnstate); - } -} - -// Function: A_SkimChase -// -// Description: Thinker/Chase routine for Skims -// -// var1 = unused -// var2 = unused -// -void A_SkimChase(mobj_t *actor) -{ - INT32 delta; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SkimChase", actor)) - return; -#endif - if (actor->reactiontime) - actor->reactiontime--; - - // modify target threshold - if (actor->threshold) - { - if (!actor->target || actor->target->health <= 0) - actor->threshold = 0; - else - actor->threshold--; - } - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - P_LookForPlayers(actor, true, false, 0); - - // the spawnstate for skims already calls this function so just return either way - // without changing state - return; - } - - // do not attack twice in a row - if (actor->flags2 & MF2_JUSTATTACKED) - { - actor->flags2 &= ~MF2_JUSTATTACKED; - P_NewChaseDir(actor); - return; - } - - // check for melee attack - if (actor->info->meleestate && P_SkimCheckMeleeRange(actor)) - { - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - - P_SetMobjState(actor, actor->info->meleestate); - return; - } - - // check for missile attack - if (actor->info->missilestate) - { - if (actor->movecount || !P_CheckMissileRange(actor)) - goto nomissile; - - P_SetMobjState(actor, actor->info->missilestate); - actor->flags2 |= MF2_JUSTATTACKED; - return; - } - -nomissile: - // possibly choose another target - if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - && P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); -} - -// Function: A_FaceTarget -// -// Description: Immediately turn to face towards your target. -// -// var1 = unused -// var2 = unused -// -void A_FaceTarget(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FaceTarget", actor)) - return; -#endif - if (!actor->target) - return; - - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); -} - -// Function: A_FaceTracer -// -// Description: Immediately turn to face towards your tracer. -// -// var1 = unused -// var2 = unused -// -void A_FaceTracer(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FaceTracer", actor)) - return; -#endif - if (!actor->tracer) - return; - - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); -} - -// Function: A_LobShot -// -// Description: Lob an object at your target. -// -// var1 = object # to lob -// var2: -// var2 >> 16 = height offset -// var2 & 65535 = airtime -// -void A_LobShot(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2 >> 16; - mobj_t *shot, *hitspot; - angle_t an; - fixed_t z; - fixed_t dist; - fixed_t vertical, horizontal; - fixed_t airtime = var2 & 65535; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_LobShot", actor)) - return; -#endif - if (!actor->target) - return; - - A_FaceTarget(actor); - - if (actor->eflags & MFE_VERTICALFLIP) - { - z = actor->z + actor->height - FixedMul(locvar2*FRACUNIT, actor->scale); - if (actor->type == MT_BLACKEGGMAN) - z -= FixedMul(mobjinfo[locvar1].height, actor->scale/2); - else - z -= FixedMul(mobjinfo[locvar1].height, actor->scale); - } - else - z = actor->z + FixedMul(locvar2*FRACUNIT, actor->scale); - - shot = P_SpawnMobj(actor->x, actor->y, z, locvar1); - - if (actor->type == MT_BLACKEGGMAN) - { - shot->destscale = actor->scale/2; - P_SetScale(shot, actor->scale/2); - } - else - { - shot->destscale = actor->scale; - P_SetScale(shot, actor->scale); - } - - // Keep track of where it's going to land - hitspot = P_SpawnMobj(actor->target->x&(64*FRACUNIT-1), actor->target->y&(64*FRACUNIT-1), actor->target->subsector->sector->floorheight, MT_NULL); - hitspot->tics = airtime; - P_SetTarget(&shot->tracer, hitspot); - - P_SetTarget(&shot->target, actor); // where it came from - - shot->angle = an = actor->angle; - an >>= ANGLETOFINESHIFT; - - dist = P_AproxDistance(actor->target->x - shot->x, actor->target->y - shot->y); - - horizontal = dist / airtime; - vertical = FixedMul((gravity*airtime)/2, shot->scale); - - shot->momx = FixedMul(horizontal, FINECOSINE(an)); - shot->momy = FixedMul(horizontal, FINESINE(an)); - shot->momz = vertical; - -/* Try to adjust when destination is not the same height - if (actor->z != actor->target->z) - { - fixed_t launchhyp; - fixed_t diff; - fixed_t orig; - - diff = actor->z - actor->target->z; - { - launchhyp = P_AproxDistance(horizontal, vertical); - - orig = FixedMul(FixedDiv(vertical, horizontal), diff); - - CONS_Debug(DBG_GAMELOGIC, "orig: %d\n", (orig)>>FRACBITS); - - horizontal = dist / airtime; - vertical = (gravity*airtime)/2; - } - dist -= orig; - shot->momx = FixedMul(horizontal, FINECOSINE(an)); - shot->momy = FixedMul(horizontal, FINESINE(an)); - shot->momz = vertical; -*/ - - if (shot->info->seesound) - S_StartSound(shot, shot->info->seesound); - - if (!(actor->flags & MF_BOSS)) - { - if (ultimatemode) - actor->reactiontime = actor->info->reactiontime*TICRATE; - else - actor->reactiontime = actor->info->reactiontime*TICRATE*2; - } -} - -// Function: A_FireShot -// -// Description: Shoot an object at your target. -// -// var1 = object # to shoot -// var2 = height offset -// -void A_FireShot(mobj_t *actor) -{ - fixed_t z; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FireShot", actor)) - return; -#endif - if (!actor->target) - return; - - A_FaceTarget(actor); - - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); - - P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z); - - if (!(actor->flags & MF_BOSS)) - { - if (ultimatemode) - actor->reactiontime = actor->info->reactiontime*TICRATE; - else - actor->reactiontime = actor->info->reactiontime*TICRATE*2; - } -} - -// Function: A_SuperFireShot -// -// Description: Shoot an object at your target that will even stall Super Sonic. -// -// var1 = object # to shoot -// var2 = height offset -// -void A_SuperFireShot(mobj_t *actor) -{ - fixed_t z; - mobj_t *mo; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SuperFireShot", actor)) - return; -#endif - if (!actor->target) - return; - - A_FaceTarget(actor); - - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); - - mo = P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z); - - if (mo) - mo->flags2 |= MF2_SUPERFIRE; - - if (!(actor->flags & MF_BOSS)) - { - if (ultimatemode) - actor->reactiontime = actor->info->reactiontime*TICRATE; - else - actor->reactiontime = actor->info->reactiontime*TICRATE*2; - } -} - -// Function: A_BossFireShot -// -// Description: Shoot an object at your target ala Bosses: -// -// var1 = object # to shoot -// var2: -// 0 - Boss 1 Left side -// 1 - Boss 1 Right side -// 2 - Boss 3 Left side upper -// 3 - Boss 3 Left side lower -// 4 - Boss 3 Right side upper -// 5 - Boss 3 Right side lower -// -void A_BossFireShot(mobj_t *actor) -{ - fixed_t x, y, z; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BossFireShot", actor)) - return; -#endif - if (!actor->target) - return; - - A_FaceTarget(actor); - - switch (locvar2) - { - case 0: - x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(48*FRACUNIT, actor->scale); - break; - case 1: - x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(48*FRACUNIT, actor->scale); - break; - case 2: - x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(42*FRACUNIT, actor->scale); - break; - case 3: - x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(30*FRACUNIT, actor->scale); - break; - case 4: - x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(42*FRACUNIT, actor->scale); - break; - case 5: - x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(30*FRACUNIT, actor->scale); - break; - default: - x = actor->x; - y = actor->y; - z = actor->z + actor->height/2; - break; - } - - P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z); -} - -// Function: A_Boss7FireMissiles -// -// Description: Shoot 4 missiles of a specific object type at your target ala Black Eggman -// -// var1 = object # to shoot -// var2 = firing sound -// -void A_Boss7FireMissiles(mobj_t *actor) -{ - mobj_t dummymo; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss7FireMissiles", actor)) - return; -#endif - - if (!actor->target) - { - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - A_FaceTarget(actor); - - S_StartSound(NULL, locvar2); - - // set dummymo's coordinates - dummymo.x = actor->target->x; - dummymo.y = actor->target->y; - dummymo.z = actor->target->z + FixedMul(16*FRACUNIT, actor->scale); // raised height - - P_SpawnXYZMissile(actor, &dummymo, locvar1, - actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->z + FixedDiv(actor->height, 3*FRACUNIT/2)); - - P_SpawnXYZMissile(actor, &dummymo, locvar1, - actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->z + FixedDiv(actor->height, 3*FRACUNIT/2)); - - P_SpawnXYZMissile(actor, &dummymo, locvar1, - actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->z + actor->height/2); - - P_SpawnXYZMissile(actor, &dummymo, locvar1, - actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), - actor->z + actor->height/2); -} - -// Function: A_Boss1Laser -// -// Description: Shoot an object at your target ala Bosses: -// -// var1 = object # to shoot -// var2: -// 0 - Boss 1 Left side -// 1 - Boss 1 Right side -// -void A_Boss1Laser(mobj_t *actor) -{ - fixed_t x, y, z, floorz, speed; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - INT32 i; - angle_t angle; - mobj_t *point; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss1Laser", actor)) - return; -#endif - if (!actor->target) - return; - - switch (locvar2) - { - case 0: - x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height; - else - z = actor->z + FixedMul(56*FRACUNIT, actor->scale); - break; - case 1: - x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height; - else - z = actor->z + FixedMul(56*FRACUNIT, actor->scale); - break; - default: - x = actor->x; - y = actor->y; - z = actor->z + actor->height/2; - break; - } - - if (!(actor->flags2 & MF2_FIRING)) - { - actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); - if (mobjinfo[locvar1].seesound) - S_StartSound(actor, mobjinfo[locvar1].seesound); - if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) - { - point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); - point->angle = actor->angle; - point->fuse = actor->tics+1; - P_SetTarget(&point->target, actor->target); - P_SetTarget(&actor->target, point); - } - } - /* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path - else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) - actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/ - - if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH) - angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); - else - angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); - point = P_SpawnMobj(x, y, z, locvar1); - P_SetTarget(&point->target, actor); - point->angle = actor->angle; - speed = point->radius*2; - point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed); - point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed)); - point->momy = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINESINE(point->angle>>ANGLETOFINESHIFT), speed)); - - for (i = 0; i < 256; i++) - { - mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type); - mo->angle = point->angle; - P_UnsetThingPosition(mo); - mo->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY; - P_SetThingPosition(mo); - - x = point->x, y = point->y, z = point->z; - if (P_RailThinker(point)) - break; - } - - floorz = P_FloorzAtPos(x, y, z, mobjinfo[MT_EGGMOBILE_FIRE].height); - if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1) - { - point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE); - point->target = actor; - point->destscale = 3*FRACUNIT; - point->scalespeed = FRACUNIT>>2; - point->fuse = TICRATE; - } - - if (actor->tics > 1) - actor->flags2 |= MF2_FIRING; - else - actor->flags2 &= ~MF2_FIRING; -} - -// Function: A_FocusTarget -// -// Description: Home in on your target. -// -// var1: -// 0 - accelerative focus with friction -// 1 - steady focus with fixed movement speed -// anything else - don't move -// var2: -// 0 - don't trace target, just move forwards -// & 1 - change horizontal angle -// & 2 - change vertical angle -// -void A_FocusTarget(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FocusTarget", actor)) - return; -#endif - - if (actor->target) - { - fixed_t speed = FixedMul(actor->info->speed, actor->scale); - fixed_t dist = (locvar2 ? R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) : speed+1); - angle_t hangle = ((locvar2 & 1) ? R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) : actor->angle); - angle_t vangle = ((locvar2 & 2) ? R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist) : ANGLE_90); - switch(locvar1) - { - case 0: - { - actor->momx -= actor->momx>>4, actor->momy -= actor->momy>>4, actor->momz -= actor->momz>>4; - actor->momz += FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed); - actor->momx += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed)); - actor->momy += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed)); - } - break; - case 1: - if (dist > speed) - { - actor->momz = FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed); - actor->momx = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed)); - actor->momy = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed)); - } - else - { - actor->momx = 0, actor->momy = 0, actor->momz = 0; - actor->z = actor->target->z + (actor->target->height>>1); - P_TryMove(actor, actor->target->x, actor->target->y, true); - } - break; - default: - break; - } - } -} - -// Function: A_Boss4Reverse -// -// Description: Reverse arms direction. -// -// var1 = sfx to play -// var2 = unused -// -void A_Boss4Reverse(mobj_t *actor) -{ - sfxenum_t locvar1 = (sfxenum_t)var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss4Reverse", actor)) - return; -#endif - S_StartSound(NULL, locvar1); - actor->reactiontime = 0; - if (actor->movedir == 1) - actor->movedir = 2; - else - actor->movedir = 1; -} - -// Function: A_Boss4SpeedUp -// -// Description: Speed up arms -// -// var1 = sfx to play -// var2 = unused -// -void A_Boss4SpeedUp(mobj_t *actor) -{ - sfxenum_t locvar1 = (sfxenum_t)var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss4SpeedUp", actor)) - return; -#endif - S_StartSound(NULL, locvar1); - actor->reactiontime = 2; -} - -// Function: A_Boss4Raise -// -// Description: Raise helmet -// -// var1 = sfx to play -// var2 = unused -// -void A_Boss4Raise(mobj_t *actor) -{ - sfxenum_t locvar1 = (sfxenum_t)var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss4Raise", actor)) - return; -#endif - S_StartSound(NULL, locvar1); - actor->reactiontime = 1; -} - -// Function: A_SkullAttack -// -// Description: Fly at the player like a missile. -// -// var1: -// 0 - Fly at the player -// 1 - Fly away from the player -// 2 - Strafe in relation to the player -// var2: -// 0 - Fly horizontally and vertically -// 1 - Fly horizontal-only (momz = 0) -// -#define SKULLSPEED (20*FRACUNIT) - -void A_SkullAttack(mobj_t *actor) -{ - mobj_t *dest; - angle_t an; - INT32 dist; - INT32 speed; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SkullAttack", actor)) - return; -#endif - if (!actor->target) - return; - - speed = FixedMul(SKULLSPEED, actor->scale); - - dest = actor->target; - actor->flags2 |= MF2_SKULLFLY; - if (actor->info->activesound) - S_StartSound(actor, actor->info->activesound); - A_FaceTarget(actor); - - if (locvar1 == 1) - actor->angle += ANGLE_180; - else if (locvar1 == 2) - actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90; - - an = actor->angle >> ANGLETOFINESHIFT; - - actor->momx = FixedMul(speed, FINECOSINE(an)); - actor->momy = FixedMul(speed, FINESINE(an)); - dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); - dist = dist / speed; - - if (dist < 1) - dist = 1; - - actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist; - - if (locvar1 == 1) - actor->momz = -actor->momz; - if (locvar2 == 1) - actor->momz = 0; -} - -// Function: A_BossZoom -// -// Description: Like A_SkullAttack, but used by Boss 1. -// -// var1 = unused -// var2 = unused -// -void A_BossZoom(mobj_t *actor) -{ - mobj_t *dest; - angle_t an; - INT32 dist; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BossZoom", actor)) - return; -#endif - if (!actor->target) - return; - - dest = actor->target; - actor->flags2 |= MF2_SKULLFLY; - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - A_FaceTarget(actor); - an = actor->angle >> ANGLETOFINESHIFT; - actor->momx = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINECOSINE(an)); - actor->momy = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINESINE(an)); - dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); - dist = dist / FixedMul(actor->info->speed*5*FRACUNIT, actor->scale); - - if (dist < 1) - dist = 1; - actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist; -} - -// Function: A_BossScream -// -// Description: Spawns explosions and plays appropriate sounds around the defeated boss. -// -// var1: -// 0 - Use movecount to spawn explosions evenly -// 1 - Use P_Random to spawn explosions at complete random -// var2 = Object to spawn. Default is MT_BOSSEXPLODE. -// -void A_BossScream(mobj_t *actor) -{ - mobj_t *mo; - fixed_t x, y, z; - angle_t fa; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobjtype_t explodetype; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BossScream", actor)) - return; -#endif - switch (locvar1) - { - default: - case 0: - actor->movecount += 4*16; - actor->movecount %= 360; - fa = (FixedAngle(actor->movecount*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; - break; - case 1: - fa = (FixedAngle(P_RandomKey(360)*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; - break; - } - x = actor->x + FixedMul(FINECOSINE(fa),actor->radius); - y = actor->y + FixedMul(FINESINE(fa),actor->radius); - - // Determine what mobj to spawn. If undefined or invalid, use MT_BOSSEXPLODE as default. - if (locvar2 <= 0 || locvar2 >= NUMMOBJTYPES) - explodetype = MT_BOSSEXPLODE; - else - explodetype = (mobjtype_t)locvar2; - - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - mobjinfo[explodetype].height - FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale); - - mo = P_SpawnMobj(x, y, z, explodetype); - if (actor->eflags & MFE_VERTICALFLIP) - mo->flags2 |= MF2_OBJECTFLIP; - mo->destscale = actor->scale; - P_SetScale(mo, mo->destscale); - if (actor->info->deathsound) - S_StartSound(mo, actor->info->deathsound); -} - -// Function: A_Scream -// -// Description: Starts the death sound of the object. -// -// var1 = unused -// var2 = unused -// -void A_Scream(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Scream", actor)) - return; -#endif - if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL)) - S_StartScreamSound(actor, sfx_mario2); - else if (actor->info->deathsound) - S_StartScreamSound(actor, actor->info->deathsound); -} - -// Function: A_Pain -// -// Description: Starts the pain sound of the object. -// -// var1 = unused -// var2 = unused -// -void A_Pain(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Pain", actor)) - return; -#endif - if (actor->info->painsound) - S_StartSound(actor, actor->info->painsound); - - actor->flags2 &= ~MF2_FIRING; - actor->flags2 &= ~MF2_SUPERFIRE; -} - -// Function: A_Fall -// -// Description: Changes a dying object's flags to reflect its having fallen to the ground. -// -// var1 = unused -// var2 = unused -// -void A_Fall(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Fall", actor)) - return; -#endif - // actor is on ground, it can be walked over - actor->flags &= ~MF_SOLID; - - // fall through the floor - actor->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; - - // So change this if corpse objects - // are meant to be obstacles. -} - -#define LIVESBOXDISPLAYPLAYER // Use displayplayer instead of closest player - -// Function: A_1upThinker -// -// Description: Used by the 1up box to show the player's face. -// -// var1 = unused -// var2 = unused -// -void A_1upThinker(mobj_t *actor) -{ - INT32 i; - fixed_t dist = INT32_MAX; - fixed_t temp; - INT32 closestplayer = -1; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_1upThinker", actor)) - return; -#endif - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].bot || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - if ((netgame || multiplayer) && players[i].playerstate != PST_LIVE) - continue; - - temp = P_AproxDistance(players[i].mo->x-actor->x, players[i].mo->y-actor->y); - - if (temp < dist) - { - closestplayer = i; - dist = temp; - } - } - - if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0) - { // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite. - if (actor->tracer) { - P_RemoveMobj(actor->tracer); - actor->tracer = NULL; - } - return; - } - - // We're using the overlay, so use the overlay 1up box (no text) - actor->sprite = SPR_TV1P; - - if (!actor->tracer) - { - P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY)); - P_SetTarget(&actor->tracer->target, actor); - actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame - P_SetMobjState(actor->tracer, actor->info->seestate); - - // The overlay is going to be one tic early turning off and on - // because it's going to get its thinker run the frame we spawned it. - // So make it take one tic longer if it just spawned. - ++actor->tracer->tics; - } - - actor->tracer->color = players[closestplayer].mo->color; - actor->tracer->skin = &skins[players[closestplayer].skin]; -} - -// Function: A_MonitorPop -// -// Description: Used by monitors when they explode. -// -// var1 = unused -// var2 = unused -// -void A_MonitorPop(mobj_t *actor) -{ - mobjtype_t item = 0; - mobj_t *newmobj; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MonitorPop", actor)) - return; -#endif - - // Spawn the "pop" explosion. - if (actor->info->deathsound) - S_StartSound(actor, actor->info->deathsound); - P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_EXPLODE); - - // We're dead now. De-solidify. - actor->health = 0; - P_UnsetThingPosition(actor); - actor->flags &= ~MF_SOLID; - actor->flags |= MF_NOCLIP; - P_SetThingPosition(actor); - - if (actor->info->damage == MT_UNKNOWN) - { - // MT_UNKNOWN is random. Because it's unknown to us... get it? - item = P_DoRandomBoxChances(); - - if (item == MT_NULL) - { - CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n")); - return; - } - } - else - item = actor->info->damage; - - if (item == 0) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n"); - return; - } - - newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item); - P_SetTarget(&newmobj->target, actor->target); // Transfer target - - if (item == MT_1UP_ICON) - { - if (actor->tracer) // Remove the old lives icon. - P_RemoveMobj(actor->tracer); - - if (!newmobj->target - || !newmobj->target->player - || !newmobj->target->skin - || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) - {} // No lives icon for this player, use the default. - else - { // Spawn the lives icon. - mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&livesico->target, newmobj); - P_SetTarget(&newmobj->tracer, livesico); - - livesico->color = newmobj->target->player->mo->color; - livesico->skin = &skins[newmobj->target->player->skin]; - P_SetMobjState(livesico, newmobj->info->seestate); - - // We're using the overlay, so use the overlay 1up sprite (no text) - newmobj->sprite = SPR_TV1P; - } - } -} - -// Function: A_GoldMonitorPop -// -// Description: Used by repeating monitors when they turn off. They don't really pop, but, you know... -// -// var1 = unused -// var2 = unused -// -void A_GoldMonitorPop(mobj_t *actor) -{ - mobjtype_t item = 0; - mobj_t *newmobj; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GoldMonitorPop", actor)) - return; -#endif - - // Don't spawn the "pop" explosion, because the monitor isn't broken. - if (actor->info->deathsound) - S_StartSound(actor, actor->info->deathsound); - //P_SpawnMobjFromMobj(actor, 0, 0, actor.height/4, MT_EXPLODE); - - // Remove our flags for a bit. - // Players can now stand on top of us. - P_UnsetThingPosition(actor); - actor->flags &= ~(MF_MONITOR|MF_SHOOTABLE); - P_SetThingPosition(actor); - - // Don't count this box in statistics. Sorry. - if (actor->target && actor->target->player) - --actor->target->player->numboxes; - actor->fuse = 0; // Don't let the monitor code screw us up. - - if (actor->info->damage == MT_UNKNOWN) - { - // MT_UNKNOWN is random. Because it's unknown to us... get it? - item = P_DoRandomBoxChances(); - - if (item == MT_NULL) - { - CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n")); - return; - } - } - else - item = actor->info->damage; - - if (item == 0) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_GoldMonitorPop\n"); - return; - } - - // Note: the icon spawns 1 fracunit higher - newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 14*FRACUNIT, item); - P_SetTarget(&newmobj->target, actor->target); // Transfer target - - if (item == MT_1UP_ICON) - { - if (actor->tracer) // Remove the old lives icon. - P_RemoveMobj(actor->tracer); - - if (!newmobj->target - || !newmobj->target->player - || !newmobj->target->skin - || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) - {} // No lives icon for this player, use the default. - else - { // Spawn the lives icon. - mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&livesico->target, newmobj); - P_SetTarget(&newmobj->tracer, livesico); - - livesico->color = newmobj->target->player->mo->color; - livesico->skin = &skins[newmobj->target->player->skin]; - P_SetMobjState(livesico, newmobj->info->seestate); - - // We're using the overlay, so use the overlay 1up sprite (no text) - newmobj->sprite = SPR_TV1P; - } - } -} - -// Function: A_GoldMonitorRestore -// -// Description: A repeating monitor is coming back to life. Reset monitor flags, etc. -// -// var1 = unused -// var2 = unused -// -void A_GoldMonitorRestore(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GoldMonitorRestore", actor)) - return; -#endif - - actor->flags |= MF_MONITOR|MF_SHOOTABLE; - actor->health = 1; // Just in case. -} - -// Function: A_GoldMonitorSparkle -// -// Description: Spawns the little sparkly effect around big monitors. Looks pretty, doesn't it? -// -// var1 = unused -// var2 = unused -// -void A_GoldMonitorSparkle(mobj_t *actor) -{ - fixed_t i, ngangle, xofs, yofs; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GoldMonitorSparkle", actor)) - return; -#endif - - ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS); - xofs = FINESINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); - yofs = FINECOSINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); - - for (i = FRACUNIT*2; i <= FRACUNIT*3; i += FRACUNIT/2) - P_SetObjectMomZ(P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE), i, false); -} - -// Function: A_Explode -// -// Description: Explodes an object, doing damage to any objects nearby. The target is used as the cause of the explosion. Damage value is used as explosion range. -// -// var1 = damagetype -// var2 = unused -// -void A_Explode(mobj_t *actor) -{ - INT32 locvar1 = var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Explode", actor)) - return; -#endif - P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1); -} - -// Function: A_BossDeath -// -// Description: Possibly trigger special effects when boss dies. -// -// var1 = unused -// var2 = unused -// -void A_BossDeath(mobj_t *mo) -{ - thinker_t *th; - mobj_t *mo2; - line_t junk; - INT32 i; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BossDeath", mo)) - return; -#endif - - P_LinedefExecute(LE_BOSSDEAD, mo, NULL); - mo->health = 0; - - // Boss is dead (but not necessarily fleeing...) - // Lua may use this to ignore bosses after they start fleeing - mo->flags2 |= MF2_BOSSDEAD; - - // make sure there is a player alive for victory - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && ((players[i].mo && players[i].mo->health) - || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) - break; - - if (i == MAXPLAYERS) - return; // no one left alive, so do not end game - - // scan the remaining thinkers to see - // if all bosses are dead - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - if (mo2 != mo && (mo2->flags & MF_BOSS) && mo2->health > 0) - goto bossjustdie; // other boss not dead - just go straight to dying! - } - - // victory! - P_LinedefExecute(LE_ALLBOSSESDEAD, mo, NULL); - if (mo->flags2 & MF2_BOSSNOTRAP) - { - for (i = 0; i < MAXPLAYERS; i++) - P_DoPlayerExit(&players[i]); - } - else - { - // Bring the egg trap up to the surface - junk.tag = 680; - EV_DoElevator(&junk, elevateHighest, false); - junk.tag = 681; - EV_DoElevator(&junk, elevateUp, false); - junk.tag = 682; - EV_DoElevator(&junk, elevateHighest, false); - } - -bossjustdie: -#ifdef HAVE_BLUA - if (LUAh_BossDeath(mo)) - return; - else if (P_MobjWasRemoved(mo)) - return; -#endif - if (mo->type == MT_BLACKEGGMAN || mo->type == MT_CYBRAKDEMON) - { - mo->flags |= MF_NOCLIP; - mo->flags &= ~MF_SPECIAL; - - S_StartSound(NULL, sfx_befall); - } - else if (mo->type == MT_KOOPA) - { - junk.tag = 650; - EV_DoCeiling(&junk, raiseToHighest); - return; - } - else // eggmobiles - { - // Stop exploding and prepare to run. - P_SetMobjState(mo, mo->info->xdeathstate); - if (P_MobjWasRemoved(mo)) - return; - - P_SetTarget(&mo->target, NULL); - - // Flee! Flee! Find a point to escape to! If none, just shoot upward! - // scan the thinkers to find the runaway point - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == MT_BOSSFLYPOINT) - { - // If this one's closer then the last one, go for it. - if (!mo->target || - P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) < - P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z)) - P_SetTarget(&mo->target, mo2); - // Otherwise... Don't! - } - } - - mo->flags |= MF_NOGRAVITY|MF_NOCLIP; - mo->flags |= MF_NOCLIPHEIGHT; - - if (mo->target) - { - mo->angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y); - mo->flags2 |= MF2_BOSSFLEE; - mo->momz = FixedMul(FixedDiv(mo->target->z - mo->z, P_AproxDistance(mo->x-mo->target->x,mo->y-mo->target->y)), FixedMul(2*FRACUNIT, mo->scale)); - } - else - mo->momz = FixedMul(2*FRACUNIT, mo->scale); - } - - if (mo->type == MT_EGGMOBILE2) - { - mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->y + P_ReturnThrustY(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK1].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK1); // Right tank - mo2->angle = mo->angle; - mo2->destscale = mo->scale; - P_SetScale(mo2, mo2->destscale); - if (mo->eflags & MFE_VERTICALFLIP) - { - mo2->eflags |= MFE_VERTICALFLIP; - mo2->flags2 |= MF2_OBJECTFLIP; - } - P_InstaThrust(mo2, mo2->angle - ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale)); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - - mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->y + P_ReturnThrustY(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK2].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK2); // Left tank - mo2->angle = mo->angle; - mo2->destscale = mo->scale; - P_SetScale(mo2, mo2->destscale); - if (mo->eflags & MFE_VERTICALFLIP) - { - mo2->eflags |= MFE_VERTICALFLIP; - mo2->flags2 |= MF2_OBJECTFLIP; - } - P_InstaThrust(mo2, mo2->angle + ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale)); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - - mo2 = P_SpawnMobj(mo->x, mo->y, - mo->z + ((mo->eflags & MFE_VERTICALFLIP)? mobjinfo[MT_BOSSSPIGOT].height-FixedMul(32*FRACUNIT,mo->scale): mo->height + FixedMul(32*FRACUNIT, mo->scale)), MT_BOSSSPIGOT); - mo2->angle = mo->angle; - mo2->destscale = mo->scale; - P_SetScale(mo2, mo2->destscale); - if (mo->eflags & MFE_VERTICALFLIP) - { - mo2->eflags |= MFE_VERTICALFLIP; - mo2->flags2 |= MF2_OBJECTFLIP; - } - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - return; - } -} - -// Function: A_CustomPower -// -// Description: Provides a custom powerup. Target (must be a player) is awarded the powerup. Reactiontime of the object is used as an index to the powers array. -// -// var1 = Power index # -// var2 = Power duration in tics -// -void A_CustomPower(mobj_t *actor) -{ - player_t *player; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - boolean spawnshield = false; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CustomPower", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - if (locvar1 >= NUMPOWERS) - { - CONS_Debug(DBG_GAMELOGIC, "Power #%d out of range!\n", locvar1); - return; - } - - player = actor->target->player; - - if (locvar1 == pw_shield && player->powers[pw_shield] != locvar2) - spawnshield = true; - - player->powers[locvar1] = (UINT16)locvar2; - if (actor->info->seesound) - S_StartSound(player->mo, actor->info->seesound); - - if (spawnshield) //workaround for a bug - P_SpawnShieldOrb(player); -} - -// Function: A_GiveWeapon -// -// Description: Gives the player the specified weapon panels. -// -// var1 = Weapon index # -// var2 = unused -// -void A_GiveWeapon(mobj_t *actor) -{ - player_t *player; - INT32 locvar1 = var1; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GiveWeapon", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - if (locvar1 >= 1<<(NUM_WEAPONS-1)) - { - CONS_Debug(DBG_GAMELOGIC, "Weapon #%d out of range!\n", locvar1); - return; - } - - player = actor->target->player; - - player->ringweapons |= locvar1; - if (actor->info->seesound) - S_StartSound(player->mo, actor->info->seesound); -} - -// Function: A_RingBox -// -// Description: Awards the player 10 rings. -// -// var1 = unused -// var2 = unused -// -void A_RingBox(mobj_t *actor) -{ - player_t *player; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RingBox", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - player = actor->target->player; - - P_GivePlayerRings(player, actor->info->reactiontime); - if (actor->info->seesound) - S_StartSound(player->mo, actor->info->seesound); -} - -// Function: A_Invincibility -// -// Description: Awards the player invincibility. -// -// var1 = unused -// var2 = unused -// -void A_Invincibility(mobj_t *actor) -{ - player_t *player; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Invincibility", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - player = actor->target->player; - player->powers[pw_invulnerability] = invulntics + 1; - - if (P_IsLocalPlayer(player) && !player->powers[pw_super]) - { - S_StopMusic(); - if (mariomode) - G_GhostAddColor(GHC_INVINCIBLE); - strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14); - S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]); - S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); - } -} - -// Function: A_SuperSneakers -// -// Description: Awards the player super sneakers. -// -// var1 = unused -// var2 = unused -// -void A_SuperSneakers(mobj_t *actor) -{ - player_t *player; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SuperSneakers", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - player = actor->target->player; - - actor->target->player->powers[pw_sneakers] = sneakertics + 1; - - if (P_IsLocalPlayer(player) && !player->powers[pw_super]) - { - if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)) - S_SpeedMusic(1.4f); - else - { - S_StopMusic(); - S_ChangeMusicInternal("_shoes", false); - } - strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12); - S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]); - } -} - -// Function: A_AwardScore -// -// Description: Adds a set amount of points to the player's score. -// -// var1 = unused -// var2 = unused -// -void A_AwardScore(mobj_t *actor) -{ - player_t *player; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_AwardScore", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - player = actor->target->player; - - P_AddPlayerScore(player, actor->info->reactiontime); - if (actor->info->seesound) - S_StartSound(player->mo, actor->info->seesound); -} - -// Function: A_ExtraLife -// -// Description: Awards the player an extra life. -// -// var1 = unused -// var2 = unused -// -void A_ExtraLife(mobj_t *actor) -{ - player_t *player; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ExtraLife", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - player = actor->target->player; - - if (actor->type == MT_1UP_ICON && actor->tracer) - { - // We're using the overlay, so use the overlay 1up sprite (no text) - actor->sprite = SPR_TV1P; - } - - if (ultimatemode) //I don't THINK so! - { - S_StartSound(player->mo, sfx_lose); - return; - } - - P_GiveCoopLives(player, 1, true); -} - -// Function: A_GiveShield -// -// Description: Awards the player a specified shield. -// -// var1 = Shield type (make with SH_ constants) -// var2 = unused -// -void A_GiveShield(mobj_t *actor) -{ - player_t *player; - UINT16 locvar1 = var1; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GiveShield", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - player = actor->target->player; - - P_SwitchShield(player, locvar1); - S_StartSound(player->mo, actor->info->seesound); -} - -// Function: A_GravityBox -// -// Description: Awards the player gravity boots. -// -// var1 = unused -// var2 = unused -// -void A_GravityBox(mobj_t *actor) -{ - player_t *player; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GravityBox", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - player = actor->target->player; - - S_StartSound(player, actor->info->activesound); - - player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1); -} - -// Function: A_ScoreRise -// -// Description: Makes the little score logos rise. Speed value sets speed. -// -// var1 = unused -// var2 = unused -// -void A_ScoreRise(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ScoreRise", actor)) - return; -#endif - // make logo rise! - P_SetObjectMomZ(actor, actor->info->speed, false); -} - -// Function: A_ParticleSpawn -// -// Description: Hyper-specialised function for spawning a particle for MT_PARTICLEGEN. -// -// var1 = unused -// var2 = unused -// -void A_ParticleSpawn(mobj_t *actor) -{ - INT32 i = 0; - mobj_t *spawn; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ParticleSpawn", actor)) - return; -#endif - if (!actor->health) - return; - - if (!actor->lastlook) - return; - - if (!actor->threshold) - return; - - for (i = 0; i < actor->lastlook; i++) - { - spawn = P_SpawnMobj( - actor->x + FixedMul(FixedMul(actor->friction, actor->scale), FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), - actor->y + FixedMul(FixedMul(actor->friction, actor->scale), FINESINE(actor->angle>>ANGLETOFINESHIFT)), - actor->z, - (mobjtype_t)actor->threshold); - P_SetScale(spawn, actor->scale); - spawn->momz = FixedMul(actor->movefactor, spawn->scale); - spawn->destscale = spawn->scale/100; - spawn->scalespeed = spawn->scale/actor->health; - spawn->tics = (tic_t)actor->health; - spawn->flags2 |= (actor->flags2 & MF2_OBJECTFLIP); - spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones - - actor->angle += actor->movedir; - } - - actor->angle += (angle_t)actor->movecount; - actor->tics = (tic_t)actor->reactiontime; -} - -// Function: A_BunnyHop -// -// Description: Makes object hop like a bunny. -// -// var1 = jump strength -// var2 = horizontal movement -// -void A_BunnyHop(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BunnyHop", actor)) - return; -#endif - if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) - || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) - { - P_SetObjectMomZ(actor, locvar1*FRACUNIT, false); - P_InstaThrust(actor, actor->angle, FixedMul(locvar2*FRACUNIT, actor->scale)); // Launch the hopping action! PHOOM!! - } -} - -// Function: A_BubbleSpawn -// -// Description: Spawns a randomly sized bubble from the object's location. Only works underwater. -// -// var1 = Distance to look for players. If no player is in this distance, bubbles aren't spawned. (Ambush overrides) -// var2 = unused -// -void A_BubbleSpawn(mobj_t *actor) -{ - INT32 i, locvar1 = var1; - UINT8 prandom; - mobj_t *bubble = NULL; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BubbleSpawn", actor)) - return; -#endif - if (!(actor->eflags & MFE_UNDERWATER)) - { - // Don't draw or spawn bubbles above water - actor->flags2 |= MF2_DONTDRAW; - return; - } - actor->flags2 &= ~MF2_DONTDRAW; - - if (!(actor->flags2 & MF2_AMBUSH)) - { - // Quick! Look through players! - // Don't spawn bubbles unless a player is relatively close by (var1). - for (i = 0; i < MAXPLAYERS; ++i) - if (playeringame[i] && players[i].mo - && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<x, actor->y, actor->z + (actor->height / 2), MT_EXTRALARGEBUBBLE); - else if (prandom > 128) - bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_SMALLBUBBLE); - else if (prandom < 128 && prandom > 96) - bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_MEDIUMBUBBLE); - - if (bubble) - { - bubble->destscale = actor->scale; - P_SetScale(bubble, actor->scale); - } -} - -// Function: A_FanBubbleSpawn -// -// Description: Spawns bubbles from fans, if they're underwater. -// -// var1 = Distance to look for players. If no player is in this distance, bubbles aren't spawned. (Ambush overrides) -// var2 = unused -// -void A_FanBubbleSpawn(mobj_t *actor) -{ - INT32 i, locvar1 = var1; - UINT8 prandom; - mobj_t *bubble = NULL; - fixed_t hz = actor->z + (4*actor->height)/5; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FanBubbleSpawn", actor)) - return; -#endif - if (!(actor->eflags & MFE_UNDERWATER)) - return; - - if (!(actor->flags2 & MF2_AMBUSH)) - { - // Quick! Look through players! - // Don't spawn bubbles unless a player is relatively close by (var2). - for (i = 0; i < MAXPLAYERS; ++i) - if (playeringame[i] && players[i].mo - && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<x, actor->y, hz, MT_SMALLBUBBLE); - else if ((prandom & 0xF0) == 0xF0) - bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_MEDIUMBUBBLE); - - if (bubble) - { - bubble->destscale = actor->scale; - P_SetScale(bubble, actor->scale); - } -} - -// Function: A_BubbleRise -// -// Description: Raises a bubble -// -// var1: -// 0 = Bend around the water abit, looking more realistic -// 1 = Rise straight up -// var2 = rising speed -// -void A_BubbleRise(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BubbleRise", actor)) - return; -#endif - if (actor->type == MT_EXTRALARGEBUBBLE) - P_SetObjectMomZ(actor, FixedDiv(6*FRACUNIT,5*FRACUNIT), false); // make bubbles rise! - else - { - P_SetObjectMomZ(actor, locvar2, true); // make bubbles rise! - - // Move around slightly to make it look like it's bending around the water - if (!locvar1) - { - UINT8 prandom = P_RandomByte(); - if (!(prandom & 0x7)) // *****000 - { - P_InstaThrust(actor, prandom & 0x70 ? actor->angle + ANGLE_90 : actor->angle, - FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale)); - } - else if (!(prandom & 0x38)) // **000*** - { - P_InstaThrust(actor, prandom & 0x70 ? actor->angle - ANGLE_90 : actor->angle - ANGLE_180, - FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale)); - } - } - } -} - -// Function: A_BubbleCheck -// -// Description: Checks if a bubble should be drawn or not. Bubbles are not drawn above water. -// -// var1 = unused -// var2 = unused -// -void A_BubbleCheck(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BubbleCheck", actor)) - return; -#endif - if (actor->eflags & MFE_UNDERWATER) - actor->flags2 &= ~MF2_DONTDRAW; // underwater so draw - else - actor->flags2 |= MF2_DONTDRAW; // above water so don't draw -} - -// Function: A_AttractChase -// -// Description: Makes a ring chase after a player with a ring shield and also causes spilled rings to flicker. -// -// var1 = unused -// var2 = unused -// -void A_AttractChase(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_AttractChase", actor)) - return; -#endif - if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) - return; - - // spilled rings flicker before disappearing - if (leveltime & 1 && actor->type == (mobjtype_t)actor->info->reactiontime && actor->fuse && actor->fuse < 2*TICRATE) - actor->flags2 |= MF2_DONTDRAW; - else - actor->flags2 &= ~MF2_DONTDRAW; - - // Turn flingrings back into regular rings if attracted. - if (actor->tracer && actor->tracer->player - && !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) - { - mobj_t *newring; - newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); - newring->momx = actor->momx; - newring->momy = actor->momy; - newring->momz = actor->momz; - P_RemoveMobj(actor); - return; - } - - P_LookForShield(actor); // Go find 'em, boy! - - if (!actor->tracer - || !actor->tracer->player - || !actor->tracer->health - || !P_CheckSight(actor, actor->tracer)) // You have to be able to SEE it...sorta - { - // Lost attracted rings don't through walls anymore. - actor->flags &= ~MF_NOCLIP; - P_SetTarget(&actor->tracer, NULL); - return; - } - - // If a FlingRing gets attracted by a shield, change it into a normal ring. - if (actor->type == (mobjtype_t)actor->info->reactiontime) - { - P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); - P_RemoveMobj(actor); - return; - } - - // Keep stuff from going down inside floors and junk - actor->flags &= ~MF_NOCLIPHEIGHT; - - // Let attracted rings move through walls and such. - actor->flags |= MF_NOCLIP; - - P_Attract(actor, actor->tracer, false); -} - -// Function: A_DropMine -// -// Description: Drops a mine. Raisestate specifies the object # to use for the mine. -// -// var1 = height offset -// var2: -// lower 16 bits = proximity check distance (0 disables) -// upper 16 bits = 0 to check proximity with target, 1 for tracer -// -void A_DropMine(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - fixed_t z; - mobj_t *mine; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_DropMine", actor)) - return; -#endif - - if (locvar2 & 65535) - { - fixed_t dist; - mobj_t *target; - - if (locvar2 >> 16) - target = actor->tracer; - else - target = actor->target; - - if (!target) - return; - - dist = P_AproxDistance(actor->x-target->x, actor->y-target->y)>>FRACBITS; - - if (dist > FixedMul((locvar2 & 65535), actor->scale)) - return; - } - - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - mobjinfo[actor->info->raisestate].height - FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale); - - // Use raisestate instead of MT_MINE - mine = P_SpawnMobj(actor->x, actor->y, z, (mobjtype_t)actor->info->raisestate); - if (actor->eflags & MFE_VERTICALFLIP) - mine->eflags |= MFE_VERTICALFLIP; - mine->momz = actor->momz + actor->pmomz; - - S_StartSound(actor, actor->info->attacksound); -} - -// Function: A_FishJump -// -// Description: Makes the stupid harmless fish in Greenflower Zone jump. -// -// var1 = Jump strength (in FRACBITS), if specified. Otherwise, uses the angle value. -// var2 = unused -// -void A_FishJump(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FishJump", actor)) - return; -#endif - - if (locvar2) - { - fixed_t rad = actor->radius>>FRACBITS; - P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale))) - { - fixed_t jumpval; - - if (locvar1) - jumpval = var1; - else - jumpval = FixedMul(AngleFixed(actor->angle)/4, actor->scale); - - if (!jumpval) jumpval = FixedMul(44*(FRACUNIT/4), actor->scale); - actor->momz = jumpval; - P_SetMobjStateNF(actor, actor->info->seestate); - } - - if (actor->momz < 0 - && (actor->state < &states[actor->info->meleestate] || actor->state > &states[actor->info->xdeathstate])) - P_SetMobjStateNF(actor, actor->info->meleestate); -} - -// Function:A_ThrownRing -// -// Description: Thinker for thrown rings/sparkle trail -// -// var1 = unused -// var2 = unused -// -void A_ThrownRing(mobj_t *actor) -{ - INT32 c = 0; - INT32 stop; - player_t *player; - fixed_t dist; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ThrownRing", actor)) - return; -#endif - - if (leveltime % (TICRATE/7) == 0) - { - mobj_t *ring = NULL; - - if (actor->flags2 & MF2_EXPLOSION) - { - if (actor->momx != 0 || actor->momy != 0) - ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOKE); - // Else spawn nothing because it's totally stationary and constantly smoking would be weird -SH - } - else if (actor->flags2 & MF2_AUTOMATIC) - ring = P_SpawnGhostMobj(actor); - else if (!(actor->flags2 & MF2_RAILRING)) - ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPARK); - - if (ring) - { - /* - P_SetTarget(&ring->target, actor); - ring->color = actor->color; //copy color - */ - ring->destscale = actor->scale; - P_SetScale(ring, actor->scale); - } - } - - // A_GrenadeRing beeping lives once moooooore -SH - if (actor->type == MT_THROWNGRENADE && actor->fuse % TICRATE == 0) - S_StartSound(actor, actor->info->attacksound); - - // decrement bounce ring time - if (actor->flags2 & MF2_BOUNCERING) - { - if (actor->fuse) - actor->fuse--; - else { - P_RemoveMobj(actor); - return; - } - } - - // spilled rings (and thrown bounce) flicker before disappearing - if (leveltime & 1 && actor->fuse > 0 && actor->fuse < 2*TICRATE - && actor->type != MT_THROWNGRENADE) - actor->flags2 |= MF2_DONTDRAW; - else - actor->flags2 &= ~MF2_DONTDRAW; - - if (actor->tracer && actor->tracer->health <= 0) - P_SetTarget(&actor->tracer, NULL); - - // Updated homing ring special capability - // If you have a ring shield, all rings thrown - // at you become homing (except rail)! - if (actor->tracer) - { - // A non-homing ring getting attracted by a - // magnetic player. If he gets too far away, make - // sure to stop the attraction! - if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) - && P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x, - actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale))) - { - P_SetTarget(&actor->tracer, NULL); - } - - if (actor->tracer && (actor->tracer->health) - && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow. - { - const INT32 temp = actor->threshold; - actor->threshold = 32000; - P_HomingAttack(actor, actor->tracer); - actor->threshold = temp; - return; - } - } - - // first time init, this allow minimum lastlook changes - if (actor->lastlook < 0) - actor->lastlook = P_RandomByte(); - - actor->lastlook %= MAXPLAYERS; - - stop = (actor->lastlook - 1) & PLAYERSMASK; - - for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK) - { - // done looking - if (actor->lastlook == stop) - return; - - if (!playeringame[actor->lastlook]) - continue; - - if (c++ == 2) - return; - - player = &players[actor->lastlook]; - - if (!player->mo) - continue; - - if (player->mo->health <= 0) - continue; // dead - - if ((netgame || multiplayer) && player->spectator) - continue; // spectator - - if (actor->target && actor->target->player) - { - if (player->mo == actor->target) - continue; - - // Don't home in on teammates. - if (gametype == GT_CTF - && actor->target->player->ctfteam == player->ctfteam) - continue; - } - - dist = P_AproxDistance(P_AproxDistance(player->mo->x-actor->x, - player->mo->y-actor->y), player->mo->z-actor->z); - - // check distance - if (actor->flags2 & MF2_RAILRING) - { - if (dist > FixedMul(RING_DIST/2, player->mo->scale)) - continue; - } - else if (dist > FixedMul(RING_DIST, player->mo->scale)) - continue; - - // do this after distance check because it's more computationally expensive - if (!P_CheckSight(actor, player->mo)) - continue; // out of sight - - if ((player->powers[pw_shield] & SH_PROTECTELECTRIC) - && dist < FixedMul(RING_DIST/4, player->mo->scale)) - P_SetTarget(&actor->tracer, player->mo); - return; - } - - return; -} - -// Function: A_SetSolidSteam -// -// Description: Makes steam solid so it collides with the player to boost them. -// -// var1 = unused -// var2 = unused -// -void A_SetSolidSteam(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetSolidSteam", actor)) - return; -#endif - actor->flags &= ~MF_NOCLIP; - actor->flags |= MF_SOLID; - if (!(actor->flags2 & MF2_AMBUSH)) - { - if (P_RandomChance(FRACUNIT/8)) - { - if (actor->info->deathsound) - S_StartSound(actor, actor->info->deathsound); // Hiss! - } - else - { - if (actor->info->painsound) - S_StartSound(actor, actor->info->painsound); - } - } - - P_SetObjectMomZ (actor, 1, true); -} - -// Function: A_UnsetSolidSteam -// -// Description: Makes an object non-solid and also noclip. Used by the steam. -// -// var1 = unused -// var2 = unused -// -void A_UnsetSolidSteam(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_UnsetSolidSteam", actor)) - return; -#endif - actor->flags &= ~MF_SOLID; - actor->flags |= MF_NOCLIP; -} - -// Function: A_SignPlayer -// -// Description: Changes the state of a level end sign to reflect the player that hit it. -// -// var1 = unused -// var2 = unused -// -void A_SignPlayer(mobj_t *actor) -{ - mobj_t *ov; - skin_t *skin; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SignPlayer", actor)) - return; -#endif - if (!actor->target) - return; - - if (!actor->target->player) - return; - - skin = &skins[actor->target->player->skin]; - - if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor? - { - actor->color = skin->prefoppositecolor; - /* - If you're here from the comment above Color_Opposite, - the following line is the one which is dependent on the - array being symmetrical. It gets the opposite of the - opposite of your desired colour just so it can get the - brightness frame for the End Sign. It's not a great - design choice, but it's constant time array access and - the idea that the colours should be OPPOSITES is kind - of in the name. If you have a better idea, feel free - to let me know. ~toast 2016/07/20 - */ - actor->frame += (15 - Color_Opposite[(Color_Opposite[(skin->prefoppositecolor - 1)*2] - 1)*2 + 1]); - } - else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor. - { - actor->color = Color_Opposite[(actor->target->player->skincolor - 1)*2]; - actor->frame += (15 - Color_Opposite[(actor->target->player->skincolor - 1)*2 + 1]); - } - - if (skin->sprites[SPR2_SIGN].numframes) - { - // spawn an overlay of the player's face. - ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY); - P_SetTarget(&ov->target, actor); - ov->color = actor->target->player->skincolor; - ov->skin = skin; - P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN - } -} - -// Function: A_OverlayThink -// -// Description: Moves the overlay to the position of its target. -// -// var1 = unused -// var2 = invert, z offset -// -void A_OverlayThink(mobj_t *actor) -{ - fixed_t destx, desty; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_OverlayThink", actor)) - return; -#endif - if (!actor->target) - return; - - if (!splitscreen && rendermode != render_soft) - { - angle_t viewingangle; - - if (players[displayplayer].awayviewtics) - viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); - else if (!camera.chase && players[displayplayer].mo) - viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); - else - viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, camera.x, camera.y); - - destx = actor->target->x + P_ReturnThrustX(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale)); - desty = actor->target->y + P_ReturnThrustY(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale)); - } - else - { - destx = actor->target->x; - desty = actor->target->y; - } - P_UnsetThingPosition(actor); - actor->x = destx; - actor->y = desty; - P_SetThingPosition(actor); - if (actor->eflags & MFE_VERTICALFLIP) - actor->z = actor->target->z + actor->target->height - mobjinfo[actor->type].height - ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; - else - actor->z = actor->target->z + ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; - actor->angle = actor->target->angle; - actor->eflags = actor->target->eflags; - - actor->momx = actor->target->momx; - actor->momy = actor->target->momy; - actor->momz = actor->target->momz; // assume target has correct momz! Do not use P_SetObjectMomZ! -} - -// Function: A_JetChase -// -// Description: A_Chase for Jettysyns -// -// var1 = unused -// var2 = unused -// -void A_JetChase(mobj_t *actor) -{ - fixed_t thefloor; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_JetChase", actor)) - return; -#endif - - if (actor->flags2 & MF2_AMBUSH) - return; - - if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz - && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) - thefloor = actor->watertop; - else - thefloor = actor->floorz; - - if (actor->reactiontime) - actor->reactiontime--; - - if (P_RandomChance(FRACUNIT/32)) - { - actor->momx = actor->momx / 2; - actor->momy = actor->momy / 2; - actor->momz = actor->momz / 2; - } - - // Bounce if too close to floor or ceiling - - // ideal for Jetty-Syns above you on 3d floors - if (actor->momz && ((actor->z - FixedMul((32<scale)) < thefloor) && !((thefloor + FixedMul(32*FRACUNIT, actor->scale) + actor->height) > actor->ceilingz)) - actor->momz = -actor->momz/2; - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - actor->momx = actor->momy = actor->momz = 0; - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - // modify target threshold - if (actor->threshold) - { - if (!actor->target || actor->target->health <= 0) - actor->threshold = 0; - else - actor->threshold--; - } - - // turn towards movement direction if not there yet - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - - if ((multiplayer || netgame) && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))) - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - // If the player is over 3072 fracunits away, then look for another player - if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), - actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale))) - { - return; // got a new target - } - - // chase towards player - if (ultimatemode) - P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/2, actor->scale)); - else - P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/4, actor->scale)); - - // must adjust height - if (ultimatemode) - { - if (actor->z < (actor->target->z + actor->target->height + FixedMul((64<scale))) - actor->momz += FixedMul(FRACUNIT/2, actor->scale); - else - actor->momz -= FixedMul(FRACUNIT/2, actor->scale); - } - else - { - if (actor->z < (actor->target->z + actor->target->height + FixedMul((32<scale))) - actor->momz += FixedMul(FRACUNIT/2, actor->scale); - else - actor->momz -= FixedMul(FRACUNIT/2, actor->scale); - } -} - -// Function: A_JetbThink -// -// Description: Thinker for Jetty-Syn bombers -// -// var1 = unused -// var2 = unused -// -void A_JetbThink(mobj_t *actor) -{ - sector_t *nextsector; - fixed_t thefloor; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_JetbThink", actor)) - return; -#endif - - if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz - && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) - thefloor = actor->watertop; - else - thefloor = actor->floorz; - - if (actor->target) - { - A_JetChase(actor); - // check for melee attack - if (actor->info->raisestate - && (actor->z > (actor->floorz + FixedMul((32<scale))) - && P_JetbCheckMeleeRange(actor) && !actor->reactiontime - && (actor->target->z >= actor->floorz)) - { - mobj_t *bomb; - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - - // use raisestate instead of MT_MINE - bomb = P_SpawnMobj(actor->x, actor->y, actor->z - FixedMul((32<scale), (mobjtype_t)actor->info->raisestate); - - P_SetTarget(&bomb->target, actor); - bomb->destscale = actor->scale; - P_SetScale(bomb, actor->scale); - actor->reactiontime = TICRATE; // one second - S_StartSound(actor, actor->info->attacksound); - } - } - else if (((actor->z - FixedMul((32<scale)) < thefloor) && !((thefloor + FixedMul((32<scale) + actor->height) > actor->ceilingz)) - actor->z = thefloor+FixedMul((32<scale); - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector; - - // Move downwards or upwards to go through a passageway. - if (nextsector->ceilingheight < actor->z + actor->height) - actor->momz -= FixedMul(5*FRACUNIT, actor->scale); - else if (nextsector->floorheight > actor->z) - actor->momz += FixedMul(5*FRACUNIT, actor->scale); -} - -// Function: A_JetgShoot -// -// Description: Firing function for Jetty-Syn gunners. -// -// var1 = unused -// var2 = unused -// -void A_JetgShoot(mobj_t *actor) -{ - fixed_t dist; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_JetgShoot", actor)) - return; -#endif - - if (!actor->target) - return; - - if (actor->reactiontime) - return; - - dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); - - if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale)) - return; - - if (dist < FixedMul(64*FRACUNIT, actor->scale)) - return; - - A_FaceTarget(actor); - P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate); - - if (ultimatemode) - actor->reactiontime = actor->info->reactiontime*TICRATE; - else - actor->reactiontime = actor->info->reactiontime*TICRATE*2; - - if (actor->info->attacksound) - S_StartSound(actor, actor->info->attacksound); -} - -// Function: A_ShootBullet -// -// Description: Shoots a bullet. Raisestate defines object # to use as projectile. -// -// var1 = unused -// var2 = unused -// -void A_ShootBullet(mobj_t *actor) -{ - fixed_t dist; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ShootBullet", actor)) - return; -#endif - - if (!actor->target) - return; - - dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z); - - if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale)) - return; - - A_FaceTarget(actor); - P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate); - - if (actor->info->attacksound) - S_StartSound(actor, actor->info->attacksound); -} - -// Function: A_MinusDigging -// -// Description: Minus digging in the ground. -// -// var1 = unused -// var2 = unused -// -void A_MinusDigging(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MinusDigging", actor)) - return; -#endif - actor->flags &= ~MF_SPECIAL; - actor->flags &= ~MF_SHOOTABLE; - - if (!actor->target) - { - A_Look(actor); - return; - } - - if (actor->reactiontime) - { - actor->reactiontime--; - return; - } - - // Dirt trail - P_SpawnGhostMobj(actor); - - actor->flags |= MF_NOCLIPTHING; - var1 = 3; - A_Chase(actor); - actor->flags &= ~MF_NOCLIPTHING; - - // Play digging sound - if (!(leveltime & 15)) - S_StartSound(actor, actor->info->activesound); - - // If we're close enough to our target, pop out of the ground - if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < actor->radius - && abs(actor->target->z - actor->z) < 2*actor->height) - P_SetMobjState(actor, actor->info->missilestate); - - // Snap to ground - if (actor->eflags & MFE_VERTICALFLIP) - actor->z = actor->ceilingz - actor->height; - else - actor->z = actor->floorz; -} - -// Function: A_MinusPopup -// -// Description: Minus popping out of the ground. -// -// var1 = unused -// var2 = unused -// -void A_MinusPopup(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MinusPopup", actor)) - return; -#endif - P_SetObjectMomZ(actor, 10*FRACUNIT, false); - - actor->flags |= MF_SPECIAL; - actor->flags |= MF_SHOOTABLE; - - // Sound for busting out of the ground. - S_StartSound(actor, actor->info->attacksound); -} - -// Function: A_MinusCheck -// -// Description: If the minus hits the floor, dig back into the ground. -// -// var1 = unused -// var2 = unused -// -void A_MinusCheck(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MinusCheck", actor)) - return; -#endif - if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) - || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)) - { - actor->flags &= ~MF_SPECIAL; - actor->flags &= ~MF_SHOOTABLE; - actor->reactiontime = TICRATE; - P_SetMobjState(actor, actor->info->seestate); - return; - } - - // 'Falling' animation - if (P_MobjFlip(actor)*actor->momz < 0 && actor->state < &states[actor->info->meleestate]) - P_SetMobjState(actor, actor->info->meleestate); -} - -// Function: A_ChickenCheck -// -// Description: Resets the chicken once it hits the floor again. -// -// var1 = unused -// var2 = unused -// -void A_ChickenCheck(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ChickenCheck", actor)) - return; -#endif - if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) - || (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height >= actor->ceilingz)) - { - if (!(actor->momx || actor->momy || actor->momz) - && actor->state > &states[actor->info->seestate]) - { - A_Chase(actor); - P_SetMobjState(actor, actor->info->seestate); - } - - actor->momx >>= 2; - actor->momy >>= 2; - } -} - -// Function: A_JetgThink -// -// Description: Thinker for Jetty-Syn Gunners -// -// var1 = unused -// var2 = unused -// -void A_JetgThink(mobj_t *actor) -{ - sector_t *nextsector; - - fixed_t thefloor; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_JetgThink", actor)) - return; -#endif - - if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz - && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) - thefloor = actor->watertop; - else - thefloor = actor->floorz; - - if (actor->target) - { - if (P_RandomChance(FRACUNIT/8) && !actor->reactiontime) - P_SetMobjState(actor, actor->info->missilestate); - else - A_JetChase (actor); - } - else if (actor->z - FixedMul((32<scale) < thefloor && !(thefloor + FixedMul((32<scale) - + actor->height > actor->ceilingz)) - { - actor->z = thefloor + FixedMul((32<scale); - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector; - - // Move downwards or upwards to go through a passageway. - if (nextsector->ceilingheight < actor->z + actor->height) - actor->momz -= FixedMul(5*FRACUNIT, actor->scale); - else if (nextsector->floorheight > actor->z) - actor->momz += FixedMul(5*FRACUNIT, actor->scale); -} - -// Function: A_MouseThink -// -// Description: Thinker for scurrying mice. -// -// var1 = unused -// var2 = unused -// -void A_MouseThink(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MouseThink", actor)) - return; -#endif - - if (actor->reactiontime) - actor->reactiontime--; - - if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z == actor->floorz) - || (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height == actor->ceilingz)) - && !actor->reactiontime) - { - if (twodlevel || actor->flags2 & MF2_TWOD) - { - if (P_RandomChance(FRACUNIT/2)) - actor->angle += ANGLE_180; - } - else if (P_RandomChance(FRACUNIT/2)) - actor->angle += ANGLE_90; - else - actor->angle -= ANGLE_90; - - P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale)); - actor->reactiontime = TICRATE/5; - } -} - -// Function: A_DetonChase -// -// Description: Chases a Deton after a player. -// -// var1 = unused -// var2 = unused -// -void A_DetonChase(mobj_t *actor) -{ - angle_t exact; - fixed_t xydist, dist; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_DetonChase", actor)) - return; -#endif - - // modify tracer threshold - if (!actor->tracer || actor->tracer->health <= 0) - actor->threshold = 0; - else - actor->threshold = 1; - - if (!actor->tracer || !(actor->tracer->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, true, 0)) - return; // got a new target - - actor->momx = actor->momy = actor->momz = 0; - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - if (multiplayer && !actor->threshold && P_LookForPlayers(actor, true, true, 0)) - return; // got a new target - - // Face movement direction if not doing so - exact = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); - actor->angle = exact; - /*if (exact != actor->angle) - { - if (exact - actor->angle > ANGLE_180) - { - actor->angle -= actor->info->raisestate; - if (exact - actor->angle < ANGLE_180) - actor->angle = exact; - } - else - { - actor->angle += actor->info->raisestate; - if (exact - actor->angle > ANGLE_180) - actor->angle = exact; - } - }*/ - // movedir is up/down angle: how much it has to go up as it goes over to the player - xydist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); - exact = R_PointToAngle2(0, 0, xydist, actor->tracer->z - actor->z); - actor->movedir = exact; - /*if (exact != actor->movedir) - { - if (exact - actor->movedir > ANGLE_180) - { - actor->movedir -= actor->info->raisestate; - if (exact - actor->movedir < ANGLE_180) - actor->movedir = exact; - } - else - { - actor->movedir += actor->info->raisestate; - if (exact - actor->movedir > ANGLE_180) - actor->movedir = exact; - } - }*/ - - // check for melee attack - if (actor->tracer) - { - if (P_AproxDistance(actor->tracer->x-actor->x, actor->tracer->y-actor->y) < actor->radius+actor->tracer->radius) - { - if (!((actor->tracer->z > actor->z + actor->height) || (actor->z > actor->tracer->z + actor->tracer->height))) - { - P_ExplodeMissile(actor); - return; - } - } - } - - // chase towards player - if ((dist = P_AproxDistance(xydist, actor->tracer->z-actor->z)) - > FixedMul((actor->info->painchance << FRACBITS), actor->scale)) - { - P_SetTarget(&actor->tracer, NULL); // Too far away - return; - } - - if (actor->reactiontime == 0) - { - actor->reactiontime = actor->info->reactiontime; - return; - } - - if (actor->reactiontime > 1) - { - actor->reactiontime--; - return; - } - - if (actor->reactiontime > 0) - { - actor->reactiontime = -42; - - if (actor->info->seesound) - S_StartScreamSound(actor, actor->info->seesound); - } - - if (actor->reactiontime == -42) - { - fixed_t xyspeed; - - actor->reactiontime = -42; - - exact = actor->movedir>>ANGLETOFINESHIFT; - xyspeed = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINECOSINE(exact)); - actor->momz = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINESINE(exact)); - - exact = actor->angle>>ANGLETOFINESHIFT; - actor->momx = FixedMul(xyspeed, FINECOSINE(exact)); - actor->momy = FixedMul(xyspeed, FINESINE(exact)); - - // Variable re-use - xyspeed = (P_AproxDistance(actor->tracer->x - actor->x, P_AproxDistance(actor->tracer->y - actor->y, actor->tracer->z - actor->z))>>(FRACBITS+6)); - - if (xyspeed < 1) - xyspeed = 1; - - if (leveltime % xyspeed == 0) - S_StartSound(actor, sfx_deton); - } -} - -// Function: A_CapeChase -// -// Description: Set an object's location to its target or tracer. -// -// var1: -// 0 = Use target -// 1 = Use tracer -// upper 16 bits = Z offset -// var2: -// upper 16 bits = forward/backward offset -// lower 16 bits = sideways offset -// -void A_CapeChase(mobj_t *actor) -{ - mobj_t *chaser; - fixed_t foffsetx, foffsety, boffsetx, boffsety; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - angle_t angle; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CapeChase", actor)) - return; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_CapeChase called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); - - if (locvar1 & 65535) - chaser = actor->tracer; - else - chaser = actor->target; - - if (!chaser || (chaser->health <= 0)) - { - if (chaser) - CONS_Debug(DBG_GAMELOGIC, "Hmm, the guy I'm chasing (object type %d) has no health.. so I'll die too!\n", chaser->type); - - P_RemoveMobj(actor); - return; - } - - angle = (chaser->player ? chaser->player->drawangle : chaser->angle); - - foffsetx = P_ReturnThrustX(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); - foffsety = P_ReturnThrustY(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); - - boffsetx = P_ReturnThrustX(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); - boffsety = P_ReturnThrustY(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); - - P_UnsetThingPosition(actor); - actor->x = chaser->x + foffsetx + boffsetx; - actor->y = chaser->y + foffsety + boffsety; - if (chaser->eflags & MFE_VERTICALFLIP) - { - actor->eflags |= MFE_VERTICALFLIP; - actor->flags2 |= MF2_OBJECTFLIP; - actor->z = chaser->z + chaser->height - actor->height - FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale); - } - else - { - actor->eflags &= ~MFE_VERTICALFLIP; - actor->flags2 &= ~MF2_OBJECTFLIP; - actor->z = chaser->z + FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale); - } - actor->angle = angle; - P_SetThingPosition(actor); -} - -// Function: A_RotateSpikeBall -// -// Description: Rotates a spike ball around its target/tracer. -// -// var1: -// 0 = Use target -// 1 = Use tracer -// var2 = unused -// -void A_RotateSpikeBall(mobj_t *actor) -{ - INT32 locvar1 = var1; - const fixed_t radius = FixedMul(12*actor->info->speed, actor->scale); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RotateSpikeBall", actor)) - return; -#endif - - if (actor->type == MT_SPECIALSPIKEBALL) // don't remove this, these spikeballs share the same states as the rotating spikeballs - return; - - if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen. - { - CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Spikeball has no target\n"); - P_RemoveMobj(actor); - return; - } - - if (!actor->info->speed) - { - CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Object has no speed.\n"); - return; - } - - actor->angle += FixedAngle(actor->info->speed); - P_UnsetThingPosition(actor); - { - const angle_t fa = actor->angle>>ANGLETOFINESHIFT; - if (!locvar1) - { - actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius); - actor->y = actor->target->y + FixedMul(FINESINE(fa),radius); - actor->z = actor->target->z + actor->target->height/2; - } - else - { - actor->x = actor->tracer->x + FixedMul(FINECOSINE(fa),radius); - actor->y = actor->tracer->y + FixedMul(FINESINE(fa),radius); - actor->z = actor->tracer->z + actor->tracer->height/2; - } - P_SetThingPosition(actor); - } -} - -// Function: A_UnidusBall -// -// Description: Rotates a spike ball around its target. -// -// var1: -// 0 = Don't throw -// 1 = Throw -// 2 = Throw when target leaves MF2_SKULLFLY. -// var2 = unused -// -void A_UnidusBall(mobj_t *actor) -{ - INT32 locvar1 = var1; - boolean canthrow = false; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_UnidusBall", actor)) - return; -#endif - - actor->angle += ANGLE_11hh; - - if (actor->movecount) - { - if (P_AproxDistance(actor->momx, actor->momy) < FixedMul(actor->info->damage/2, actor->scale)) - P_ExplodeMissile(actor); - return; - } - - if (!actor->target || !actor->target->health) - { - CONS_Debug(DBG_GAMELOGIC, "A_UnidusBall: Removing unthrown spikeball from nonexistant Unidus\n"); - P_RemoveMobj(actor); - return; - } - - P_UnsetThingPosition(actor); - { - const angle_t angle = actor->movedir + FixedAngle(actor->info->speed*(leveltime%360)); - const UINT16 fa = angle>>ANGLETOFINESHIFT; - - actor->x = actor->target->x + FixedMul(FINECOSINE(fa),actor->threshold); - actor->y = actor->target->y + FixedMul( FINESINE(fa),actor->threshold); - actor->z = actor->target->z + actor->target->height/2 - actor->height/2; - - if (locvar1 == 1 && actor->target->target) - { - const angle_t tang = R_PointToAngle2(actor->target->x, actor->target->y, actor->target->target->x, actor->target->target->y); - const angle_t mina = tang-ANGLE_11hh; - canthrow = (angle-mina < FixedAngle(actor->info->speed*3)); - } - } - P_SetThingPosition(actor); - - if (locvar1 == 1 && canthrow) - { - if (P_AproxDistance(actor->target->target->x - actor->target->x, actor->target->target->y - actor->target->y) > FixedMul(MISSILERANGE>>1, actor->scale) - || !P_CheckSight(actor, actor->target->target)) - return; - - actor->movecount = actor->info->damage>>FRACBITS; - actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING); - P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->target->target->x, actor->target->target->y), FixedMul(actor->info->damage, actor->scale)); - } - else if (locvar1 == 2) - { - boolean skull = (actor->target->flags2 & MF2_SKULLFLY) == MF2_SKULLFLY; - if (actor->target->state == &states[actor->target->info->painstate]) - { - P_KillMobj(actor, NULL, NULL, 0); - return; - } - switch(actor->extravalue2) - { - case 0: // at least one frame where not dashing - if (!skull) ++actor->extravalue2; - else break; - /* FALLTHRU */ - case 1: // at least one frame where ARE dashing - if (skull) ++actor->extravalue2; - else break; - /* FALLTHRU */ - case 2: // not dashing again? - if (skull) break; - // launch. - { - mobj_t *target = actor->target; - if (actor->target->target) - target = actor->target->target; - actor->movecount = actor->info->damage>>FRACBITS; - actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING); - P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, target->x, target->y), FixedMul(actor->info->damage, actor->scale)); - } - default: // from our compiler appeasement program (CAP). - break; - } - } -} - -// Function: A_RockSpawn -// -// Spawns rocks at a specified interval -// -// var1 = unused -// var2 = unused -void A_RockSpawn(mobj_t *actor) -{ - mobj_t *mo; - mobjtype_t type; - INT32 i = P_FindSpecialLineFromTag(12, (INT16)actor->threshold, -1); - line_t *line; - fixed_t dist; - fixed_t randomoomph; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RockSpawn", actor)) - return; -#endif - - if (i == -1) - { - CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: Unable to find parameter line 12 (tag %d)!\n", actor->threshold); - return; - } - - line = &lines[i]; - - if (!(sides[line->sidenum[0]].textureoffset >> FRACBITS)) - { - CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: No X-offset detected! (tag %d)!\n", actor->threshold); - return; - } - - dist = P_AproxDistance(line->dx, line->dy)/16; - - if (dist < 1) - dist = 1; - - type = MT_ROCKCRUMBLE1 + (sides[line->sidenum[0]].rowoffset >> FRACBITS); - - if (line->flags & ML_NOCLIMB) - randomoomph = P_RandomByte() * (FRACUNIT/32); - else - randomoomph = 0; - - mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK); - P_SetMobjState(mo, mobjinfo[type].spawnstate); - mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); - - P_InstaThrust(mo, mo->angle, dist + randomoomph); - mo->momz = dist + randomoomph; - - var1 = sides[line->sidenum[0]].textureoffset >> FRACBITS; - A_SetTics(actor); -} - -// -// Function: A_SlingAppear -// -// Appears a sling. -// -// var1 = unused -// var2 = unused -// -void A_SlingAppear(mobj_t *actor) -{ - boolean firsttime = true; - UINT8 mlength = 4; - mobj_t *spawnee; - mobj_t *hprev = actor; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SlingAppear", actor)) - return; -#endif - - P_UnsetThingPosition(actor); - actor->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetThingPosition(actor); - actor->lastlook = 128; - actor->movecount = actor->lastlook; - actor->threshold = 0; - actor->movefactor = actor->threshold; - actor->friction = 128; - - while (mlength > 0) - { - spawnee = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLMACECHAIN); - - P_SetTarget(&spawnee->tracer, actor); - P_SetTarget(&spawnee->hprev, hprev); - P_SetTarget(&hprev->hnext, spawnee); - hprev = spawnee; - - spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; - spawnee->movecount = mlength; - - if (firsttime) - { - // This is the outermost link in the chain - spawnee->flags2 |= MF2_AMBUSH; - firsttime = false; - } - - mlength--; - } -} - -// Function: A_SetFuse -// -// Description: Sets the actor's fuse timer if not set already. May also change state when fuse reaches the last tic, otherwise by default the actor will die or disappear. (Replaces A_SnowBall) -// -// var1 = fuse timer duration (in tics). -// var2: -// lower 16 bits = if > 0, state to change to when fuse = 1 -// upper 16 bits: 0 = (default) don't set fuse unless 0, 1 = force change, 2 = force no change -// -void A_SetFuse(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetFuse", actor)) - return; -#endif - - if ((!actor->fuse || (locvar2 >> 16)) && (locvar2 >> 16) != 2) // set the actor's fuse value - actor->fuse = locvar1; - - if (actor->fuse == 1 && (locvar2 & 65535)) // change state on the very last tic (fuse is handled before actions in P_MobjThinker) - { - actor->fuse = 0; // don't die/disappear the next tic! - P_SetMobjState(actor, locvar2 & 65535); - } -} - -// Function: A_CrawlaCommanderThink -// -// Description: Thinker for Crawla Commander. -// -// var1 = shoot bullets? -// var2 = "pogo mode" speed -// -void A_CrawlaCommanderThink(mobj_t *actor) -{ - fixed_t dist; - sector_t *nextsector; - fixed_t thefloor; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - boolean hovermode = (actor->health > 1 || actor->fuse); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CrawlaCommanderThink", actor)) - return; -#endif - - if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz - && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) - thefloor = actor->watertop; - else - thefloor = actor->floorz; - - if (!actor->fuse && actor->flags2 & MF2_FRET) - { - if (actor->info->painsound) - S_StartSound(actor, actor->info->painsound); - - actor->fuse = TICRATE/2; - actor->momz = 0; - - P_InstaThrust(actor, actor->angle-ANGLE_180, FixedMul(5*FRACUNIT, actor->scale)); - } - - if (actor->reactiontime > 0) - actor->reactiontime--; - - if (actor->fuse < 2) - { - actor->fuse = 0; - actor->flags2 &= ~MF2_FRET; - } - - // Hover mode - if (hovermode) - { - if (actor->z < thefloor + FixedMul(16*FRACUNIT, actor->scale)) - actor->momz += FixedMul(FRACUNIT, actor->scale); - else if (actor->z < thefloor + FixedMul(32*FRACUNIT, actor->scale)) - actor->momz += FixedMul(FRACUNIT/2, actor->scale); - else - actor->momz += FixedMul(16, actor->scale); - } - - if (!actor->target) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - if (actor->state != &states[actor->info->spawnstate]) - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y); - - if (actor->target->player && (!hovermode || actor->reactiontime <= 2*TICRATE)) - { - if (dist < FixedMul(64<<(FRACBITS+(hovermode ? 1 : 0)), actor->scale) - && ((actor->target->player->pflags & PF_JUMPED) || (actor->target->player->pflags & PF_SPINNING))) - { - // Auugh! She's trying to kill you! Strafe! STRAAAAFFEEE!! - P_InstaThrust(actor, actor->angle - ANGLE_180, FixedMul(20*FRACUNIT, actor->scale)); - return; - } - } - - if (locvar1) - { - if (actor->health < 2 && P_RandomChance(FRACUNIT/128)) - P_SpawnMissile(actor, actor->target, locvar1); - } - - // Face the player - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - - if (actor->threshold && dist > FixedMul(256*FRACUNIT, actor->scale)) - actor->momx = actor->momy = 0; - - if (actor->reactiontime && actor->reactiontime <= 2*TICRATE && dist > actor->target->radius - FixedMul(FRACUNIT, actor->scale)) - { - actor->threshold = 0; - - // Roam around, somewhat in the player's direction. - actor->angle += (P_RandomByte()<<10); - actor->angle -= (P_RandomByte()<<10); - - if (hovermode) - { - fixed_t mom; - P_Thrust(actor, actor->angle, 2*actor->scale); - mom = P_AproxDistance(actor->momx, actor->momy); - if (mom > 20*actor->scale) - { - mom += 20*actor->scale; - mom >>= 1; - P_InstaThrust(actor, R_PointToAngle2(0, 0, actor->momx, actor->momy), mom); - } - } - } - else if (!actor->reactiontime) - { - if (hovermode && !(actor->flags2 & MF2_FRET)) // Hover Mode - { - if (dist < FixedMul(512*FRACUNIT, actor->scale)) - { - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_InstaThrust(actor, actor->angle, FixedMul(40*FRACUNIT, actor->scale)); - actor->threshold = 1; - if (actor->info->attacksound) - S_StartSound(actor, actor->info->attacksound); - } - } - actor->reactiontime = 3*TICRATE + (P_RandomByte()>>2); - } - - if (actor->health == 1) - P_Thrust(actor, actor->angle, 1); - - // Pogo Mode - if (!hovermode && actor->z <= actor->floorz) - { - if (actor->info->activesound) - S_StartSound(actor, actor->info->activesound); - - if (dist < FixedMul(256*FRACUNIT, actor->scale)) - { - actor->momz = FixedMul(locvar2, actor->scale); - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_InstaThrust(actor, actor->angle, FixedMul(locvar2/8, actor->scale)); - // pogo on player - } - else - { - UINT8 prandom = P_RandomByte(); - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); - P_InstaThrust(actor, actor->angle, FixedDiv(FixedMul(locvar2, actor->scale), 3*FRACUNIT/2)); - actor->momz = FixedMul(locvar2, actor->scale); // Bounce up in air - } - } - - nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector; - - // Move downwards or upwards to go through a passageway. - if (nextsector->floorheight > actor->z && nextsector->floorheight - actor->z < FixedMul(128*FRACUNIT, actor->scale)) - actor->momz += (nextsector->floorheight - actor->z) / 4; -} - -// Function: A_RingExplode -// -// Description: An explosion ring exploding -// -// var1 = unused -// var2 = unused -// -void A_RingExplode(mobj_t *actor) -{ - mobj_t *mo2; - thinker_t *th; - angle_t d; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RingExplode", actor)) - return; -#endif - - for (d = 0; d < 16; d++) - P_SpawnParaloop(actor->x, actor->y, actor->z + actor->height, FixedMul(actor->info->painchance, actor->scale), 16, MT_NIGHTSPARKLE, S_NULL, d*(ANGLE_22h), true); - - S_StartSound(actor, sfx_prloop); - - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2 == actor) // Don't explode yourself! Endless loop! - continue; - - if (P_AproxDistance(P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y), mo2->z - actor->z) > FixedMul(actor->info->painchance, actor->scale)) - continue; - - if (mo2->flags & MF_SHOOTABLE) - { - actor->flags2 |= MF2_DEBRIS; - P_DamageMobj(mo2, actor, actor->target, 1, 0); - continue; - } - } - return; -} - -// Function: A_OldRingExplode -// -// Description: An explosion ring exploding, 1.09.4 style -// -// var1 = object # to explode as debris -// var2 = unused -// -void A_OldRingExplode(mobj_t *actor) { - UINT8 i; - mobj_t *mo; - const fixed_t ns = FixedMul(20 * FRACUNIT, actor->scale); - INT32 locvar1 = var1; - //INT32 locvar2 = var2; - boolean changecolor = (actor->target && actor->target->player); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_OldRingExplode", actor)) - return; -#endif - - for (i = 0; i < 32; i++) - { - const angle_t fa = (i*FINEANGLES/16) & FINEMASK; - - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); - P_SetTarget(&mo->target, actor->target); // Transfer target so player gets the points - - mo->momx = FixedMul(FINECOSINE(fa),ns); - mo->momy = FixedMul(FINESINE(fa),ns); - - if (i > 15) - { - if (i & 1) - mo->momz = ns; - else - mo->momz = -ns; - } - - mo->flags2 |= MF2_DEBRIS; - mo->fuse = TICRATE/5; - - if (changecolor) - { - if (gametype != GT_CTF) - mo->color = actor->target->color; //copy color - else if (actor->target->player->ctfteam == 2) - mo->color = skincolor_bluering; - } - } - - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); - - P_SetTarget(&mo->target, actor->target); - mo->momz = ns; - mo->flags2 |= MF2_DEBRIS; - mo->fuse = TICRATE/5; - - if (changecolor) - { - if (gametype != GT_CTF) - mo->color = actor->target->color; //copy color - else if (actor->target->player->ctfteam == 2) - mo->color = skincolor_bluering; - } - - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); - - P_SetTarget(&mo->target, actor->target); - mo->momz = -ns; - mo->flags2 |= MF2_DEBRIS; - mo->fuse = TICRATE/5; - - if (changecolor) - { - if (gametype != GT_CTF) - mo->color = actor->target->color; //copy color - else if (actor->target->player->ctfteam == 2) - mo->color = skincolor_bluering; - } -} - -// Function: A_MixUp -// -// Description: Mix up all of the player positions. -// -// var1 = unused -// var2 = unused -// -void A_MixUp(mobj_t *actor) -{ - boolean teleported[MAXPLAYERS]; - INT32 i, numplayers = 0, prandom = 0; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MixUp", actor)) - return; -#else - (void)actor; -#endif - - if (!multiplayer) - return; - - // No mix-up monitors in hide and seek or time only race. - // The random factor is okay for other game modes, but in these, it is cripplingly unfair. - if (gametype == GT_HIDEANDSEEK || gametype == GT_RACE) - { - S_StartSound(actor, sfx_lose); - return; - } - - numplayers = 0; - memset(teleported, 0, sizeof (teleported)); - - // Count the number of players in the game - // and grab their xyz coords - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE - && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) - { - if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators - continue; - - numplayers++; - } - - if (numplayers <= 1) // Not enough players to mix up. - { - S_StartSound(actor, sfx_lose); - return; - } - else if (numplayers == 2) // Special case -- simple swap - { - fixed_t x, y, z; - angle_t angle; - INT32 one = -1, two = 0; // default value 0 to make the compiler shut up - - // Zoom tube stuff - mobj_t *tempthing = NULL; //tracer - UINT16 carry1,carry2; //carry - INT32 transspeed; //player speed - - // Starpost stuff - INT16 starpostx, starposty, starpostz; - INT32 starpostnum; - tic_t starposttime; - angle_t starpostangle; - - INT32 mflags2; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE - && !players[i].exiting && !players[i].powers[pw_super]) - { - if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators - continue; - - if (one == -1) - one = i; - else - { - two = i; - break; - } - } - - //get this done first! - tempthing = players[one].mo->tracer; - P_SetTarget(&players[one].mo->tracer, players[two].mo->tracer); - P_SetTarget(&players[two].mo->tracer, tempthing); - - //zoom tubes use player->speed to determine direction and speed - transspeed = players[one].speed; - players[one].speed = players[two].speed; - players[two].speed = transspeed; - - //set flags variables now but DON'T set them. - carry1 = (players[one].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[one].powers[pw_carry]); - carry2 = (players[two].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[two].powers[pw_carry]); - - x = players[one].mo->x; - y = players[one].mo->y; - z = players[one].mo->z; - angle = players[one].mo->angle; - - starpostx = players[one].starpostx; - starposty = players[one].starposty; - starpostz = players[one].starpostz; - starpostangle = players[one].starpostangle; - starpostnum = players[one].starpostnum; - starposttime = players[one].starposttime; - - mflags2 = players[one].mo->flags2; - - P_MixUp(players[one].mo, players[two].mo->x, players[two].mo->y, players[two].mo->z, players[two].mo->angle, - players[two].starpostx, players[two].starposty, players[two].starpostz, - players[two].starpostnum, players[two].starposttime, players[two].starpostangle, - players[two].mo->flags2); - - P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz, - starpostnum, starposttime, starpostangle, - mflags2); - - //carry set after mixup. Stupid P_ResetPlayer() takes away some of the stuff we look for... - //but not all of it! So we need to make sure they aren't set wrong or anything. - players[one].powers[pw_carry] = carry2; - players[two].powers[pw_carry] = carry1; - - teleported[one] = true; - teleported[two] = true; - } - else - { - fixed_t position[MAXPLAYERS][3]; - angle_t anglepos[MAXPLAYERS]; - INT32 pindex[MAXPLAYERS], counter = 0, teleportfrom = 0; - - // Zoom tube stuff - mobj_t *transtracer[MAXPLAYERS]; //tracer - //pflags_t transflag[MAXPLAYERS]; //cyan pink white pink cyan - UINT16 transcarry[MAXPLAYERS]; //player carry - INT32 transspeed[MAXPLAYERS]; //player speed - - // Star post stuff - INT16 spposition[MAXPLAYERS][3]; - INT32 starpostnum[MAXPLAYERS]; - tic_t starposttime[MAXPLAYERS]; - angle_t starpostangle[MAXPLAYERS]; - - INT32 flags2[MAXPLAYERS]; - - for (i = 0; i < MAXPLAYERS; i++) - { - position[i][0] = position[i][1] = position[i][2] = anglepos[i] = pindex[i] = -1; - teleported[i] = false; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && players[i].playerstate == PST_LIVE - && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) - { - if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators - continue; - - position[counter][0] = players[i].mo->x; - position[counter][1] = players[i].mo->y; - position[counter][2] = players[i].mo->z; - pindex[counter] = i; - anglepos[counter] = players[i].mo->angle; - players[i].mo->momx = players[i].mo->momy = players[i].mo->momz = - players[i].rmomx = players[i].rmomy = 1; - players[i].cmomx = players[i].cmomy = 0; - - transcarry[counter] = (players[i].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[i].powers[pw_carry]); - transspeed[counter] = players[i].speed; - transtracer[counter] = players[i].mo->tracer; - - spposition[counter][0] = players[i].starpostx; - spposition[counter][1] = players[i].starposty; - spposition[counter][2] = players[i].starpostz; - starpostnum[counter] = players[i].starpostnum; - starposttime[counter] = players[i].starposttime; - starpostangle[counter] = players[i].starpostangle; - - flags2[counter] = players[i].mo->flags2; - - counter++; - } - } - - counter = 0; - - // Mix them up! - for (;;) - { - if (counter > 255) // fail-safe to avoid endless loop - break; - prandom = P_RandomByte(); - prandom %= numplayers; // I love modular arithmetic, don't you? - if (prandom) // Make sure it's not a useless mix - break; - counter++; - } - - counter = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && players[i].playerstate == PST_LIVE - && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) - { - if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators - continue; - - teleportfrom = (counter + prandom) % numplayers; - - //speed and tracer come before... - players[i].speed = transspeed[teleportfrom]; - P_SetTarget(&players[i].mo->tracer, transtracer[teleportfrom]); - - P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom], - spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2], - starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom], - flags2[teleportfrom]); - - //...carry after. same reasoning. - players[i].powers[pw_carry] = transcarry[teleportfrom]; - - teleported[i] = true; - counter++; - } - } - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (teleported[i]) - { - if (playeringame[i] && players[i].playerstate == PST_LIVE - && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) - { - if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators - continue; - - P_SetThingPosition(players[i].mo); - -#ifdef ESLOPE - players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); - players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); -#else - players[i].mo->floorz = players[i].mo->subsector->sector->floorheight; - players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight; -#endif - - P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y); - } - } - } - - // Play the 'bowrwoosh!' sound - S_StartSound(NULL, sfx_mixup); -} - -// Function: A_RecyclePowers -// -// Description: Take all player's powers, and swap 'em. -// -// var1 = unused -// var2 = unused -// -void A_RecyclePowers(mobj_t *actor) -{ - INT32 i, j, k, numplayers = 0; - -#ifdef WEIGHTEDRECYCLER - UINT8 beneficiary = 255; -#endif - UINT8 playerslist[MAXPLAYERS]; - UINT8 postscramble[MAXPLAYERS]; - - UINT16 powers[MAXPLAYERS][NUMPOWERS]; - INT32 weapons[MAXPLAYERS]; - INT32 weaponheld[MAXPLAYERS]; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RecyclePowers", actor)) - return; -#endif - -#if !defined(WEIGHTEDRECYCLER) && !defined(HAVE_BLUA) - // actor is used in all scenarios but this one, funny enough - (void)actor; -#endif - - if (!multiplayer) - { - S_StartSound(actor, sfx_lose); - return; - } - - numplayers = 0; - - // Count the number of players in the game - for (i = 0, j = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE - && !players[i].exiting && !((netgame || multiplayer) && players[i].spectator)) - { -#ifndef WEIGHTEDRECYCLER - if (players[i].powers[pw_super]) - continue; // Ignore super players -#endif - - numplayers++; - postscramble[j] = playerslist[j] = (UINT8)i; - -#ifdef WEIGHTEDRECYCLER - // The guy who started the recycle gets the best result - if (actor && actor->target && actor->target->player && &players[i] == actor->target->player) - beneficiary = (UINT8)i; -#endif - - // Save powers - for (k = 0; k < NUMPOWERS; k++) - powers[i][k] = players[i].powers[k]; - //1.1: ring weapons too - weapons[i] = players[i].ringweapons; - weaponheld[i] = players[i].currentweapon; - - j++; - } - } - - if (numplayers <= 1) - { - S_StartSound(actor, sfx_lose); - return; //nobody to touch! - } - - //shuffle the post scramble list, whee! - // hardcoded 0-1 to 1-0 for two players - if (numplayers == 2) - { - postscramble[0] = playerslist[1]; - postscramble[1] = playerslist[0]; - } - else - for (j = 0; j < numplayers; j++) - { - UINT8 tempint; - - i = j + ((P_RandomByte() + leveltime) % (numplayers - j)); - tempint = postscramble[j]; - postscramble[j] = postscramble[i]; - postscramble[i] = tempint; - } - -#ifdef WEIGHTEDRECYCLER - //the joys of qsort... - if (beneficiary != 255) { - qsort(playerslist, numplayers, sizeof(UINT8), P_RecycleCompare); - - // now, make sure the benificiary is in the best slot - // swap out whatever poor sap was going to get the best items - for (i = 0; i < numplayers; i++) - { - if (postscramble[i] == beneficiary) - { - postscramble[i] = postscramble[0]; - postscramble[0] = beneficiary; - break; - } - } - } -#endif - - // now assign! - for (i = 0; i < numplayers; i++) - { - UINT8 send_pl = playerslist[i]; - UINT8 recv_pl = postscramble[i]; - - // debugF - CONS_Debug(DBG_GAMELOGIC, "sending player %hu's items to %hu\n", (UINT16)send_pl, (UINT16)recv_pl); - - for (j = 0; j < NUMPOWERS; j++) - { - if (j == pw_flashing || j == pw_underwater || j == pw_spacetime || j == pw_carry - || j == pw_tailsfly || j == pw_extralife || j == pw_nocontrol || j == pw_super) - continue; - players[recv_pl].powers[j] = powers[send_pl][j]; - } - - //1.1: weapon rings too - players[recv_pl].ringweapons = weapons[send_pl]; - players[recv_pl].currentweapon = weaponheld[send_pl]; - - P_SpawnShieldOrb(&players[recv_pl]); - if (P_IsLocalPlayer(&players[recv_pl])) - P_RestoreMusic(&players[recv_pl]); - P_FlashPal(&players[recv_pl], PAL_RECYCLE, 10); - } - - S_StartSound(NULL, sfx_gravch); //heh, the sound effect I used is already in -} - -// Function: A_Boss1Chase -// -// Description: Like A_Chase, but for Boss 1. -// -// var1 = unused -// var2 = unused -// -void A_Boss1Chase(mobj_t *actor) -{ - INT32 delta; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss1Chase", actor)) - return; -#endif - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjStateNF(actor, actor->info->spawnstate); - return; - } - - if (actor->reactiontime) - actor->reactiontime--; - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - // do not attack twice in a row - if (actor->flags2 & MF2_JUSTATTACKED) - { - actor->flags2 &= ~MF2_JUSTATTACKED; - P_NewChaseDir(actor); - return; - } - - if (actor->movecount) - goto nomissile; - - if (!P_CheckMissileRange(actor)) - goto nomissile; - - if (actor->reactiontime <= 0) - { - if (actor->health > actor->info->damage) - { - if (P_RandomChance(FRACUNIT/2)) - P_SetMobjState(actor, actor->info->missilestate); - else - P_SetMobjState(actor, actor->info->meleestate); - } - else - { - P_LinedefExecute(LE_PINCHPHASE, actor, NULL); - P_SetMobjState(actor, actor->info->raisestate); - } - - actor->flags2 |= MF2_JUSTATTACKED; - actor->reactiontime = actor->info->reactiontime; - return; - } - - // ? -nomissile: - // possibly choose another target - if (multiplayer && P_RandomChance(FRACUNIT/128)) - { - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - } - - if (actor->flags & MF_FLOAT && !(actor->flags2 & MF2_SKULLFLY)) - { // Float up/down to your target's position. Stay above them, but not out of jump range. - fixed_t target_min = actor->target->floorz+FixedMul(64*FRACUNIT, actor->scale); - if (target_min < actor->target->z - actor->height) - target_min = actor->target->z - actor->height; - if (target_min < actor->floorz+FixedMul(33*FRACUNIT, actor->scale)) - target_min = actor->floorz+FixedMul(33*FRACUNIT, actor->scale); - if (actor->z > target_min+FixedMul(16*FRACUNIT, actor->scale)) - actor->momz = FixedMul((-actor->info->speed<<(FRACBITS-1)), actor->scale); - else if (actor->z < target_min) - actor->momz = FixedMul(actor->info->speed<<(FRACBITS-1), actor->scale); - else - actor->momz = FixedMul(actor->momz,7*FRACUNIT/8); - } - - // chase towards player - if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) > actor->radius+actor->target->radius) - { - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); - } - // too close, don't want to chase. - else if (--actor->movecount < 0) - { - // A mini-A_FaceTarget based on P_NewChaseDir. - // Yes, it really is this simple when you get down to it. - fixed_t deltax, deltay; - - deltax = actor->target->x - actor->x; - deltay = actor->target->y - actor->y; - - actor->movedir = diags[((deltay < 0)<<1) + (deltax > 0)]; - actor->movecount = P_RandomByte() & 15; - } -} - -// Function: A_Boss2Chase -// -// Description: Really doesn't 'chase', but rather goes in a circle. -// -// var1 = unused -// var2 = unused -// -void A_Boss2Chase(mobj_t *actor) -{ - fixed_t radius; - boolean reverse = false; - INT32 speedvar; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss2Chase", actor)) - return; -#endif - - if (actor->health <= 0) - return; - - // Startup randomness - if (actor->reactiontime <= -666) - actor->reactiontime = 2*TICRATE + P_RandomByte(); - - // When reactiontime hits zero, he will go the other way - if (--actor->reactiontime <= 0) - { - reverse = true; - actor->reactiontime = 2*TICRATE + P_RandomByte(); - } - - P_SetTarget(&actor->target, P_GetClosestAxis(actor)); - - if (!actor->target) // This should NEVER happen. - { - CONS_Debug(DBG_GAMELOGIC, "Boss2 has no target!\n"); - A_BossDeath(actor); - return; - } - - radius = actor->target->radius; - - if (reverse) - { - actor->watertop = -actor->watertop; - actor->extravalue1 = 18; - if (actor->flags2 & MF2_AMBUSH) - actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2; - actor->extravalue2 = actor->extravalue1; - } - - // Turnaround - if (actor->extravalue1 > 0) - { - --actor->extravalue1; - - // Set base angle - { - const angle_t fa = (actor->target->angle + FixedAngle(actor->watertop))>>ANGLETOFINESHIFT; - const fixed_t fc = FixedMul(FINECOSINE(fa),radius); - const fixed_t fs = FixedMul(FINESINE(fa),radius); - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs); - } - - // Now turn you around! - // Note that the start position is the final position, we move it back around - // to intermediary positions... - actor->angle -= FixedAngle(FixedMul(FixedDiv(180<extravalue2<extravalue1<flags2 & MF2_AMBUSH) - speedvar = actor->health; - else - speedvar = actor->info->spawnhealth; - - actor->target->angle += // Don't use FixedAngleC! - FixedAngle(FixedDiv(FixedMul(actor->watertop, (actor->info->spawnhealth*(FRACUNIT/4)*3)), speedvar*FRACUNIT)); - - P_UnsetThingPosition(actor); - { - const angle_t fa = actor->target->angle>>ANGLETOFINESHIFT; - const fixed_t fc = FixedMul(FINECOSINE(fa),radius); - const fixed_t fs = FixedMul(FINESINE(fa),radius); - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs); - actor->x = actor->target->x + fc; - actor->y = actor->target->y + fs; - } - P_SetThingPosition(actor); - - // Spray goo once every second - if (leveltime % (speedvar*15/10)-1 == 0) - { - const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale); - mobj_t *goop; - fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale); - angle_t fa; - // actor->movedir is used to determine the last - // direction goo was sprayed in. There are 8 possible - // directions to spray. (45-degree increments) - - actor->movedir++; - actor->movedir %= NUMDIRS; - fa = (actor->movedir*FINEANGLES/8) & FINEMASK; - - goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance); - goop->momx = FixedMul(FINECOSINE(fa),ns); - goop->momy = FixedMul(FINESINE(fa),ns); - goop->momz = FixedMul(4*FRACUNIT, actor->scale); - goop->fuse = 10*TICRATE; - - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - - if (P_RandomChance(FRACUNIT/2)) - { - goop->momx *= 2; - goop->momy *= 2; - } - else if (P_RandomChance(129*FRACUNIT/256)) - { - goop->momx *= 3; - goop->momy *= 3; - } - - actor->flags2 |= MF2_JUSTATTACKED; - } - } -} - -// Function: A_Boss2Pogo -// -// Description: Pogo part of Boss 2 AI. -// -// var1 = unused -// var2 = unused -// -void A_Boss2Pogo(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss2Pogo", actor)) - return; -#endif - if (actor->z <= actor->floorz + FixedMul(8*FRACUNIT, actor->scale) && actor->momz <= 0) - { - if (actor->state != &states[actor->info->raisestate]) - P_SetMobjState(actor, actor->info->raisestate); - // Pogo Mode - } - else if (actor->momz < 0 && actor->reactiontime) - { - const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale); - mobj_t *goop; - fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale); - angle_t fa; - INT32 i; - // spray in all 8 directions! - for (i = 0; i < 8; i++) - { - actor->movedir++; - actor->movedir %= NUMDIRS; - fa = (actor->movedir*FINEANGLES/8) & FINEMASK; - - goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance); - goop->momx = FixedMul(FINECOSINE(fa),ns); - goop->momy = FixedMul(FINESINE(fa),ns); - goop->momz = FixedMul(4*FRACUNIT, actor->scale); - - goop->fuse = 10*TICRATE; - } - actor->reactiontime = 0; // we already shot goop, so don't do it again! - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - actor->flags2 |= MF2_JUSTATTACKED; - } -} - -// Function: A_Boss2TakeDamage -// -// Description: Special function for Boss 2 so you can't just sit and destroy him. -// -// var1 = Invincibility duration -// var2 = unused -// -void A_Boss2TakeDamage(mobj_t *actor) -{ - INT32 locvar1 = var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss2TakeDamage", actor)) - return; -#endif - A_Pain(actor); - actor->reactiontime = 1; // turn around - if (locvar1 == 0) // old A_Invincibilerize behavior - actor->movecount = TICRATE; - else - actor->movecount = locvar1; // become flashing invulnerable for this long. -} - -// Function: A_Boss7Chase -// -// Description: Like A_Chase, but for Black Eggman -// -// var1 = unused -// var2 = unused -// -void A_Boss7Chase(mobj_t *actor) -{ - INT32 delta; - INT32 i; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss7Chase", actor)) - return; -#endif - - if (actor->z != actor->floorz) - return; - - // Self-adjust if stuck on the edge - if (actor->tracer) - { - if (P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y) > 128*FRACUNIT - actor->radius) - P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y), FRACUNIT); - } - - if (actor->flags2 & MF2_FRET) - { - P_SetMobjState(actor, S_BLACKEGG_DESTROYPLAT1); - S_StartSound(0, sfx_s3k53); - actor->flags2 &= ~MF2_FRET; - return; - } - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - // Is a player on top of us? - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - if (players[i].mo->health <= 0) - continue; - - if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) > actor->radius) - continue; - - if (players[i].mo->z > actor->z + actor->height - 2*FRACUNIT - && players[i].mo->z < actor->z + actor->height + 32*FRACUNIT) - { - // Punch him! - P_SetMobjState(actor, actor->info->meleestate); - S_StartSound(0, sfx_begrnd); // warning sound - return; - } - } - - if (actor->health <= actor->info->damage - && actor->target - && actor->target->player - && (actor->target->player->powers[pw_carry] == CR_GENERIC)) - { - A_FaceTarget(actor); - P_SetMobjState(actor, S_BLACKEGG_SHOOT1); - actor->movecount = TICRATE + P_RandomByte()/2; - return; - } - - if (actor->reactiontime) - actor->reactiontime--; - - if (actor->reactiontime <= 0 && actor->z == actor->floorz) - { - // Here, we'll call P_RandomByte() and decide what kind of attack to do - switch(actor->threshold) - { - case 0: // Lob cannon balls - if (actor->z < 1056*FRACUNIT) - { - A_FaceTarget(actor); - P_SetMobjState(actor, actor->info->xdeathstate); - actor->movecount = 7*TICRATE + P_RandomByte(); - break; - } - actor->threshold++; - /* FALLTHRU */ - case 1: // Chaingun Goop - A_FaceTarget(actor); - P_SetMobjState(actor, S_BLACKEGG_SHOOT1); - - if (actor->health > actor->info->damage) - actor->movecount = TICRATE + P_RandomByte()/3; - else - actor->movecount = TICRATE + P_RandomByte()/2; - break; - case 2: // Homing Missile - A_FaceTarget(actor); - P_SetMobjState(actor, actor->info->missilestate); - S_StartSound(0, sfx_beflap); - break; - } - - actor->threshold++; - actor->threshold %= 3; - return; - } - - // possibly choose another target - if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - && P_BossTargetPlayer(actor, false)) - return; // got a new target - - if (leveltime & 1) - { - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); - } -} - -// Function: A_GoopSplat -// -// Description: Black Eggman goop hits a target and sticks around for awhile. -// -// var1 = unused -// var2 = unused -// -void A_GoopSplat(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GoopSplat", actor)) - return; -#endif - P_UnsetThingPosition(actor); - if (sector_list) - { - P_DelSeclist(sector_list); - sector_list = NULL; - } - actor->flags = MF_SPECIAL; // Not a typo - P_SetThingPosition(actor); -} - -// Function: A_Boss2PogoSFX -// -// Description: Pogoing for Boss 2 -// -// var1 = pogo jump strength -// var2 = idle pogo speed -// -void A_Boss2PogoSFX(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss2PogoSFX", actor)) - return; -#endif - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - return; - } - - // Boing! - if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(256*FRACUNIT, actor->scale)) - { - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale)); - // pogo on player - } - else - { - UINT8 prandom = P_RandomByte(); - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); - P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); - } - if (actor->info->activesound) S_StartSound(actor, actor->info->activesound); - actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air - actor->reactiontime = 1; -} - -// Function: A_Boss2PogoTarget -// -// Description: Pogoing for Boss 2, tries to actually land on the player directly. -// -// var1 = pogo jump strength -// var2 = idle pogo speed -// -void A_Boss2PogoTarget(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss2PogoTarget", actor)) - return; -#endif - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) || (actor->target->player && actor->target->player->powers[pw_flashing]) - || P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) >= FixedMul(512*FRACUNIT, actor->scale)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 512*FRACUNIT)) - ; // got a new target - else if (P_LookForPlayers(actor, true, false, 0)) - ; // got a new target - else - return; - } - - // Target hit, retreat! - if (actor->target->player->powers[pw_flashing] > TICRATE || actor->flags2 & MF2_FRET) - { - UINT8 prandom = P_RandomByte(); - actor->z++; // unstick from the floor - actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it. - P_InstaThrust(actor, actor->angle+ANGLE_180, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed - } - // Try to land on top of the player. - else if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(512*FRACUNIT, actor->scale)) - { - fixed_t airtime, gravityadd, zoffs; - - // check gravity in the sector (for later math) - P_CheckGravity(actor, true); - gravityadd = actor->momz; - - actor->z++; // unstick from the floor - actor->momz = FixedMul(locvar1 + (locvar1>>2), actor->scale); // Bounce up in air - - /*badmath = 0; - airtime = 0; - do { - badmath += momz; - momz += gravityadd; - airtime++; - } while(badmath > 0); - airtime = 2*airtime<momz<<1, gravityadd)<<1; // going from 0 to 0 is much simpler - zoffs = (P_GetPlayerHeight(actor->target->player)>>1) + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height, - airtime = FixedDiv((-actor->momz - FixedSqrt(FixedMul(actor->momz,actor->momz)+zoffs)), gravityadd)<<1; // to try and land on their head rather than on their feet - - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - P_InstaThrust(actor, actor->angle, FixedDiv(P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y), airtime)); - } - // Wander semi-randomly towards the player to get closer. - else - { - UINT8 prandom = P_RandomByte(); - actor->z++; // unstick from the floor - actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it. - P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed - } - // Boing! - if (actor->info->activesound) S_StartSound(actor, actor->info->activesound); - - if (actor->info->missilestate) // spawn the pogo stick collision box - { - mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate); - pogo->target = actor; - } - - actor->reactiontime = 1; -} - -// Function: A_EggmanBox -// -// Description: Harms the player -// -// var1 = unused -// var2 = unused -// -void A_EggmanBox(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_EggmanBox", actor)) - return; -#endif - if (!actor->target || !actor->target->player) - { - CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); - return; - } - - P_DamageMobj(actor->target, actor, actor, 1, 0); // Ow! -} - -// Function: A_TurretFire -// -// Description: Initiates turret fire. -// -// var1 = object # to repeatedly fire -// var2 = distance threshold -// -void A_TurretFire(mobj_t *actor) -{ - INT32 count = 0; - fixed_t dist; - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_TurretFire", actor)) - return; -#endif - - if (locvar2) - dist = FixedMul(locvar2*FRACUNIT, actor->scale); - else - dist = FixedMul(2048*FRACUNIT, actor->scale); - - if (!locvar1) - locvar1 = MT_TURRETLASER; - - while (P_SupermanLook4Players(actor) && count < MAXPLAYERS) - { - if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist) - { - actor->flags2 |= MF2_FIRING; - actor->extravalue1 = locvar1; - break; - } - - count++; - } -} - -// Function: A_SuperTurretFire -// -// Description: Initiates turret fire that even stops Super Sonic. -// -// var1 = object # to repeatedly fire -// var2 = distance threshold -// -void A_SuperTurretFire(mobj_t *actor) -{ - INT32 count = 0; - fixed_t dist; - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SuperTurretFire", actor)) - return; -#endif - - if (locvar2) - dist = FixedMul(locvar2*FRACUNIT, actor->scale); - else - dist = FixedMul(2048*FRACUNIT, actor->scale); - - if (!locvar1) - locvar1 = MT_TURRETLASER; - - while (P_SupermanLook4Players(actor) && count < MAXPLAYERS) - { - if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist) - { - actor->flags2 |= MF2_FIRING; - actor->flags2 |= MF2_SUPERFIRE; - actor->extravalue1 = locvar1; - break; - } - - count++; - } -} - -// Function: A_TurretStop -// -// Description: Stops the turret fire. -// -// var1 = Don't play activesound? -// var2 = unused -// -void A_TurretStop(mobj_t *actor) -{ - INT32 locvar1 = var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_TurretStop", actor)) - return; -#endif - - actor->flags2 &= ~MF2_FIRING; - actor->flags2 &= ~MF2_SUPERFIRE; - - if (actor->target && actor->info->activesound && !locvar1) - S_StartSound(actor, actor->info->activesound); -} - -// Function: A_SparkFollow -// -// Description: Used by the hyper sparks to rotate around their target. -// -// var1 = unused -// var2 = unused -// -void A_SparkFollow(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SparkFollow", actor)) - return; -#endif - - if ((!actor->target || (actor->target->health <= 0)) - || (actor->target->player && !actor->target->player->powers[pw_super])) - { - P_RemoveMobj(actor); - return; - } - - actor->angle += FixedAngle(actor->info->damage*FRACUNIT); - P_UnsetThingPosition(actor); - { - const angle_t fa = actor->angle>>ANGLETOFINESHIFT; - actor->x = actor->target->x + FixedMul(FINECOSINE(fa),FixedMul(actor->info->speed, actor->scale)); - actor->y = actor->target->y + FixedMul(FINESINE(fa),FixedMul(actor->info->speed, actor->scale)); - if (actor->target->eflags & MFE_VERTICALFLIP) - actor->z = actor->target->z + actor->target->height - FixedDiv(actor->target->height,3*FRACUNIT); - else - actor->z = actor->target->z + FixedDiv(actor->target->height,3*FRACUNIT) - actor->height; - } - P_SetThingPosition(actor); -} - -// Function: A_BuzzFly -// -// Description: Makes an object slowly fly after a player, in the manner of a Buzz. -// -// var1 = sfx to play -// var2 = length of sfx, set to threshold if played -// -void A_BuzzFly(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BuzzFly", actor)) - return; -#endif - if (actor->flags2 & MF2_AMBUSH) - return; - - if (actor->reactiontime) - actor->reactiontime--; - - // modify target threshold - if (actor->threshold) - { - if (!actor->target || actor->target->health <= 0) - actor->threshold = 0; - else - actor->threshold--; - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - actor->momz = actor->momy = actor->momx = 0; - P_SetMobjState(actor, actor->info->spawnstate); - return; - } - - // turn towards movement direction if not there yet - actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - - if (actor->target->health <= 0 || (!actor->threshold && !P_CheckSight(actor, actor->target))) - { - if ((multiplayer || netgame) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale))) - return; // got a new target - - actor->momx = actor->momy = actor->momz = 0; - P_SetMobjState(actor, actor->info->spawnstate); // Go back to looking around - return; - } - - // If the player is over 3072 fracunits away, then look for another player - if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), - actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale)) - { - if (multiplayer || netgame) - P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)); // maybe get a new target - - return; - } - - // chase towards player - { - INT32 dist, realspeed; - const fixed_t mf = 5*(FRACUNIT/4); - - if (ultimatemode) - realspeed = FixedMul(FixedMul(actor->info->speed,mf), actor->scale); - else - realspeed = FixedMul(actor->info->speed, actor->scale); - - dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, - actor->target->y - actor->y), actor->target->z - actor->z); - - if (dist < 1) - dist = 1; - - actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), realspeed); - actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), realspeed); - actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), realspeed); - - if (actor->z+actor->momz >= actor->waterbottom && actor->watertop > actor->floorz - && actor->z+actor->momz > actor->watertop - FixedMul(256*FRACUNIT, actor->scale) - && actor->z+actor->momz <= actor->watertop) - { - actor->momz = 0; - actor->z = actor->watertop; - } - } - - if (locvar1 != sfx_None && !actor->threshold) - { - S_StartSound(actor, locvar1); - actor->threshold = locvar2; - } -} - -// Function: A_GuardChase -// -// Description: Modified A_Chase for Egg Guard -// -// var1 = unused -// var2 = unused -// -void A_GuardChase(mobj_t *actor) -{ - INT32 delta; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GuardChase", actor)) - return; -#endif - - if (actor->reactiontime) - actor->reactiontime--; - - if (actor->threshold != 42) // In formation... - { - fixed_t speed; - - if (!actor->tracer || !actor->tracer->health) - { - P_SetTarget(&actor->tracer, NULL); - actor->threshold = 42; - P_SetMobjState(actor, actor->info->painstate); - actor->flags |= MF_SPECIAL|MF_SHOOTABLE; - return; - } - - speed = actor->extravalue1*actor->scale; - - if (actor->flags2 & MF2_AMBUSH) - speed <<= 1; - - if (speed - && !P_TryMove(actor, - actor->x + P_ReturnThrustX(actor, actor->angle, speed), - actor->y + P_ReturnThrustY(actor, actor->angle, speed), - false) - && speed > 0) // can't be the same check as previous so that P_TryMove gets to happen. - { - if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_OBJECTSPECIAL)) - actor->angle += ANGLE_90; - else if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_EXTRA)) - actor->angle -= ANGLE_90; - else - actor->angle += ANGLE_180; - } - - if (actor->extravalue1 < actor->info->speed) - actor->extravalue1++; - } - else // Break ranks! - { - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjStateNF(actor, actor->info->spawnstate); - return; - } - - // possibly choose another target - if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - && P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) - { - P_NewChaseDir(actor); - actor->movecount += 5; // Increase tics before change in direction allowed. - } - } - - // Now that we've moved, its time for our shield to move! - // Otherwise it'll never act as a proper overlay. - if (actor->tracer && actor->tracer->state - && actor->tracer->state->action.acp1) - { - var1 = actor->tracer->state->var1, var2 = actor->tracer->state->var2; - actor->tracer->state->action.acp1(actor->tracer); - } -} - -// Function: A_EggShield -// -// Description: Modified A_Chase for Egg Guard's shield -// -// var1 = unused -// var2 = unused -// -void A_EggShield(mobj_t *actor) -{ - INT32 i; - player_t *player; - fixed_t blockdist; - fixed_t newx, newy; - fixed_t movex, movey; - angle_t angle; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_EggShield", actor)) - return; -#endif - - if (!actor->target || !actor->target->health) - { - P_RemoveMobj(actor); - return; - } - - newx = actor->target->x + P_ReturnThrustX(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale)); - newy = actor->target->y + P_ReturnThrustY(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale)); - - movex = newx - actor->x; - movey = newy - actor->y; - - actor->angle = actor->target->angle; - if (actor->target->eflags & MFE_VERTICALFLIP) - { - actor->eflags |= MFE_VERTICALFLIP; - actor->z = actor->target->z + actor->target->height - actor->height; - } - else - actor->z = actor->target->z; - - actor->destscale = actor->target->destscale; - P_SetScale(actor, actor->target->scale); - - actor->floorz = actor->target->floorz; - actor->ceilingz = actor->target->ceilingz; - - if (!movex && !movey) - return; - - P_UnsetThingPosition(actor); - actor->x = newx; - actor->y = newy; - P_SetThingPosition(actor); - - // Search for players to push - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - player = &players[i]; - - if (!player->mo) - continue; - - if (player->mo->z > actor->z + actor->height) - continue; - - if (player->mo->z + player->mo->height < actor->z) - continue; - - blockdist = actor->radius + player->mo->radius; - - if (abs(actor->x - player->mo->x) >= blockdist || abs(actor->y - player->mo->y) >= blockdist) - continue; // didn't hit it - - angle = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; - - if (angle > ANGLE_90 && angle < ANGLE_270) - continue; - - // Blocked by the shield - player->mo->momx += movex; - player->mo->momy += movey; - return; - } -} - - -// Function: A_SetReactionTime -// -// Description: Sets the object's reaction time. -// -// var1 = 1 (use value in var2); 0 (use info table value) -// var2 = if var1 = 1, then value to set -// -void A_SetReactionTime(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetReactionTime", actor)) - return; -#endif - if (var1) - actor->reactiontime = var2; - else - actor->reactiontime = actor->info->reactiontime; -} - -// Function: A_Boss1Spikeballs -// -// Description: Boss 1 spikeball spawning loop. -// -// var1 = ball number -// var2 = total balls -// -void A_Boss1Spikeballs(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *ball; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss1Spikeballs", actor)) - return; -#endif - - ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL); - P_SetTarget(&ball->target, actor); - ball->movedir = FixedAngle(FixedMul(FixedDiv(locvar1<threshold = ball->radius + actor->radius + ball->info->painchance; - - S_StartSound(ball, ball->info->seesound); - var1 = ball->state->var1, var2 = ball->state->var2; - ball->state->action.acp1(ball); -} - -// Function: A_Boss3TakeDamage -// -// Description: Called when Boss 3 takes damage. -// -// var1 = movecount value -// var2 = unused -// -void A_Boss3TakeDamage(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss3TakeDamage", actor)) - return; -#endif - actor->movecount = var1; - - if (actor->target && actor->target->spawnpoint) - actor->threshold = actor->target->spawnpoint->extrainfo; -} - -// Function: A_Boss3Path -// -// Description: Does pathfinding along Boss 3's nodes. -// -// var1 = unused -// var2 = unused -// -void A_Boss3Path(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss3Path", actor)) - return; -#endif - - if (actor->tracer && actor->tracer->health && actor->tracer->movecount) - actor->movecount |= 1; - else if (actor->movecount & 1) - actor->movecount = 0; - - if (actor->movecount & 2) // We've reached a firing point? - { - // Wait here and pretend to be angry or something. - actor->momx = 0; - actor->momy = 0; - actor->momz = 0; - P_SetTarget(&actor->target, actor->tracer->target); - var1 = 0, var2 = 0; - A_FaceTarget(actor); - if (actor->tracer->state == &states[actor->tracer->info->missilestate]) - P_SetMobjState(actor, actor->info->missilestate); - return; - } - else if (actor->threshold >= 0) // Traveling mode - { - thinker_t *th; - mobj_t *mo2; - fixed_t dist, dist2; - fixed_t speed; - - P_SetTarget(&actor->target, NULL); - - // scan the thinkers - // to find a point that matches - // the number - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold) - { - P_SetTarget(&actor->target, mo2); - break; - } - } - - if (!actor->target) // Should NEVER happen - { - CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d\n", actor->threshold); - return; - } - - dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z); - - if (dist < 1) - dist = 1; - - if (actor->tracer && ((actor->tracer->movedir) - || (actor->tracer->health <= actor->tracer->info->damage))) - speed = actor->info->speed * 2; - else - speed = actor->info->speed; - - actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), speed); - actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), speed); - actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), speed); - - if (actor->momx != 0 || actor->momy != 0) - actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); - - dist2 = P_AproxDistance(P_AproxDistance(actor->target->x - (actor->x + actor->momx), actor->target->y - (actor->y + actor->momy)), actor->target->z - (actor->z + actor->momz)); - - if (dist2 < 1) - dist2 = 1; - - if ((dist >> FRACBITS) <= (dist2 >> FRACBITS)) - { - // If further away, set XYZ of mobj to waypoint location - P_UnsetThingPosition(actor); - actor->x = actor->target->x; - actor->y = actor->target->y; - actor->z = actor->target->z; - actor->momx = actor->momy = actor->momz = 0; - P_SetThingPosition(actor); - - if (actor->threshold == 0) - { - P_RemoveMobj(actor); // Cycle completed. Dummy removed. - return; - } - - // Set to next waypoint in sequence - if (actor->target->spawnpoint) - { - // From the center point, choose one of the five paths - if (actor->target->spawnpoint->angle == 0) - { - P_RemoveMobj(actor); // Cycle completed. Dummy removed. - return; - } - else - actor->threshold = actor->target->spawnpoint->extrainfo; - - // If the deaf flag is set, go into firing mode - if (actor->target->spawnpoint->options & MTF_AMBUSH) - actor->movecount |= 2; - } - else // This should never happen, as well - CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy waypoint has no spawnpoint associated with it.\n"); - } - } -} - -// Function: A_LinedefExecute -// -// Description: Object's location is used to set the calling sector. The tag used is var1. Optionally, if var2 is set, the actor's angle (multiplied by var2) is added to the tag number as well. -// -// var1 = tag -// var2 = add angle to tag (optional) -// -void A_LinedefExecute(mobj_t *actor) -{ - INT32 tagnum; - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_LinedefExecute", actor)) - return; -#endif - - tagnum = locvar1; - // state numbers option is no more, custom states cannot be guaranteed to stay the same number anymore, now that they can be defined by names instead - - if (locvar2) - tagnum += locvar2*(AngleFixed(actor->angle)>>FRACBITS); - - CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecute: Running mobjtype %d's sector with tag %d\n", actor->type, tagnum); - - // tag 32768 displayed in map editors is actually tag -32768, tag 32769 is -32767, 65535 is -1 etc. - P_LinedefExecute((INT16)tagnum, actor, actor->subsector->sector); -} - -// Function: A_PlaySeeSound -// -// Description: Plays the object's seesound. -// -// var1 = unused -// var2 = unused -// -void A_PlaySeeSound(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_PlaySeeSound", actor)) - return; -#endif - if (actor->info->seesound) - S_StartScreamSound(actor, actor->info->seesound); -} - -// Function: A_PlayAttackSound -// -// Description: Plays the object's attacksound. -// -// var1 = unused -// var2 = unused -// -void A_PlayAttackSound(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_PlayAttackSound", actor)) - return; -#endif - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); -} - -// Function: A_PlayActiveSound -// -// Description: Plays the object's activesound. -// -// var1 = unused -// var2 = unused -// -void A_PlayActiveSound(mobj_t *actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_PlayActiveSound", actor)) - return; -#endif - if (actor->info->activesound) - S_StartSound(actor, actor->info->activesound); -} - -// Function: A_SmokeTrailer -// -// Description: Adds smoke trails to an object. -// -// var1 = object # to spawn as smoke -// var2 = unused -// -void A_SmokeTrailer(mobj_t *actor) -{ - mobj_t *th; - INT32 locvar1 = var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SmokeTrailer", actor)) - return; -#endif - - if (leveltime % 4) - return; - - // add the smoke behind the rocket - if (actor->eflags & MFE_VERTICALFLIP) - { - th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z + actor->height - FixedMul(mobjinfo[locvar1].height, actor->scale), locvar1); - th->flags2 |= MF2_OBJECTFLIP; - } - else - th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z, locvar1); - P_SetObjectMomZ(th, FRACUNIT, false); - th->destscale = actor->scale; - P_SetScale(th, actor->scale); - th->tics -= P_RandomByte() & 3; - if (th->tics < 1) - th->tics = 1; -} - -// Function: A_SpawnObjectAbsolute -// -// Description: Spawns an object at an absolute position -// -// var1: -// var1 >> 16 = x -// var1 & 65535 = y -// var2: -// var2 >> 16 = z -// var2 & 65535 = type -// -void A_SpawnObjectAbsolute(mobj_t *actor) -{ - INT16 x, y, z; // Want to be sure we can use negative values - mobjtype_t type; - mobj_t *mo; - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SpawnObjectAbsolute", actor)) - return; -#endif - - x = (INT16)(locvar1>>16); - y = (INT16)(locvar1&65535); - z = (INT16)(locvar2>>16); - type = (mobjtype_t)(locvar2&65535); - - mo = P_SpawnMobj(x<angle = actor->angle; - - if (actor->eflags & MFE_VERTICALFLIP) - mo->flags2 |= MF2_OBJECTFLIP; -} - -// Function: A_SpawnObjectRelative -// -// Description: Spawns an object relative to the location of the actor -// -// var1: -// var1 >> 16 = x -// var1 & 65535 = y -// var2: -// var2 >> 16 = z -// var2 & 65535 = type -// -void A_SpawnObjectRelative(mobj_t *actor) -{ - INT16 x, y, z; // Want to be sure we can use negative values - mobjtype_t type; - mobj_t *mo; - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SpawnObjectRelative", actor)) - return; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_SpawnObjectRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); - - x = (INT16)(locvar1>>16); - y = (INT16)(locvar1&65535); - z = (INT16)(locvar2>>16); - type = (mobjtype_t)(locvar2&65535); - - // Spawn objects correctly in reverse gravity. - // NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame - mo = P_SpawnMobj(actor->x + FixedMul(x<scale), - actor->y + FixedMul(y<scale), - (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), type); - - // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn - mo->angle = actor->angle; - - if (actor->eflags & MFE_VERTICALFLIP) - mo->flags2 |= MF2_OBJECTFLIP; - -} - -// Function: A_ChangeAngleRelative -// -// Description: Changes the angle to a random relative value between the min and max. Set min and max to the same value to eliminate randomness -// -// var1 = min -// var2 = max -// -void A_ChangeAngleRelative(mobj_t *actor) -{ - // Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of - // getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result - // rather than the ranges, so <0 and >360 work as possible values. -Red - INT32 locvar1 = var1; - INT32 locvar2 = var2; - //angle_t angle = (P_RandomByte()+1)<<24; - const fixed_t amin = locvar1*FRACUNIT; - const fixed_t amax = locvar2*FRACUNIT; - //const angle_t amin = FixedAngle(locvar1*FRACUNIT); - //const angle_t amax = FixedAngle(locvar2*FRACUNIT); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ChangeAngleRelative", actor)) - return; -#endif - -#ifdef PARANOIA - if (amin > amax) - I_Error("A_ChangeAngleRelative: var1 is greater then var2"); -#endif -/* - if (angle < amin) - angle = amin; - if (angle > amax) - angle = amax;*/ - - actor->angle += FixedAngle(P_RandomRange(amin, amax)); -} - -// Function: A_ChangeAngleAbsolute -// -// Description: Changes the angle to a random absolute value between the min and max. Set min and max to the same value to eliminate randomness -// -// var1 = min -// var2 = max -// -void A_ChangeAngleAbsolute(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - //angle_t angle = (P_RandomByte()+1)<<24; - const fixed_t amin = locvar1*FRACUNIT; - const fixed_t amax = locvar2*FRACUNIT; - //const angle_t amin = FixedAngle(locvar1*FRACUNIT); - //const angle_t amax = FixedAngle(locvar2*FRACUNIT); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ChangeAngleAbsolute", actor)) - return; -#endif - -#ifdef PARANOIA - if (amin > amax) - I_Error("A_ChangeAngleAbsolute: var1 is greater then var2"); -#endif -/* - if (angle < amin) - angle = amin; - if (angle > amax) - angle = amax;*/ - - actor->angle = FixedAngle(P_RandomRange(amin, amax)); -} - -// Function: A_PlaySound -// -// Description: Plays a sound -// -// var1 = sound # to play -// var2: -// 0 = Play sound without an origin -// 1 = Play sound using calling object as origin -// -void A_PlaySound(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_PlaySound", actor)) - return; -#endif - - S_StartSound(locvar2 ? actor : NULL, locvar1); -} - -// Function: A_FindTarget -// -// Description: Finds the nearest/furthest mobj of the specified type and sets actor->target to it. -// -// var1 = mobj type -// var2 = if (0) nearest; else furthest; -// -void A_FindTarget(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *targetedmobj = NULL; - thinker_t *th; - mobj_t *mo2; - fixed_t dist1 = 0, dist2 = 0; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FindTarget", actor)) - return; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); - - // scan the thinkers - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == (mobjtype_t)locvar1) - { - if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS)) - continue; // Ignore spectators - if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0) - continue; // Ignore dead things - if (targetedmobj == NULL) - { - targetedmobj = mo2; - dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); - } - else - { - dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); - - if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2)) - { - targetedmobj = mo2; - dist2 = dist1; - } - } - } - } - - if (!targetedmobj) - { - CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Unable to find the specified object to target.\n"); - return; // Oops, nothing found.. - } - - CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Found a target.\n"); - - P_SetTarget(&actor->target, targetedmobj); -} - -// Function: A_FindTracer -// -// Description: Finds the nearest/furthest mobj of the specified type and sets actor->tracer to it. -// -// var1 = mobj type -// var2 = if (0) nearest; else furthest; -// -void A_FindTracer(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *targetedmobj = NULL; - thinker_t *th; - mobj_t *mo2; - fixed_t dist1 = 0, dist2 = 0; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FindTracer", actor)) - return; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); - - // scan the thinkers - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == (mobjtype_t)locvar1) - { - if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS)) - continue; // Ignore spectators - if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0) - continue; // Ignore dead things - if (targetedmobj == NULL) - { - targetedmobj = mo2; - dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); - } - else - { - dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); - - if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2)) - { - targetedmobj = mo2; - dist2 = dist1; - } - } - } - } - - if (!targetedmobj) - { - CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Unable to find the specified object to target.\n"); - return; // Oops, nothing found.. - } - - CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Found a target.\n"); - - P_SetTarget(&actor->tracer, targetedmobj); -} - -// Function: A_SetTics -// -// Description: Sets the animation tics of an object -// -// var1 = tics to set to -// var2 = if this is set, and no var1 is supplied, the mobj's threshold value will be used. -// -void A_SetTics(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetTics", actor)) - return; -#endif - - if (locvar1) - actor->tics = locvar1; - else if (locvar2) - actor->tics = actor->threshold; -} - -// Function: A_SetRandomTics -// -// Description: Sets the animation tics of an object to a random value -// -// var1 = lower bound -// var2 = upper bound -// -void A_SetRandomTics(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetRandomTics", actor)) - return; -#endif - - actor->tics = P_RandomRange(locvar1, locvar2); -} - -// Function: A_ChangeColorRelative -// -// Description: Changes the color of an object -// -// var1 = if (var1 > 0), find target and add its color value to yours -// var2 = if (var1 = 0), color value to add -// -void A_ChangeColorRelative(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ChangeColorRelative", actor)) - return; -#endif - - if (locvar1) - { - // Have you ever seen anything so hideous? - if (actor->target) - actor->color = (UINT8)(actor->color + actor->target->color); - } - else - actor->color = (UINT8)(actor->color + locvar2); -} - -// Function: A_ChangeColorAbsolute -// -// Description: Changes the color of an object by an absolute value. Note: 0 is default colormap. -// -// var1 = if (var1 > 0), set your color to your target's color -// var2 = if (var1 = 0), color value to set to -// -void A_ChangeColorAbsolute(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ChangeColorAbsolute", actor)) - return; -#endif - - if (locvar1) - { - if (actor->target) - actor->color = actor->target->color; - } - else - actor->color = (UINT8)locvar2; -} - -// Function: A_MoveRelative -// -// Description: Moves an object (wrapper for P_Thrust) -// -// var1 = angle -// var2 = force -// -void A_MoveRelative(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MoveRelative", actor)) - return; -#endif - - P_Thrust(actor, actor->angle+FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); -} - -// Function: A_MoveAbsolute -// -// Description: Moves an object (wrapper for P_InstaThrust) -// -// var1 = angle -// var2 = force -// -void A_MoveAbsolute(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MoveAbsolute", actor)) - return; -#endif - - P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); -} - -// Function: A_Thrust -// -// Description: Pushes the object horizontally at its current angle. -// -// var1 = amount of force -// var2 = If 1, xy momentum is lost. If 0, xy momentum is kept -// -void A_Thrust(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Thrust", actor)) - return; -#endif - - if (!locvar1) - CONS_Debug(DBG_GAMELOGIC, "A_Thrust: Var1 not specified!\n"); - - if (locvar2) - P_InstaThrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale)); - else - P_Thrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale)); -} - -// Function: A_ZThrust -// -// Description: Pushes the object up or down. -// -// var1 = amount of force -// var2: -// lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept -// upper 16 bits = If 1, z momentum is lost. If 0, z momentum is kept -// -void A_ZThrust(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ZThrust", actor)) - return; -#endif - - if (!locvar1) - CONS_Debug(DBG_GAMELOGIC, "A_ZThrust: Var1 not specified!\n"); - - if (locvar2 & 65535) - actor->momx = actor->momy = 0; - - if (actor->eflags & MFE_VERTICALFLIP) - actor->z--; - else - actor->z++; - - P_SetObjectMomZ(actor, locvar1*FRACUNIT, !(locvar2 >> 16)); -} - -// Function: A_SetTargetsTarget -// -// Description: Sets your target to the object who your target is targeting. Yikes! If it happens to be NULL, you're just out of luck. -// -// var1: (Your target) -// 0 = target -// 1 = tracer -// var2: (Your target's target) -// 0 = target/tracer's target -// 1 = target/tracer's tracer -// -void A_SetTargetsTarget(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *oldtarg = NULL, *newtarg = NULL; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetTargetsTarget", actor)) - return; -#endif - - // actor's target - if (locvar1) // or tracer - oldtarg = actor->tracer; - else - oldtarg = actor->target; - - if (P_MobjWasRemoved(oldtarg)) - return; - - // actor's target's target! - if (locvar2) // or tracer - newtarg = oldtarg->tracer; - else - newtarg = oldtarg->target; - - if (P_MobjWasRemoved(newtarg)) - return; - - // set actor's new target - if (locvar1) // or tracer - P_SetTarget(&actor->tracer, newtarg); - else - P_SetTarget(&actor->target, newtarg); -} - -// Function: A_SetObjectFlags -// -// Description: Sets the flags of an object -// -// var1 = flag value to set -// var2: -// if var2 == 2, add the flag to the current flags -// else if var2 == 1, remove the flag from the current flags -// else if var2 == 0, set the flags to the exact value -// -void A_SetObjectFlags(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - boolean unlinkthings = false; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetObjectFlags", actor)) - return; -#endif - - if (locvar2 == 2) - locvar1 = actor->flags | locvar1; - else if (locvar2 == 1) - locvar1 = actor->flags & ~locvar1; - - if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links - unlinkthings = true; - - if (unlinkthings) { - P_UnsetThingPosition(actor); - if (sector_list) - { - P_DelSeclist(sector_list); - sector_list = NULL; - } - } - - actor->flags = locvar1; - - if (unlinkthings) - P_SetThingPosition(actor); -} - -// Function: A_SetObjectFlags2 -// -// Description: Sets the flags2 of an object -// -// var1 = flag value to set -// var2: -// if var2 == 2, add the flag to the current flags -// else if var2 == 1, remove the flag from the current flags -// else if var2 == 0, set the flags to the exact value -// -void A_SetObjectFlags2(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetObjectFlags2", actor)) - return; -#endif - - if (locvar2 == 2) - actor->flags2 |= locvar1; - else if (locvar2 == 1) - actor->flags2 &= ~locvar1; - else - actor->flags2 = locvar1; -} - -// Function: A_BossJetFume -// -// Description: Spawns jet fumes/other attachment miscellany for the boss. To only be used when he is spawned. -// -// var1: -// 0 - Triple jet fume pattern -// 1 - Boss 3's propeller -// 2 - Metal Sonic jet fume -// 3 - Boss 4 jet flame -// var2 = unused -// -void A_BossJetFume(mobj_t *actor) -{ - mobj_t *filler; - INT32 locvar1 = var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BossJetFume", actor)) - return; -#endif - - if (locvar1 == 0) // Boss1 jet fumes - { - fixed_t jetx, jety, jetz; - - jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale)); - jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - jetz = actor->z + actor->height - FixedMul(38*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale); - else - jetz = actor->z + FixedMul(38*FRACUNIT, actor->scale); - - filler = P_SpawnMobj(jetx, jety, jetz, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->fuse = 56; - - if (actor->eflags & MFE_VERTICALFLIP) - jetz = actor->z + actor->height - FixedMul(12*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale); - else - jetz = actor->z + FixedMul(12*FRACUNIT, actor->scale); - - filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), - jety + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), - jetz, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->fuse = 57; - - filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), - jety + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), - jetz, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->fuse = 58; - - P_SetTarget(&actor->tracer, filler); - } - else if (locvar1 == 1) // Boss 3 propeller - { - fixed_t jetx, jety, jetz; - - jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale)); - jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - jetz = actor->z + actor->height - FixedMul(17*FRACUNIT + mobjinfo[MT_PROPELLER].height, actor->scale); - else - jetz = actor->z + FixedMul(17*FRACUNIT, actor->scale); - - filler = P_SpawnMobj(jetx, jety, jetz, MT_PROPELLER); - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->angle = actor->angle - ANGLE_180; - - P_SetTarget(&actor->tracer, filler); - } - else if (locvar1 == 2) // Metal Sonic jet fumes - { - filler = P_SpawnMobj(actor->x, actor->y, actor->z, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->fuse = 59; - P_SetTarget(&actor->tracer, filler); - filler->destscale = actor->scale/2; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - } - else if (locvar1 == 3) // Boss 4 jet flame - { - fixed_t jetz; - if (actor->eflags & MFE_VERTICALFLIP) - jetz = actor->z + actor->height + FixedMul(50*FRACUNIT - mobjinfo[MT_JETFLAME].height, actor->scale); - else - jetz = actor->z - FixedMul(50*FRACUNIT, actor->scale); - filler = P_SpawnMobj(actor->x, actor->y, jetz, MT_JETFLAME); - P_SetTarget(&filler->target, actor); - // Boss 4 already uses its tracer for other things - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - } -} - -// Function: A_RandomState -// -// Description: Chooses one of the two state numbers supplied randomly. -// -// var1 = state number 1 -// var2 = state number 2 -// -void A_RandomState(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RandomState", actor)) - return; -#endif - - P_SetMobjState(actor, P_RandomChance(FRACUNIT/2) ? locvar1 : locvar2); -} - -// Function: A_RandomStateRange -// -// Description: Chooses a random state within the range supplied. -// -// var1 = Minimum state number to choose. -// var2 = Maximum state number to use. -// -void A_RandomStateRange(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RandomStateRange", actor)) - return; -#endif - - P_SetMobjState(actor, P_RandomRange(locvar1, locvar2)); -} - -// Function: A_DualAction -// -// Description: Calls two actions. Be careful, if you reference the same state this action is called from, you can create an infinite loop. -// -// var1 = state # to use 1st action from -// var2 = state # to use 2nd action from -// -void A_DualAction(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_DualAction", actor)) - return; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_DualAction called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); - - var1 = states[locvar1].var1; - var2 = states[locvar1].var2; -#ifdef HAVE_BLUA - astate = &states[locvar1]; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling First Action (state %d)...\n", locvar1); - states[locvar1].action.acp1(actor); - - var1 = states[locvar2].var1; - var2 = states[locvar2].var2; -#ifdef HAVE_BLUA - astate = &states[locvar2]; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling Second Action (state %d)...\n", locvar2); - states[locvar2].action.acp1(actor); -} - -// Function: A_RemoteAction -// -// Description: var1 is the remote object. var2 is the state reference for calling the action called on var1. var1 becomes the actor's target, the action (var2) is called on var1. actor's target is restored -// -// var1 = remote object (-2 uses tracer, -1 uses target) -// var2 = state reference for calling an action -// -void A_RemoteAction(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *originaltarget = actor->target; // Hold on to the target for later. -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RemoteAction", actor)) - return; -#endif - - // If >=0, find the closest target. - if (locvar1 >= 0) - { - ///* DO A_FINDTARGET STUFF */// - mobj_t *targetedmobj = NULL; - thinker_t *th; - mobj_t *mo2; - fixed_t dist1 = 0, dist2 = 0; - - // scan the thinkers - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == (mobjtype_t)locvar1) - { - if (targetedmobj == NULL) - { - targetedmobj = mo2; - dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); - } - else - { - dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); - - if ((locvar2 && dist1 < dist2) || (!locvar2 && dist1 > dist2)) - { - targetedmobj = mo2; - dist2 = dist1; - } - } - } - } - - if (!targetedmobj) - { - CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Unable to find the specified object to target.\n"); - return; // Oops, nothing found.. - } - - CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Found a target.\n"); - - P_SetTarget(&actor->target, targetedmobj); - - ///* END A_FINDTARGET STUFF */// - } - - // If -2, use the tracer as the target - else if (locvar1 == -2) - P_SetTarget(&actor->target, actor->tracer); - // if -1 or anything else, just use the target. - - if (actor->target) - { - // Steal the var1 and var2 from "locvar2" - var1 = states[locvar2].var1; - var2 = states[locvar2].var2; -#ifdef HAVE_BLUA - astate = &states[locvar2]; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Calling action on %p\n" - "var1 is %d\nvar2 is %d\n", actor->target, var1, var2); - states[locvar2].action.acp1(actor->target); - } - - P_SetTarget(&actor->target, originaltarget); // Restore the original target. -} - -// Function: A_ToggleFlameJet -// -// Description: Turns a flame jet on and off. -// -// var1 = unused -// var2 = unused -// -void A_ToggleFlameJet(mobj_t* actor) -{ -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ToggleFlameJet", actor)) - return; -#endif - // threshold - off delay - // movecount - on timer - - if (actor->flags2 & MF2_FIRING) - { - actor->flags2 &= ~MF2_FIRING; - - if (actor->threshold) - actor->tics = actor->threshold; - } - else - { - actor->flags2 |= MF2_FIRING; - - if (actor->movecount) - actor->tics = actor->movecount; - } -} - -// Function: A_OrbitNights -// -// Description: Used by Chaos Emeralds to orbit around Nights (aka Super Sonic.) -// -// var1 = Angle adjustment (aka orbit speed) -// var2 = Lower four bits: height offset, Upper 4 bits = set if object is Nightopian Helper -// -void A_OrbitNights(mobj_t* actor) -{ - INT32 ofs = (var2 & 0xFFFF); - boolean ishelper = (var2 & 0xFFFF0000); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_OrbitNights", actor)) - return; -#endif - - if (!actor->target || !actor->target->player || - !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE) || !actor->target->player->nightstime - // Also remove this object if they no longer have a NiGHTS helper - || (ishelper && !actor->target->player->powers[pw_nights_helper])) - { - P_RemoveMobj(actor); - return; - } - else - { - actor->extravalue1 += var1; - P_UnsetThingPosition(actor); - { - const angle_t fa = (angle_t)actor->extravalue1 >> ANGLETOFINESHIFT; - const angle_t ofa = ((angle_t)actor->extravalue1 + (ofs*ANG1)) >> ANGLETOFINESHIFT; - - const fixed_t fc = FixedMul(FINECOSINE(fa),FixedMul(32*FRACUNIT, actor->scale)); - const fixed_t fh = FixedMul(FINECOSINE(ofa),FixedMul(20*FRACUNIT, actor->scale)); - const fixed_t fs = FixedMul(FINESINE(fa),FixedMul(32*FRACUNIT, actor->scale)); - - actor->x = actor->target->x + fc; - actor->y = actor->target->y + fs; - actor->z = actor->target->z + fh + FixedMul(16*FRACUNIT, actor->scale); - - // Semi-lazy hack - actor->angle = (angle_t)actor->extravalue1 + ANGLE_90; - } - P_SetThingPosition(actor); - - if (ishelper) // Flash a helper that's about to be removed. - { - if ((actor->target->player->powers[pw_nights_helper] < TICRATE) - && (actor->target->player->powers[pw_nights_helper] & 1)) - actor->flags2 |= MF2_DONTDRAW; - else - actor->flags2 &= ~MF2_DONTDRAW; - } - } -} - -// Function: A_GhostMe -// -// Description: Spawns a "ghost" mobj of this actor, ala spindash trails and the minus's digging "trails" -// -// var1 = duration in tics -// var2 = unused -// -void A_GhostMe(mobj_t *actor) -{ - INT32 locvar1 = var1; - mobj_t *ghost; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_GhostMe", actor)) - return; -#endif - ghost = P_SpawnGhostMobj(actor); - if (ghost && locvar1 > 0) - ghost->fuse = locvar1; -} - -// Function: A_SetObjectState -// -// Description: Changes the state of an object's target/tracer. -// -// var1 = state number -// var2: -// 0 = target -// 1 = tracer -// -void A_SetObjectState(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *target; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetObjectState", actor)) - return; -#endif - - if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer)) - { - if (cv_debug) - CONS_Printf("A_SetObjectState: No target to change state!\n"); - return; - } - - if (!locvar2) // target - target = actor->target; - else // tracer - target = actor->tracer; - - if (target->health > 0) - { - if (!target->player) - P_SetMobjState(target, locvar1); - else - P_SetPlayerMobjState(target, locvar1); - } -} - -// Function: A_SetObjectTypeState -// -// Description: Changes the state of all active objects of a certain type in a certain range of the actor. -// -// var1 = state number -// var2: -// lower 16 bits = type -// upper 16 bits = range (if == 0, across whole map) -// -void A_SetObjectTypeState(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - const UINT16 loc2lw = (UINT16)(locvar2 & 65535); - const UINT16 loc2up = (UINT16)(locvar2 >> 16); - - thinker_t *th; - mobj_t *mo2; - fixed_t dist = 0; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetObjectTypeState", actor)) - return; -#endif - - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == (mobjtype_t)loc2lw) - { - dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y); - - if (mo2->health > 0) - { - if (loc2up == 0) - P_SetMobjState(mo2, locvar1); - else - { - if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale)) - P_SetMobjState(mo2, locvar1); - } - } - } - } -} - -// Function: A_KnockBack -// -// Description: Knocks back the object's target at its current speed. -// -// var1: -// 0 = target -// 1 = tracer -// var2 = unused -// -void A_KnockBack(mobj_t *actor) -{ - INT32 locvar1 = var1; - mobj_t *target; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_KnockBack", actor)) - return; -#endif - - if (!locvar1) - target = actor->target; - else - target = actor->tracer; - - if (!target) - { - if(cv_debug) - CONS_Printf("A_KnockBack: No target!\n"); - return; - } - - target->momx *= -1; - target->momy *= -1; -} - -// Function: A_PushAway -// -// Description: Pushes an object's target away from the calling object. -// -// var1 = amount of force -// var2: -// lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept -// upper 16 bits = 0 - target, 1 - tracer -// -void A_PushAway(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *target; // target - angle_t an; // actor to target angle -#ifdef HAVE_BLUA - if (LUA_CallAction("A_PushAway", actor)) - return; -#endif - - if ((!(locvar2 >> 16) && !actor->target) || ((locvar2 >> 16) && !actor->tracer)) - return; - - if (!locvar1) - CONS_Printf("A_Thrust: Var1 not specified!\n"); - - if (!(locvar2 >> 16)) // target - target = actor->target; - else // tracer - target = actor->tracer; - - an = R_PointToAngle2(actor->x, actor->y, target->x, target->y); - - if (locvar2 & 65535) - P_InstaThrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale)); - else - P_Thrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale)); -} - -// Function: A_RingDrain -// -// Description: Drain targeted player's rings. -// -// var1 = ammount of drained rings -// var2 = unused -// -void A_RingDrain(mobj_t *actor) -{ - INT32 locvar1 = var1; - player_t *player; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RingDrain", actor)) - return; -#endif - - if (!actor->target || !actor->target->player) - { - if(cv_debug) - CONS_Printf("A_RingDrain: No player targeted!\n"); - return; - } - - player = actor->target->player; - P_GivePlayerRings(player, -min(locvar1, player->rings)); -} - -// Function: A_SplitShot -// -// Description: Shoots 2 missiles that hit next to the player. -// -// var1 = target x-y-offset -// var2: -// lower 16 bits = missile type -// upper 16 bits = height offset -// -void A_SplitShot(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - const UINT16 loc2lw = (UINT16)(locvar2 & 65535); - const UINT16 loc2up = (UINT16)(locvar2 >> 16); - const fixed_t offs = (fixed_t)(locvar1*FRACUNIT); - const fixed_t hoffs = (fixed_t)(loc2up*FRACUNIT); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SplitShot", actor)) - return; -#endif - - A_FaceTarget(actor); - { - const angle_t an = (actor->angle + ANGLE_90) >> ANGLETOFINESHIFT; - const fixed_t fasin = FINESINE(an); - const fixed_t facos = FINECOSINE(an); - fixed_t xs = FixedMul(facos,FixedMul(offs, actor->scale)); - fixed_t ys = FixedMul(fasin,FixedMul(offs, actor->scale)); - fixed_t z; - - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(hoffs, actor->scale); - else - z = actor->z + FixedMul(hoffs, actor->scale); - - P_SpawnPointMissile(actor, actor->target->x+xs, actor->target->y+ys, actor->target->z, loc2lw, actor->x, actor->y, z); - P_SpawnPointMissile(actor, actor->target->x-xs, actor->target->y-ys, actor->target->z, loc2lw, actor->x, actor->y, z); - } -} - -// Function: A_MissileSplit -// -// Description: If the object is a missile it will create a new missile with an alternate flight path owned by the one who shot the former missile. -// -// var1 = splitting missile type -// var2 = splitting angle -// -void A_MissileSplit(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MissileSplit", actor)) - return; -#endif - if (actor->eflags & MFE_VERTICALFLIP) - P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z+actor->height, locvar2); - else - P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z, locvar2); -} - -// Function: A_MultiShot -// -// Description: Shoots objects horizontally that spread evenly in all directions. -// -// var1: -// lower 16 bits = number of missiles -// upper 16 bits = missile type # -// var2 = height offset -// -void A_MultiShot(mobj_t *actor) -{ - fixed_t z, xr, yr; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - const UINT16 loc1lw = (UINT16)(locvar1 & 65535); - const UINT16 loc1up = (UINT16)(locvar1 >> 16); - INT32 count = 0; - fixed_t ad; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MultiShot", actor)) - return; -#endif - - if (actor->target) - A_FaceTarget(actor); - - if(loc1lw > 90) - ad = FixedMul(90*FRACUNIT, actor->scale); - else - ad = FixedMul(loc1lw*FRACUNIT, actor->scale); - - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); - xr = FixedMul((P_SignedRandom()/3)<scale); // please note p_mobj.c's P_Rand() abuse - yr = FixedMul((P_SignedRandom()/3)<scale); // of rand(), RAND_MAX and signness mess - - while(count <= loc1lw && loc1lw >= 1) - { - const angle_t fa = FixedAngleC(count*FRACUNIT*360, ad)>>ANGLETOFINESHIFT; - const fixed_t rc = FINECOSINE(fa); - const fixed_t rs = FINESINE(fa); - const fixed_t xrc = FixedMul(xr, rc); - const fixed_t yrs = FixedMul(yr, rs); - const fixed_t xrs = FixedMul(xr, rs); - const fixed_t yrc = FixedMul(yr, rc); - - P_SpawnPointMissile(actor, xrc-yrs+actor->x, xrs+yrc+actor->y, z, loc1up, actor->x, actor->y, z); - count++; - } - - if (!(actor->flags & MF_BOSS)) - { - if (ultimatemode) - actor->reactiontime = actor->info->reactiontime*TICRATE; - else - actor->reactiontime = actor->info->reactiontime*TICRATE*2; - } -} - -// Function: A_InstaLoop -// -// Description: Makes the object move along a 2d (view angle, z) polygon. -// -// var1: -// lower 16 bits = current step -// upper 16 bits = maximum step # -// var2 = force -// -void A_InstaLoop(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - fixed_t force = max(locvar2, 1)*FRACUNIT; // defaults to 1 if var2 < 1 - const UINT16 loc1lw = (UINT16)(locvar1 & 65535); - const UINT16 loc1up = (UINT16)(locvar1 >> 16); - const angle_t fa = FixedAngleC(loc1lw*FRACUNIT*360, loc1up*FRACUNIT)>>ANGLETOFINESHIFT; - const fixed_t ac = FINECOSINE(fa); - const fixed_t as = FINESINE(fa); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_InstaLoop", actor)) - return; -#endif - - P_InstaThrust(actor, actor->angle, FixedMul(ac, FixedMul(force, actor->scale))); - P_SetObjectMomZ(actor, FixedMul(as, force), false); -} - -// Function: A_Custom3DRotate -// -// Description: Rotates the actor around its target in 3 dimensions. -// -// var1: -// lower 16 bits = radius in fracunits -// upper 16 bits = vertical offset -// var2: -// lower 16 bits = vertical rotation speed in 1/10 fracunits per tic -// upper 16 bits = horizontal rotation speed in 1/10 fracunits per tic -// -void A_Custom3DRotate(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - - const UINT16 loc1lw = (UINT16)(locvar1 & 65535); - const UINT16 loc1up = (UINT16)(locvar1 >> 16); - const UINT16 loc2lw = (UINT16)(locvar2 & 65535); - const UINT16 loc2up = (UINT16)(locvar2 >> 16); - - const fixed_t radius = FixedMul(loc1lw*FRACUNIT, actor->scale); - const fixed_t hOff = FixedMul(loc1up*FRACUNIT, actor->scale); - const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale); - const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale); -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Custom3DRotate", actor)) - return; -#endif - - if (actor->target->health == 0) - { - P_RemoveMobj(actor); - return; - } - - if (!actor->target) // This should NEVER happen. - { - if (cv_debug) - CONS_Printf("Error: Object has no target\n"); - P_RemoveMobj(actor); - return; - } - if (hspeed==0 && vspeed==0) - { - CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n"); - return; - } - - actor->angle += FixedAngle(hspeed); - actor->movedir += FixedAngle(vspeed); - P_UnsetThingPosition(actor); - { - const angle_t fa = actor->angle>>ANGLETOFINESHIFT; - - if (vspeed == 0 && hspeed != 0) - { - actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius); - actor->y = actor->target->y + FixedMul(FINESINE(fa),radius); - actor->z = actor->target->z + actor->target->height/2 - actor->height/2 + hOff; - } - else - { - const angle_t md = actor->movedir>>ANGLETOFINESHIFT; - actor->x = actor->target->x + FixedMul(FixedMul(FINESINE(md),FINECOSINE(fa)),radius); - actor->y = actor->target->y + FixedMul(FixedMul(FINESINE(md),FINESINE(fa)),radius); - actor->z = actor->target->z + FixedMul(FINECOSINE(md),radius) + actor->target->height/2 - actor->height/2 + hOff; - } - } - P_SetThingPosition(actor); -} - -// Function: A_SearchForPlayers -// -// Description: Checks if the actor has targeted a vulnerable player. If not a new player will be searched all around. If no players are available the object can call a specific state. (Useful for not moving enemies) -// -// var1: -// if var1 == 0, if necessary call state with same state number as var2 -// else, do not call a specific state if no players are available -// var2 = state number -// -void A_SearchForPlayers(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SearchForPlayers", actor)) - return; -#endif - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - if(locvar1==0) - { - P_SetMobjStateNF(actor, locvar2); - return; - } - } -} - -// Function: A_CheckRandom -// -// Description: Calls a state by chance. -// -// var1: -// lower 16 bits = denominator -// upper 16 bits = numerator (defaults to 1 if zero) -// var2 = state number -// -void A_CheckRandom(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - fixed_t chance = FRACUNIT; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckRandom", actor)) - return; -#endif - if ((locvar1 & 0xFFFF) == 0) - return; - - // The PRNG doesn't suck anymore, OK? - if (locvar1 >> 16) - chance *= (locvar1 >> 16); - chance /= (locvar1 & 0xFFFF); - - if (P_RandomChance(chance)) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckTargetRings -// -// Description: Calls a state depending on the ammount of rings currently owned by targeted players. -// -// var1 = if player rings >= var1 call state -// var2 = state number -// -void A_CheckTargetRings(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckTargetRings", actor)) - return; -#endif - - if (!(actor->target) || !(actor->target->player)) - return; - - if (actor->target->player->rings >= locvar1) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckRings -// -// Description: Calls a state depending on the ammount of rings currently owned by all players. -// -// var1 = if player rings >= var1 call state -// var2 = state number -// -void A_CheckRings(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - INT32 i, cntr = 0; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckRings", actor)) - return; -#endif - - for (i = 0; i < MAXPLAYERS; i++) - cntr += players[i].rings; - - if (cntr >= locvar1) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckTotalRings -// -// Description: Calls a state depending on the maximum ammount of rings owned by all players during this try. -// -// var1 = if total player rings >= var1 call state -// var2 = state number -// -void A_CheckTotalRings(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - - INT32 i, cntr = 0; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckTotalRings", actor)) - return; -#endif - - for (i = 0; i < MAXPLAYERS; i++) - cntr += players[i].totalring; - - if (cntr >= locvar1) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckHealth -// -// Description: Calls a state depending on the object's current health. -// -// var1 = if health <= var1 call state -// var2 = state number -// -void A_CheckHealth(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckHealth", actor)) - return; -#endif - - if (actor->health <= locvar1) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckRange -// -// Description: Calls a state if the object's target is in range. -// -// var1: -// lower 16 bits = range -// upper 16 bits = 0 - target, 1 - tracer -// var2 = state number -// -void A_CheckRange(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - fixed_t dist; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckRange", actor)) - return; -#endif - - if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) - return; - - if (!(locvar1 >> 16)) //target - dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); - else //tracer - dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); - - if (dist <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale)) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckHeight -// -// Description: Calls a state if the object and it's target have a height offset <= var1 compared to each other. -// -// var1: -// lower 16 bits = height offset -// upper 16 bits = 0 - target, 1 - tracer -// var2 = state number -// -void A_CheckHeight(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - fixed_t height; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckHeight", actor)) - return; -#endif - - if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) - return; - - if (!(locvar1 >> 16)) // target - height = abs(actor->target->z - actor->z); - else // tracer - height = abs(actor->tracer->z - actor->z); - - if (height <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale)) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckTrueRange -// -// Description: Calls a state if the object's target is in true range. (Checks height, too.) -// -// var1: -// lower 16 bits = range -// upper 16 bits = 0 - target, 1 - tracer -// var2 = state number -// -void A_CheckTrueRange(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - fixed_t height; // vertical range - fixed_t dist; // horizontal range - fixed_t l; // true range -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckTrueRange", actor)) - return; -#endif - - if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) - return; - - if (!(locvar1 >> 16)) // target - { - height = actor->target->z - actor->z; - dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); - - } - else // tracer - { - height = actor->tracer->z - actor->z; - dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); - } - - l = P_AproxDistance(dist, height); - - if (l <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale)) - P_SetMobjState(actor, locvar2); - -} - -// Function: A_CheckThingCount -// -// Description: Calls a state depending on the number of active things in range. -// -// var1: -// lower 16 bits = number of things -// upper 16 bits = thing type -// var2: -// lower 16 bits = state to call -// upper 16 bits = range (if == 0, check whole map) -// -void A_CheckThingCount(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - - const UINT16 loc1lw = (UINT16)(locvar1 & 65535); - const UINT16 loc1up = (UINT16)(locvar1 >> 16); - const UINT16 loc2lw = (UINT16)(locvar2 & 65535); - const UINT16 loc2up = (UINT16)(locvar2 >> 16); - - INT32 count = 0; - thinker_t *th; - mobj_t *mo2; - fixed_t dist = 0; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckThingCount", actor)) - return; -#endif - - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == (mobjtype_t)loc1up) - { - dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y); - - if (loc2up == 0) - count++; - else - { - if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale)) - count++; - } - } - } - - if(loc1lw <= count) - P_SetMobjState(actor, loc2lw); -} - -// Function: A_CheckAmbush -// -// Description: Calls a state if the actor is behind its targeted player. -// -// var1: -// 0 = target -// 1 = tracer -// var2 = state number -// -void A_CheckAmbush(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - angle_t at; // angle target is currently facing - angle_t atp; // actor to target angle - angle_t an; // angle between at and atp - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckAmbush", actor)) - return; -#endif - - if ((!locvar1 && !actor->target) || (locvar1 && !actor->tracer)) - return; - - if (!locvar1) // target - { - at = actor->target->angle; - atp = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); - } - else // tracer - { - at = actor->tracer->angle; - atp = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); - } - - an = atp - at; - - if (an > ANGLE_180) // flip angle if bigger than 180 - an = InvAngle(an); - - if (an < ANGLE_90+ANGLE_22h) // within an angle of 112.5 from each other? - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckCustomValue -// -// Description: Calls a state depending on the object's custom value. -// -// var1 = if custom value >= var1, call state -// var2 = state number -// -void A_CheckCustomValue(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckCustomValue", actor)) - return; -#endif - - if (actor->cusval >= locvar1) - P_SetMobjState(actor, locvar2); -} - -// Function: A_CheckCusValMemo -// -// Description: Calls a state depending on the object's custom memory value. -// -// var1 = if memory value >= var1, call state -// var2 = state number -// -void A_CheckCusValMemo(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckCusValMemo", actor)) - return; -#endif - - if (actor->cvmem >= locvar1) - P_SetMobjState(actor, locvar2); -} - -// Function: A_SetCustomValue -// -// Description: Changes the custom value of an object. -// -// var1 = manipulating value -// var2: -// if var2 == 5, multiply the custom value by var1 -// else if var2 == 4, divide the custom value by var1 -// else if var2 == 3, apply modulo var1 to the custom value -// else if var2 == 2, add var1 to the custom value -// else if var2 == 1, substract var1 from the custom value -// else if var2 == 0, replace the custom value with var1 -// -void A_SetCustomValue(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetCustomValue", actor)) - return; -#endif - - if (cv_debug) - CONS_Printf("Init custom value is %d\n", actor->cusval); - - if (locvar1 == 0 && locvar2 == 4) - return; // DON'T DIVIDE BY ZERO - - // no need for a "temp" value here, just modify the cusval directly - if (locvar2 == 5) // multiply - actor->cusval *= locvar1; - else if (locvar2 == 4) // divide - actor->cusval /= locvar1; - else if (locvar2 == 3) // modulo - actor->cusval %= locvar1; - else if (locvar2 == 2) // add - actor->cusval += locvar1; - else if (locvar2 == 1) // subtract - actor->cusval -= locvar1; - else // replace - actor->cusval = locvar1; - - if(cv_debug) - CONS_Printf("New custom value is %d\n", actor->cusval); -} - -// Function: A_UseCusValMemo -// -// Description: Memorizes or recalls a current custom value. -// -// var1: -// if var1 == 1, manipulate memory value -// else, recall memory value replacing the custom value -// var2: -// if var2 == 5, mem = mem*cv || cv = cv*mem -// else if var2 == 4, mem = mem/cv || cv = cv/mem -// else if var2 == 3, mem = mem%cv || cv = cv%mem -// else if var2 == 2, mem += cv || cv += mem -// else if var2 == 1, mem -= cv || cv -= mem -// else mem = cv || cv = mem -// -void A_UseCusValMemo(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - - INT32 temp = actor->cusval; // value being manipulated - INT32 tempM = actor->cvmem; // value used to manipulate temp with -#ifdef HAVE_BLUA - if (LUA_CallAction("A_UseCusValMemo", actor)) - return; -#endif - - if (locvar1 == 1) // cvmem being changed using cusval - { - temp = actor->cvmem; - tempM = actor->cusval; - } - else // cusval being changed with cvmem - { - temp = actor->cusval; - tempM = actor->cvmem; - } - - if (tempM == 0 && locvar2 == 4) - return; // DON'T DIVIDE BY ZERO - - // now get new value for cusval/cvmem using the other - if (locvar2 == 5) // multiply - temp *= tempM; - else if (locvar2 == 4) // divide - temp /= tempM; - else if (locvar2 == 3) // modulo - temp %= tempM; - else if (locvar2 == 2) // add - temp += tempM; - else if (locvar2 == 1) // subtract - temp -= tempM; - else // replace - temp = tempM; - - // finally, give cusval/cvmem the new value! - if (locvar1 == 1) - actor->cvmem = temp; - else - actor->cusval = temp; -} - -// Function: A_RelayCustomValue -// -// Description: Manipulates the custom value of the object's target/tracer. -// -// var1: -// lower 16 bits: -// if var1 == 0, use own custom value -// else, use var1 value -// upper 16 bits = 0 - target, 1 - tracer -// var2: -// if var2 == 5, multiply the target's custom value by var1 -// else if var2 == 4, divide the target's custom value by var1 -// else if var2 == 3, apply modulo var1 to the target's custom value -// else if var2 == 2, add var1 to the target's custom value -// else if var2 == 1, substract var1 from the target's custom value -// else if var2 == 0, replace the target's custom value with var1 -// -void A_RelayCustomValue(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - - INT32 temp; // reference value - var1 lower 16 bits changes this - INT32 tempT; // target's value - changed to tracer if var1 upper 16 bits set, then modified to become final value -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RelayCustomValue", actor)) - return; -#endif - - if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) - return; - - // reference custom value - if ((locvar1 & 65535) == 0) - temp = actor->cusval; // your own custom value - else - temp = (locvar1 & 65535); // var1 value - - if (!(locvar1 >> 16)) // target's custom value - tempT = actor->target->cusval; - else // tracer's custom value - tempT = actor->tracer->cusval; - - if (temp == 0 && locvar2 == 4) - return; // DON'T DIVIDE BY ZERO - - // now get new cusval using target's and the reference - if (locvar2 == 5) // multiply - tempT *= temp; - else if (locvar2 == 4) // divide - tempT /= temp; - else if (locvar2 == 3) // modulo - tempT %= temp; - else if (locvar2 == 2) // add - tempT += temp; - else if (locvar2 == 1) // subtract - tempT -= temp; - else // replace - tempT = temp; - - // finally, give target/tracer the new cusval! - if (!(locvar1 >> 16)) // target - actor->target->cusval = tempT; - else // tracer - actor->tracer->cusval = tempT; -} - -// Function: A_CusValAction -// -// Description: Calls an action from a reference state applying custom value parameters. -// -// var1 = state # to use action from -// var2: -// if var2 == 5, only replace new action's var2 with memory value -// else if var2 == 4, only replace new action's var1 with memory value -// else if var2 == 3, replace new action's var2 with custom value and var1 with memory value -// else if var2 == 2, replace new action's var1 with custom value and var2 with memory value -// else if var2 == 1, only replace new action's var2 with custom value -// else if var2 == 0, only replace new action's var1 with custom value -// -void A_CusValAction(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CusValAction", actor)) - return; -#endif - - if (locvar2 == 5) - { - var1 = states[locvar1].var1; - var2 = (INT32)actor->cvmem; - } - else if (locvar2 == 4) - { - var1 = (INT32)actor->cvmem; - var2 = states[locvar1].var2; - } - else if (locvar2 == 3) - { - var1 = (INT32)actor->cvmem; - var2 = (INT32)actor->cusval; - } - else if (locvar2 == 2) - { - var1 = (INT32)actor->cusval; - var2 = (INT32)actor->cvmem; - } - else if (locvar2 == 1) - { - var1 = states[locvar1].var1; - var2 = (INT32)actor->cusval; - } - else - { - var1 = (INT32)actor->cusval; - var2 = states[locvar1].var2; - } - -#ifdef HAVE_BLUA - astate = &states[locvar1]; -#endif - states[locvar1].action.acp1(actor); -} - -// Function: A_ForceStop -// -// Description: Actor immediately stops its current movement. -// -// var1: -// if var1 == 0, stop x-y-z-movement -// else, stop x-y-movement only -// var2 = unused -// -void A_ForceStop(mobj_t *actor) -{ - INT32 locvar1 = var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ForceStop", actor)) - return; -#endif - - actor->momx = actor->momy = 0; - if (locvar1 == 0) - actor->momz = 0; -} - -// Function: A_ForceWin -// -// Description: Makes all players win the level. -// -// var1 = unused -// var2 = unused -// -void A_ForceWin(mobj_t *actor) -{ - INT32 i; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ForceWin", actor)) - return; -#else - (void)actor; -#endif - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && ((players[i].mo && players[i].mo->health) - || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) - break; - } - - if (i == MAXPLAYERS) - return; - - for (i = 0; i < MAXPLAYERS; i++) - P_DoPlayerExit(&players[i]); -} - -// Function: A_SpikeRetract -// -// Description: Toggles actor solid flag. -// -// var1: -// if var1 == 0, actor no collide -// else, actor solid -// var2 = unused -// -void A_SpikeRetract(mobj_t *actor) -{ - INT32 locvar1 = var1; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SpikeRetract", actor)) - return; -#endif - - if (actor->flags & MF_NOBLOCKMAP) - return; - - if (locvar1 == 0) - { - actor->flags &= ~MF_SOLID; - actor->flags |= MF_NOCLIPTHING; - } - else - { - actor->flags |= MF_SOLID; - actor->flags &= ~MF_NOCLIPTHING; - } - if (actor->flags & MF_SOLID) - P_CheckPosition(actor, actor->x, actor->y); -} - -// Function: A_InfoState -// -// Description: Set mobj state to one predefined in mobjinfo. -// -// var1: -// if var1 == 0, set actor to spawnstate -// else if var1 == 1, set actor to seestate -// else if var1 == 2, set actor to meleestate -// else if var1 == 3, set actor to missilestate -// else if var1 == 4, set actor to deathstate -// else if var1 == 5, set actor to xdeathstate -// else if var1 == 6, set actor to raisestate -// var2 = unused -// -void A_InfoState(mobj_t *actor) -{ - INT32 locvar1 = var1; - switch (locvar1) - { - case 0: - if (actor->state != &states[actor->info->spawnstate]) - P_SetMobjState(actor, actor->info->spawnstate); - break; - case 1: - if (actor->state != &states[actor->info->seestate]) - P_SetMobjState(actor, actor->info->seestate); - break; - case 2: - if (actor->state != &states[actor->info->meleestate]) - P_SetMobjState(actor, actor->info->meleestate); - break; - case 3: - if (actor->state != &states[actor->info->missilestate]) - P_SetMobjState(actor, actor->info->missilestate); - break; - case 4: - if (actor->state != &states[actor->info->deathstate]) - P_SetMobjState(actor, actor->info->deathstate); - break; - case 5: - if (actor->state != &states[actor->info->xdeathstate]) - P_SetMobjState(actor, actor->info->xdeathstate); - break; - case 6: - if (actor->state != &states[actor->info->raisestate]) - P_SetMobjState(actor, actor->info->raisestate); - break; - default: - break; - } -} - -// Function: A_Repeat -// -// Description: Returns to state var2 until animation has been used var1 times, then continues to nextstate. -// -// var1 = repeat count -// var2 = state to return to if extravalue2 > 0 -// -void A_Repeat(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Repeat", actor)) - return; -#endif - - if (locvar1 && (!actor->extravalue2 || actor->extravalue2 > locvar1)) - actor->extravalue2 = locvar1; - - if (--actor->extravalue2 > 0) - P_SetMobjState(actor, locvar2); -} - -// Function: A_SetScale -// -// Description: Changes the scale of the actor or its target/tracer -// -// var1 = new scale (1*FRACUNIT = 100%) -// var2: -// upper 16 bits: 0 = actor, 1 = target, 2 = tracer -// lower 16 bits: 0 = instant change, 1 = smooth change -// -void A_SetScale(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *target; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SetScale", actor)) - return; -#endif - - if (locvar1 <= 0) - { - if(cv_debug) - CONS_Printf("A_SetScale: Valid scale not specified!\n"); - return; - } - - if ((locvar2>>16) == 1) - target = actor->target; - else if ((locvar2>>16) == 2) - target = actor->tracer; - else // default to yourself! - target = actor; - - if (!target) - { - if(cv_debug) - CONS_Printf("A_SetScale: No target!\n"); - return; - } - - target->destscale = locvar1; // destination scale - if (!(locvar2 & 65535)) - P_SetScale(target, locvar1); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 anyway -} - -// Function: A_RemoteDamage -// -// Description: Damages, kills or even removes either the actor or its target/tracer. Actor acts as the inflictor/source unless harming itself -// -// var1 = Mobj affected: 0 - actor, 1 - target, 2 - tracer -// var2 = Action: 0 - Damage, 1 - Kill, 2 - Remove -// -void A_RemoteDamage(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *target; // we MUST have a target - mobj_t *source = NULL; // on the other hand we don't necessarily need a source -#ifdef HAVE_BLUA - if (LUA_CallAction("A_RemoteDamage", actor)) - return; -#endif - if (locvar1 == 1) - target = actor->target; - else if (locvar1 == 2) - target = actor->tracer; - else // default to yourself! - target = actor; - - if (locvar1 == 1 || locvar1 == 2) - source = actor; - - if (!target) - { - if(cv_debug) - CONS_Printf("A_RemoteDamage: No target!\n"); - return; - } - - if (locvar2 == 1) // Kill mobj! - { - if (target->player) // players die using P_DamageMobj instead for some reason - P_DamageMobj(target, source, source, 1, DMG_INSTAKILL); - else - P_KillMobj(target, source, source, 0); - } - else if (locvar2 == 2) // Remove mobj! - { - if (target->player) //don't remove players! - return; - - P_RemoveMobj(target); - } - else // default: Damage mobj! - P_DamageMobj(target, source, source, 1, 0); -} - -// Function: A_HomingChase -// -// Description: Actor chases directly towards its destination object -// -// var1 = speed multiple -// var2 = destination: 0 = target, 1 = tracer -// -void A_HomingChase(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *dest; - fixed_t dist; - fixed_t speedmul; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_HomingChase", actor)) - return; -#endif - - if (locvar2 == 1) - dest = actor->tracer; - else //default - dest = actor->target; - - if (!dest || !dest->health) - return; - - actor->angle = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y); - - dist = P_AproxDistance(P_AproxDistance(dest->x - actor->x, dest->y - actor->y), dest->z - actor->z); - - if (dist < 1) - dist = 1; - - speedmul = FixedMul(locvar1, actor->scale); - - actor->momx = FixedMul(FixedDiv(dest->x - actor->x, dist), speedmul); - actor->momy = FixedMul(FixedDiv(dest->y - actor->y, dist), speedmul); - actor->momz = FixedMul(FixedDiv(dest->z - actor->z, dist), speedmul); -} - -// Function: A_TrapShot -// -// Description: Fires a missile in a particular direction and angle rather than AT something, Trapgoyle-style! -// -// var1: -// lower 16 bits = object # to fire -// upper 16 bits = front offset -// var2: -// lower 15 bits = vertical angle variable -// 16th bit: -// - 0: use vertical angle variable as vertical angle in degrees -// - 1: mimic P_SpawnXYZMissile -// use z of actor minus z of missile as vertical distance to cover during momz calculation -// use vertical angle variable as horizontal distance to cover during momz calculation -// upper 16 bits = height offset -// -void A_TrapShot(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - boolean oldstyle = (locvar2 & 32768) ? true : false; - mobjtype_t type = (mobjtype_t)(locvar1 & 65535); - mobj_t *missile; - INT16 frontoff = (INT16)(locvar1 >> 16); - INT16 vertoff = (INT16)(locvar2 >> 16); - fixed_t x, y, z; - fixed_t speed; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_TrapShot", actor)) - return; -#endif - - x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); - - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(vertoff*FRACUNIT, actor->scale) - FixedMul(mobjinfo[type].height, actor->scale); - else - z = actor->z + FixedMul(vertoff*FRACUNIT, actor->scale); - - CONS_Debug(DBG_GAMELOGIC, "A_TrapShot: missile no. = %d, front offset = %d, vertical angle = %d, z offset = %d\n", - type, frontoff, (INT16)(locvar2 & 65535), vertoff); - - missile = P_SpawnMobj(x, y, z, type); - - if (actor->eflags & MFE_VERTICALFLIP) - missile->flags2 |= MF2_OBJECTFLIP; - - missile->destscale = actor->scale; - P_SetScale(missile, actor->scale); - - if (missile->info->seesound) - S_StartSound(missile, missile->info->seesound); - - P_SetTarget(&missile->target, actor); - missile->angle = actor->angle; - - speed = FixedMul(missile->info->speed, missile->scale); - - if (oldstyle) - { - missile->momx = FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed); - missile->momy = FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed); - // The below line basically mimics P_SpawnXYZMissile's momz calculation. - missile->momz = (actor->z + ((actor->eflags & MFE_VERTICALFLIP) ? actor->height : 0) - z) / ((fixed_t)(locvar2 & 32767)*FRACUNIT / speed); - P_CheckMissileSpawn(missile); - } - else - { - angle_t vertang = FixedAngle(((INT16)(locvar2 & 32767))*FRACUNIT); - if (actor->eflags & MFE_VERTICALFLIP) - vertang = InvAngle(vertang); // flip firing angle - missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed)); - missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed)); - missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed); - } -} - -// Function: A_VileTarget -// -// Description: Spawns an object directly on the target, and sets this object as the actor's tracer. -// Originally used by Archviles to summon a pillar of hellfire, hence the name. -// -// var1 = mobj to spawn -// var2 = If 0, target only the actor's target. Else, target every player, period. -// -void A_VileTarget(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *fog; - mobjtype_t fogtype; - INT32 i; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_VileTarget", actor)) - return; -#endif - - if (!actor->target) - return; - - A_FaceTarget(actor); - - // Determine object to spawn - if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES) - fogtype = MT_CYBRAKDEMON_TARGET_RETICULE; - else - fogtype = (mobjtype_t)locvar1; - - if (!locvar2) - { - fog = P_SpawnMobj(actor->target->x, - actor->target->y, - actor->target->z + ((actor->target->eflags & MFE_VERTICALFLIP) ? actor->target->height - mobjinfo[fogtype].height : 0), - fogtype); - if (actor->target->eflags & MFE_VERTICALFLIP) - { - fog->eflags |= MFE_VERTICALFLIP; - fog->flags2 |= MF2_OBJECTFLIP; - } - fog->destscale = actor->target->scale; - P_SetScale(fog, fog->destscale); - - P_SetTarget(&actor->tracer, fog); - P_SetTarget(&fog->target, actor); - P_SetTarget(&fog->tracer, actor->target); - A_VileFire(fog); - } - else - { - // Our "Archvile" here is actually Oprah. "YOU GET A TARGET! YOU GET A TARGET! YOU ALL GET A TARGET!" - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - if (!players[i].mo->health) - continue; - - fog = P_SpawnMobj(players[i].mo->x, - players[i].mo->y, - players[i].mo->z + ((players[i].mo->eflags & MFE_VERTICALFLIP) ? players[i].mo->height - mobjinfo[fogtype].height : 0), - fogtype); - if (players[i].mo->eflags & MFE_VERTICALFLIP) - { - fog->eflags |= MFE_VERTICALFLIP; - fog->flags2 |= MF2_OBJECTFLIP; - } - fog->destscale = players[i].mo->scale; - P_SetScale(fog, fog->destscale); - - if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now - P_SetTarget(&actor->tracer, fog); - P_SetTarget(&fog->target, actor); - P_SetTarget(&fog->tracer, players[i].mo); - A_VileFire(fog); - } - } -} - -// Function: A_VileAttack -// -// Description: Instantly hurts the actor's target, if it's in the actor's line of sight. -// Originally used by Archviles to cause explosions where their hellfire pillars were, hence the name. -// -// var1 = sound to play -// var2: -// Lower 16 bits = optional explosion object -// Upper 16 bits = If 0, attack only the actor's target. Else, attack all the players. All of them. -// -void A_VileAttack(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - sfxenum_t soundtoplay; - mobjtype_t explosionType = MT_NULL; - mobj_t *fire; - INT32 i; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_VileAttack", actor)) - return; -#endif - - if (!actor->target) - return; - - A_FaceTarget(actor); - - if (locvar1 <= 0 || locvar1 >= NUMSFX) - soundtoplay = sfx_brakrx; - else - soundtoplay = (sfxenum_t)locvar1; - - if ((locvar2 & 0xFFFF) > 0 && (locvar2 & 0xFFFF) <= NUMMOBJTYPES) - { - explosionType = (mobjtype_t)(locvar2 & 0xFFFF); - } - - if (!(locvar2 & 0xFFFF0000)) { - if (!P_CheckSight(actor, actor->target)) - return; - - S_StartSound(actor, soundtoplay); - P_DamageMobj(actor->target, actor, actor, 1, 0); - //actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it - actor->target->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(actor->target); // How we're doing it - if (explosionType != MT_NULL) - { - P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, explosionType); - } - - // Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway. - fire = actor->tracer; - - if (!fire) - return; - - // move the fire between the vile and the player - //fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); - //fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); - P_TeleportMove(fire, - actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), - actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), - fire->z); - P_RadiusAttack(fire, actor, 70*FRACUNIT, 0); - } - else - { - // Oprahvile strikes again, but this time, she brings HOT PAIN - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - if (!players[i].mo->health) - continue; - - if (!P_CheckSight(actor, players[i].mo)) - continue; - - S_StartSound(actor, soundtoplay); - P_DamageMobj(players[i].mo, actor, actor, 1, 0); - //actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it - players[i].mo->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(players[i].mo); // How we're doing it - if (explosionType != MT_NULL) - { - P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z, explosionType); - } - - // Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway. - // However, it ONLY applies to the actor's target. Nobody else matters! - if (actor->target != players[i].mo) - continue; - - fire = actor->tracer; - - if (!fire) - continue; - - // move the fire between the vile and the player - //fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); - //fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); - P_TeleportMove(fire, - actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), - actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), - fire->z); - P_RadiusAttack(fire, actor, 70*FRACUNIT, 0); - } - } - -} - -// Function: A_VileFire -// -// Description: Kind of like A_CapeChase; keeps this object in front of its tracer, unless its target can't see it. -// Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific). -// Added some functionality to optionally draw a line directly to the enemy doing the targetting. Y'know, to hammer things in a bit. -// -// var1 = sound to play -// var2: -// Lower 16 bits = mobj to spawn (0 doesn't spawn a line at all) -// Upper 16 bits = # to spawn (default is 8) -// -void A_VileFire(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - mobj_t *dest; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_VileFire", actor)) - return; -#endif - - dest = actor->tracer; - if (!dest) - return; - - // don't move it if the vile lost sight - if (!P_CheckSight(actor->target, dest)) - return; - - // keep to same scale and gravity as tracer ALWAYS - actor->destscale = dest->scale; - P_SetScale(actor, actor->destscale); - if (dest->eflags & MFE_VERTICALFLIP) - { - actor->eflags |= MFE_VERTICALFLIP; - actor->flags2 |= MF2_OBJECTFLIP; - } - else - { - actor->eflags &= ~MFE_VERTICALFLIP; - actor->flags2 &= ~MF2_OBJECTFLIP; - } - - P_UnsetThingPosition(actor); - actor->x = dest->x + P_ReturnThrustX(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale)); - actor->y = dest->y + P_ReturnThrustY(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale)); - actor->z = dest->z + ((actor->eflags & MFE_VERTICALFLIP) ? dest->height-actor->height : 0); - P_SetThingPosition(actor); - - // Play sound, if one's specified - if (locvar1 > 0 && locvar1 < NUMSFX) - S_StartSound(actor, (sfxenum_t)locvar1); - - // Now draw the line to the actor's target - if (locvar2 & 0xFFFF) - { - mobjtype_t lineMobj; - UINT16 numLineMobjs; - fixed_t distX; - fixed_t distY; - fixed_t distZ; - UINT16 i; - - lineMobj = (mobjtype_t)(locvar2 & 0xFFFF); - numLineMobjs = (UINT16)(locvar2 >> 16); - if (numLineMobjs == 0) { - numLineMobjs = 8; - } - - // Get distance for each step - distX = (actor->target->x - actor->x) / numLineMobjs; - distY = (actor->target->y - actor->y) / numLineMobjs; - distZ = ((actor->target->z + FixedMul(actor->target->height/2, actor->target->scale)) - (actor->z + FixedMul(actor->height/2, actor->scale))) / numLineMobjs; - - for (i = 1; i <= numLineMobjs; i++) - { - P_SpawnMobj(actor->x + (distX * i), actor->y + (distY * i), actor->z + (distZ * i) + FixedMul(actor->height/2, actor->scale), lineMobj); - } - } -} - -// Function: A_BrakChase -// -// Description: Chase after your target, but speed and attack are tied to health. -// -// Every time this is called, generate a random number from a 1/4 to 3/4 of mobj's spawn health. -// If health is above that value, use missilestate to attack. -// If health is at or below that value, use meleestate to attack (default to missile state if not available). -// -// Likewise, state will linearly speed up as health goes down. -// Upper bound will be the frame's normal length. -// Lower bound defaults to 1 tic (technically 0, but we round up), unless a lower bound is specified in var1. -// -// var1 = lower-bound of frame length, in tics -// var2 = optional sound to play -// -void A_BrakChase(mobj_t *actor) -{ - INT32 delta; - INT32 lowerbound; - INT32 newtics; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BrakChase", actor)) - return; -#endif - - // Set new tics NOW, in case the state changes while we're doing this and we try applying this to the painstate or something silly - if (actor->tics > 1 && locvar1 < actor->tics) // Not much point, otherwise - { - if (locvar1 < 0) - lowerbound = 0; - else - lowerbound = locvar1; - - newtics = (((actor->tics - lowerbound) * actor->health) / actor->info->spawnhealth) + lowerbound; - if (newtics < 1) - newtics = 1; - - actor->tics = newtics; - } - - if (actor->reactiontime) - { - actor->reactiontime--; - if (actor->reactiontime == 0 && actor->type == MT_CYBRAKDEMON) - S_StartSound(0, sfx_bewar1 + P_RandomKey(4)); - } - - // modify target threshold - if (actor->threshold) - { - if (!actor->target || actor->target->health <= 0) - actor->threshold = 0; - else - actor->threshold--; - } - - // turn towards movement direction if not there yet - if (actor->movedir < NUMDIRS) - { - actor->angle &= (7<<29); - delta = actor->angle - (actor->movedir << 29); - - if (delta > 0) - actor->angle -= ANGLE_45; - else if (delta < 0) - actor->angle += ANGLE_45; - } - - if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) - { - // look for a new target - if (P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - P_SetMobjStateNF(actor, actor->info->spawnstate); - return; - } - - // do not attack twice in a row - if (actor->flags2 & MF2_JUSTATTACKED) - { - actor->flags2 &= ~MF2_JUSTATTACKED; - P_NewChaseDir(actor); - return; - } - - // Check if we can attack - if (P_CheckMissileRange(actor) && !actor->movecount) - { - // Check if we should use "melee" attack first. (Yes, this still runs outside of melee range. Quiet, you.) - if (actor->info->meleestate - && actor->health <= P_RandomRange(actor->info->spawnhealth/4, (actor->info->spawnhealth * 3)/4)) // Guaranteed true if <= 1/4 health, guaranteed false if > 3/4 health - { - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - - P_SetMobjState(actor, actor->info->meleestate); - actor->flags2 |= MF2_JUSTATTACKED; - return; - } - // Else, check for missile attack. - else if (actor->info->missilestate) - { - P_SetMobjState(actor, actor->info->missilestate); - actor->flags2 |= MF2_JUSTATTACKED; - return; - } - } - - // possibly choose another target - if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) - && P_LookForPlayers(actor, true, false, 0)) - return; // got a new target - - // chase towards player - if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) - P_NewChaseDir(actor); - - // Optionally play a sound effect - if (locvar2 > 0 && locvar2 < NUMSFX) - S_StartSound(actor, (sfxenum_t)locvar2); - - // make active sound - if (actor->type != MT_CYBRAKDEMON && actor->info->activesound && P_RandomChance(3*FRACUNIT/256)) - { - S_StartSound(actor, actor->info->activesound); - } -} - -// Function: A_BrakFireShot -// -// Description: Shoot an object at your target, offset to match where Brak's gun is. -// Also, sets Brak's reaction time; behaves normally otherwise. -// -// var1 = object # to shoot -// var2 = unused -// -void A_BrakFireShot(mobj_t *actor) -{ - fixed_t x, y, z; - INT32 locvar1 = var1; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BrakFireShot", actor)) - return; -#endif - if (!actor->target) - return; - - A_FaceTarget(actor); - - x = actor->x - + P_ReturnThrustX(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale)) - + P_ReturnThrustX(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale)); - y = actor->y - + P_ReturnThrustY(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale)) - + P_ReturnThrustY(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale)); - if (actor->eflags & MFE_VERTICALFLIP) - z = actor->z + actor->height - FixedMul(144*FRACUNIT, actor->scale); - else - z = actor->z + FixedMul(144*FRACUNIT, actor->scale); - - P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z); - - if (!(actor->flags & MF_BOSS)) - { - if (ultimatemode) - actor->reactiontime = actor->info->reactiontime*TICRATE; - else - actor->reactiontime = actor->info->reactiontime*TICRATE*2; - } -} - -// Function: A_BrakLobShot -// -// Description: Lobs an object at the floor about a third of the way toward your target. -// Implication is it'll bounce the rest of the way. -// (You can also just aim straight at the target, but whatever) -// Formula grabbed from http://en.wikipedia.org/wiki/Trajectory_of_a_projectile#Angle_required_to_hit_coordinate_.28x.2Cy.29 -// -// var1 = object # to lob -// var2: -// Lower 16 bits: height offset to shoot from, from the actor's bottom (none that "airtime" malarky) -// Upper 16 bits: if 0, aim 1/3 of the way. Else, aim directly at target. -// - -void A_BrakLobShot(mobj_t *actor) -{ - fixed_t v; // Velocity to shoot object - fixed_t a1, a2, aToUse; // Velocity squared - fixed_t g; // Gravity - fixed_t x; // Horizontal difference - INT32 x_int; // x! But in integer form! - fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up) - INT32 y_int; // y! But in integer form! - INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper. - fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number. - angle_t theta; // Angle of attack - mobjtype_t typeOfShot; - mobj_t *shot; // Object to shoot - fixed_t newTargetX; // If not aiming directly - fixed_t newTargetY; // If not aiming directly - INT32 locvar1 = var1; - INT32 locvar2 = var2 & 0x0000FFFF; - INT32 aimDirect = var2 & 0xFFFF0000; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_BrakLobShot", actor)) - return; -#endif - - if (!actor->target) - return; // Don't even bother if we've got nothing to aim at. - - // Look up actor's current gravity situation - if (actor->subsector->sector->gravity) - g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); - else - g = gravity; - - // Look up distance between actor and its target - x = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); - if (!aimDirect) - { - // Distance should actually be a third of the way over - x = FixedDiv(x, 3<x + P_ReturnThrustX(actor, actor->angle, x); - newTargetY = actor->y + P_ReturnThrustY(actor, actor->angle, x); - x = P_AproxDistance(newTargetX - actor->x, newTargetY - actor->y); - // Look up height difference between actor and the ground 1/3 of the way to its target - y = P_FloorzAtPos(newTargetX, newTargetY, actor->target->z, actor->target->height) - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale)); - } - else - { - // Look up height difference between actor and its target - y = actor->target->z - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale)); - } - - // Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise. - x_int = x>>FRACBITS; - y_int = y>>FRACBITS; - intHypotenuse = (x_int*x_int) + (y_int*y_int); - fixedHypotenuse = FixedSqrt(intHypotenuse) *256; - - // a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -. - a1 = FixedMul(g,y+fixedHypotenuse); - a2 = FixedMul(g,y-fixedHypotenuse); - - // Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v. - if (a1 < 0 || a2 < 0) - { - if (a1 < 0 && a2 < 0) - { - //Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort! - return; - } - // Just find which one's NOT negative, and use that - aToUse = max(a1,a2); - } - else - { - // Both are positive; use whichever's smaller so it can decay faster - aToUse = min(a1,a2); - } - v = FixedSqrt(aToUse); - // Okay, so we know the velocity. Let's actually find theta. - // We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So: - //theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS]; - theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))]; - - // Okay, complicated math done. Let's fire our object already, sheesh. - A_FaceTarget(actor); - if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES) - typeOfShot = MT_CANNONBALL; - else typeOfShot = (mobjtype_t)locvar1; - shot = P_SpawnMobj(actor->x, actor->y, actor->z + FixedMul(locvar2*FRACUNIT, actor->scale), typeOfShot); - if (shot->info->seesound) - S_StartSound(shot, shot->info->seesound); - P_SetTarget(&shot->target, actor); // where it came from - - shot->angle = actor->angle; - - // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. - shot->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(shot->angle >> ANGLETOFINESHIFT)); - shot->momy = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINESINE(shot->angle >> ANGLETOFINESHIFT)); - // Then the vertical axis. No angle-correction needed here. - shot->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT)); - // I hope that's all that's needed, ugh -} - -// Function: A_NapalmScatter -// -// Description: Scatters a specific number of projectiles around in a circle. -// Intended for use with objects that are affected by gravity; would be kind of silly otherwise. -// -// var1: -// Lower 16 bits: object # to lob (TODO: come up with a default) -// Upper 16 bits: Number to lob (default 8) -// var2: -// Lower 16 bits: distance to toss them (No default - 0 does just that - but negatives will revert to 128) -// Upper 16 bits: airtime in tics (default 16) -// -void A_NapalmScatter(mobj_t *actor) -{ - mobjtype_t typeOfShot = var1 & 0x0000FFFF; // Type - INT32 numToShoot = (var1 & 0xFFFF0000) >> 16; // How many - fixed_t distance = (var2 & 0x0000FFFF) << FRACBITS; // How far - fixed_t airtime = var2 & 0xFFFF0000; // How long until impact (assuming no obstacles) - fixed_t vx; // Horizontal momentum - fixed_t vy; // Vertical momentum - fixed_t g; // Gravity - INT32 i; // for-loop cursor - mobj_t *mo; // each and every spawned napalm burst - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_NapalmScatter", actor)) - return; -#endif - - // Some quick sanity-checking - if (typeOfShot >= NUMMOBJTYPES) // I'd add a <0 check, too, but 0x0000FFFF isn't negative in this case - typeOfShot = MT_NULL; - if (numToShoot <= 0) // Presumably you forgot to set var1 up; else, why are you calling this to shoot nothing? - numToShoot = 8; - else if (numToShoot > 8192) // If you seriously need this many objects spawned, stop and ask yourself "Why am I doing this?" - numToShoot = 8192; - if (distance < 0) // Presumably you thought this was an unsigned integer, you naive fool - distance = 32767<subsector->sector->gravity) - g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); - else - g = gravity; - - // vy = (g*(airtime-1))/2 - vy = FixedMul(g,(airtime-(1<>1; - // vx = distance/airtime - vx = FixedDiv(distance, airtime); - - for (i = 0; ix, actor->y, actor->z, typeOfShot); - P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot - - mo->angle = fa << ANGLETOFINESHIFT; - mo->momx = FixedMul(FINECOSINE(fa),vx); - mo->momy = FixedMul(FINESINE(fa),vx); - mo->momz = vy; - } -} - -// Function: A_SpawnFreshCopy -// -// Description: Spawns a copy of the mobj. x, y, z, angle, scale, target and tracer carry over; everything else starts anew. -// Mostly writing this because I want to do multiple actions to pass these along in a single frame instead of several. -// -// var1 = unused -// var2 = unused -// -void A_SpawnFreshCopy(mobj_t *actor) -{ - mobj_t *newObject; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SpawnFreshCopy", actor)) - return; -#endif - - newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); - newObject->flags2 = actor->flags2 & MF2_AMBUSH; - newObject->angle = actor->angle; - newObject->color = actor->color; - P_SetTarget(&newObject->target, actor->target); - P_SetTarget(&newObject->tracer, actor->tracer); - - if (newObject->info->seesound) - S_StartSound(newObject, newObject->info->seesound); -} - -// Internal Flicky spawning function. -mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers) -{ - mobj_t *flicky; - - if (!flickytype) - { - if (!mapheaderinfo[gamemap-1] || !mapheaderinfo[gamemap-1]->numFlickies) // No mapheader, no shoes, no service. - return NULL; - else - { - INT32 prandom = P_RandomKey(mapheaderinfo[gamemap-1]->numFlickies); - flickytype = mapheaderinfo[gamemap-1]->flickies[prandom]; - } - } - - flicky = P_SpawnMobjFromMobj(actor, 0, 0, 0, flickytype); - flicky->angle = actor->angle; - - if (flickytype == MT_SEED) - flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2; - - if (actor->eflags & MFE_UNDERWATER) - momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT)); - - P_SetObjectMomZ(flicky, momz, false); - flicky->movedir = (P_RandomChance(FRACUNIT/2) ? -1 : 1); - flicky->fuse = P_RandomRange(595, 700); // originally 300, 350 - flicky->threshold = 0; - - if (lookforplayers) - P_LookForPlayers(flicky, true, false, 0); - - return flicky; -} - -// Function: A_FlickySpawn -// -// Description: Flicky spawning function. -// -// var1: -// lower 16 bits: if 0, spawns random flicky based on level header. Else, spawns the designated thing type. -// upper 16 bits: if 0, no sound is played. Else, A_Scream is called. -// var2 = upwards thrust for spawned flicky. If zero, default value is provided. -// -void A_FlickySpawn(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickySpawn", actor)) - return; -#endif - - if (locvar1 >> 16) { - A_Scream(actor); // A shortcut for the truly lazy. - locvar1 &= 65535; - } - - P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true); -} - -// Internal Flicky bubbling function. -void P_InternalFlickyBubble(mobj_t *actor) -{ - if (actor->eflags & MFE_UNDERWATER) - { - mobj_t *overlay; - - if (!((actor->z + 3*actor->height/2) < actor->watertop) || !mobjinfo[actor->type].raisestate || actor->tracer) - return; - - overlay = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY); - P_SetMobjStateNF(overlay, mobjinfo[actor->type].raisestate); - P_SetTarget(&actor->tracer, overlay); - P_SetTarget(&overlay->target, actor); - return; - } - - if (!actor->tracer || P_MobjWasRemoved(actor->tracer)) - return; - - P_RemoveMobj(actor->tracer); - P_SetTarget(&actor->tracer, NULL); -} - -// Function: A_FlickyAim -// -// Description: Flicky aiming function. -// -// var1 = how far around the target (in angle constants) the flicky should look -// var2 = distance from target to aim for -// -void A_FlickyAim(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - boolean flickyhitwall = false; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyAim", actor)) - return; -#endif - - if (actor->momx == actor->momy && actor->momy == 0) - flickyhitwall = true; - - P_InternalFlickyBubble(actor); - P_InstaThrust(actor, 0, 0); - - if (!actor->target) - { - P_LookForPlayers(actor, true, false, 0); - actor->angle = P_RandomKey(36)*ANG10; - return; - } - - if (actor->fuse > 2*TICRATE) - { - angle_t posvar; - fixed_t chasevar, chasex, chasey; - - if (flickyhitwall) - actor->movedir *= -1; - - posvar = ((R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + actor->movedir*locvar1) >> ANGLETOFINESHIFT) & FINEMASK; - chasevar = FixedSqrt(max(FRACUNIT, P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y) - locvar2)) + locvar2; - - chasex = actor->target->x + FixedMul(FINECOSINE(posvar), chasevar); - chasey = actor->target->y + FixedMul(FINESINE(posvar), chasevar); - - if (P_AproxDistance(chasex - actor->x, chasey - actor->y)) - actor->angle = R_PointToAngle2(actor->x, actor->y, chasex, chasey); - } - else if (flickyhitwall) - { - actor->angle += ANGLE_180; - actor->threshold = 0; - } -} - -//Internal Flicky flying function. Also usuable as an underwater swim thrust. -void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez) -{ - angle_t vertangle; - - flyspeed = FixedMul(flyspeed, actor->scale); - actor->flags |= MF_NOGRAVITY; - - var1 = ANG30; - var2 = 32*FRACUNIT; - A_FlickyAim(actor); - - chasez *= 8; - if (!actor->target || !(actor->fuse > 2*TICRATE)) - chasez += ((actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz - 24*FRACUNIT : actor->floorz + 24*FRACUNIT); - else - { - fixed_t add = actor->target->z + (actor->target->height - actor->height)/2; - if (add > (actor->ceilingz - 24*actor->scale - actor->height)) - add = actor->ceilingz - 24*actor->scale - actor->height; - else if (add < (actor->floorz + 24*actor->scale)) - add = actor->floorz + 24*actor->scale; - chasez += add; - } - - if (!targetdist) - targetdist = 16*FRACUNIT; //Default! - - if (actor->target && abs(chasez - actor->z) > targetdist) - targetdist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); - - vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK; - P_InstaThrust(actor, actor->angle, FixedMul(FINECOSINE(vertangle), flyspeed)); - actor->momz = FixedMul(FINESINE(vertangle), flyspeed); -} - -// Function: A_FlickyFly -// -// Description: Flicky flying function. -// -// var1 = how fast to fly -// var2 = how far ahead the target should be considered -// -void A_FlickyFly(mobj_t *actor) -{ - // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyFly", actor)) - return; -#endif - P_InternalFlickyFly(actor, var1, var2, - FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK) - ); -} - -// Function: A_FlickySoar -// -// Description: Flicky soaring function - specific to puffin. -// -// var1 = how fast to fly -// var2 = how far ahead the target should be considered -// -void A_FlickySoar(mobj_t *actor) -{ - // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickySoar", actor)) - return; -#endif - P_InternalFlickyFly(actor, var1, var2, - 2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK))) - ); - - if (P_MobjFlip(actor)*actor->momz > 0 && actor->frame == 1 && actor->sprite == SPR_FL10) - actor->frame = 3; -} - -//Function: A_FlickyCoast -// -// Description: Flicky swim-coasting function. -// -// var1 = speed to change state upon reaching -// var2 = state to change to upon slowing down -// the spawnstate of the mobj = state to change to when above water -// -void A_FlickyCoast(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyCoast", actor)) - return; -#endif - if (actor->eflags & MFE_UNDERWATER) - { - actor->momx = (11*actor->momx)/12; - actor->momy = (11*actor->momy)/12; - actor->momz = (11*actor->momz)/12; - - if (P_AproxDistance(P_AproxDistance(actor->momx, actor->momy), actor->momz) < locvar1) - P_SetMobjState(actor, locvar2); - - return; - } - - actor->flags &= ~MF_NOGRAVITY; - P_SetMobjState(actor, mobjinfo[actor->type].spawnstate); -} - -// Internal Flicky hopping function. -void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle) -{ - if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) - || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz))) - { - if (momz) - { - if (actor->eflags & MFE_UNDERWATER) - momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT)); - P_SetObjectMomZ(actor, momz, false); - } - P_InstaThrust(actor, angle, FixedMul(momh, actor->scale)); - } -} - -// Function: A_FlickyHop -// -// Description: Flicky hopping function. -// -// var1 = vertical thrust -// var2 = horizontal thrust -// -void A_FlickyHop(mobj_t *actor) -{ - // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyHop instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyHop", actor)) - return; -#endif - P_InternalFlickyHop(actor, var1, var2, actor->angle); -} - -// Function: A_FlickyFlounder -// -// Description: Flicky floundering function. -// -// var1 = intended vertical thrust -// var2 = intended horizontal thrust -// -void A_FlickyFlounder(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - angle_t hopangle; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyFlounder", actor)) - return; -#endif - locvar1 *= (P_RandomKey(2) + 1); - locvar2 *= (P_RandomKey(2) + 1); - hopangle = (actor->angle + (P_RandomKey(9) - 4)*ANG2); - P_InternalFlickyHop(actor, locvar1, locvar2, hopangle); -} - -// Function: A_FlickyCheck -// -// Description: Flicky airtime check function. -// -// var1 = state to change to upon touching the floor -// var2 = state to change to upon falling -// the meleestate of the mobj = state to change to when underwater -// -void A_FlickyCheck(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyCheck", actor)) - return; -#endif - if (locvar2 && P_MobjFlip(actor)*actor->momz < 1) - P_SetMobjState(actor, locvar2); - else if (locvar1 && ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) - || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz))) - P_SetMobjState(actor, locvar1); - else if (mobjinfo[actor->type].meleestate && (actor->eflags & MFE_UNDERWATER)) - P_SetMobjState(actor, mobjinfo[actor->type].meleestate); - P_InternalFlickyBubble(actor); -} - -// Function: A_FlickyHeightCheck -// -// Description: Flicky height check function. -// -// var1 = state to change to when falling below height relative to target -// var2 = height relative to target to change state at -// -void A_FlickyHeightCheck(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyHeightCheck", actor)) - return; -#endif - if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1 - && ((P_MobjFlip(actor)*((actor->z + actor->height/2) - (actor->target->z + actor->target->height/2)) < locvar2) - || (actor->z - actor->height < actor->floorz) || (actor->z + 2*actor->height > actor->ceilingz))) - P_SetMobjState(actor, locvar1); - P_InternalFlickyBubble(actor); -} - -// Function: A_FlickyFlutter -// -// Description: Flicky fluttering function - specific to chicken. -// -// var1 = state to change to upon touching the floor -// var2 = state to change to upon falling -// the meleestate of the mobj = state to change to when underwater -// -void A_FlickyFlutter(mobj_t *actor) -{ - // We're not setting up locvars here - it passes var1 and var2 through to A_FlickyCheck instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlickyFlutter", actor)) - return; -#endif - A_FlickyCheck(actor); - - var1 = ANG30; - var2 = 32*FRACUNIT; - A_FlickyAim(actor); - - P_InstaThrust(actor, actor->angle, 2*actor->scale); - if (P_MobjFlip(actor)*actor->momz < -FRACUNIT/2) - actor->momz = -P_MobjFlip(actor)*actor->scale/2; -} - -#undef FLICKYHITWALL - -// Function: A_FlameParticle -// -// Description: Creates the mobj's painchance at a random position around the object's radius. -// -// var1 = unused -// var2 = unused -// -void A_FlameParticle(mobj_t *actor) -{ - mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance); - fixed_t rad, hei; - mobj_t *particle; - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_FlameParticle", actor)) - return; -#endif - - if (!type) - return; - - rad = actor->radius>>FRACBITS; - hei = actor->height>>FRACBITS; - particle = P_SpawnMobjFromMobj(actor, - P_RandomRange(rad, -rad)<momx = actor->momy = actor->momz = 0; - - fade = P_SpawnGhostMobj(actor); - fade->frame = actor->frame; - - if (!(locvar1 & 2)) - { - fade->fuse = 15; - fade->flags2 |= MF2_BOSSNOTRAP; - } - else - fade->fuse = 20; - - if (!(locvar1 & 4)) - P_SetTarget(&actor->tracer, fade); -} - -// Function: A_Boss5Jump -// -// Description: Makes an object jump in an arc to land on their tracer precicely. -// Adapted from A_BrakLobShot, see there for explanation. -// -// var1 = unused -// var2 = unused -// -void A_Boss5Jump(mobj_t *actor) -{ - fixed_t v; // Velocity to jump at - fixed_t a1, a2, aToUse; // Velocity squared - fixed_t g; // Gravity - fixed_t x; // Horizontal difference - INT32 x_int; // x! But in integer form! - fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up) - INT32 y_int; // y! But in integer form! - INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper. - fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number. - angle_t theta; // Angle of attack - // INT32 locvar1 = var1; - // INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_Boss5Jump", actor)) - return; -#endif - - if (!actor->tracer) - return; // Don't even bother if we've got nothing to aim at. - - // Look up actor's current gravity situation - if (actor->subsector->sector->gravity) - g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); - else - g = gravity; - - // Look up distance between actor and its tracer - x = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); - // Look up height difference between actor and its tracer - y = actor->tracer->z - actor->z; - - // Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise. - x_int = x>>FRACBITS; - y_int = y>>FRACBITS; - intHypotenuse = (x_int*x_int) + (y_int*y_int); - fixedHypotenuse = FixedSqrt(intHypotenuse) *256; - - // a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -. - a1 = FixedMul(g,y+fixedHypotenuse); - a2 = FixedMul(g,y-fixedHypotenuse); - - // Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v. - if (a1 < 0 || a2 < 0) - { - if (a1 < 0 && a2 < 0) - { - //Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort! - return; - } - // Just find which one's NOT negative, and use that - aToUse = max(a1,a2); - } - else - { - // Both are positive; use whichever's smaller so it can decay faster - aToUse = min(a1,a2); - } - v = FixedSqrt(aToUse); - // Okay, so we know the velocity. Let's actually find theta. - // We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So: - //theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS]; - theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))]; - - // Okay, complicated math done. Let's make this object jump already. - A_FaceTracer(actor); - - if (actor->eflags & MFE_VERTICALFLIP) - actor->z--; - else - actor->z++; - - // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. - fixedHypotenuse = FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)); // variable reuse - actor->momx = FixedMul(fixedHypotenuse, FINECOSINE(actor->angle >> ANGLETOFINESHIFT)); - actor->momy = FixedMul(fixedHypotenuse, FINESINE(actor->angle >> ANGLETOFINESHIFT)); - // Then the vertical axis. No angle-correction needed here. - actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT)); - // I hope that's all that's needed, ugh -} - -// Function: A_LightBeamReset -// Description: Resets momentum and position for DSZ's projecting light beams -// -// var1 = unused -// var2 = unused -// -void A_LightBeamReset(mobj_t *actor) -{ - // INT32 locvar1 = var1; - // INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_LightBeamReset", actor)) - return; -#endif - - P_SetScale(actor, FRACUNIT + P_SignedRandom()*FRACUNIT/256); - actor->destscale = actor->scale; - - if (!actor->spawnpoint) - return; // this can't work properly welp - - actor->momx = P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; - actor->momy = P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; - actor->momz = P_SignedRandom()*FRACUNIT/128; - - P_UnsetThingPosition(actor); - actor->x = actor->spawnpoint->x*FRACUNIT + P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; - actor->y = actor->spawnpoint->y*FRACUNIT + P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; - actor->z = actor->spawnpoint->z*FRACUNIT + P_SignedRandom()*FRACUNIT/2; - P_SetThingPosition(actor); -} - -// Function: A_MineExplode -// Description: Handles the explosion of a DSZ mine. -// -// var1 = unused -// var2 = unused -// -void A_MineExplode(mobj_t *actor) -{ - // INT32 locvar1 = var1; - // INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MineExplode", actor)) - return; -#endif - - A_Scream(actor); - actor->flags = MF_NOGRAVITY|MF_NOCLIP; - - quake.epicenter = NULL; - quake.radius = 512*FRACUNIT; - quake.intensity = 8*FRACUNIT; - quake.time = TICRATE/3; - - P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT, DMG_CANHURTSELF); - P_MobjCheckWater(actor); - - { -#define dist 64 - UINT8 i; - mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE); - S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e)); - P_SpawnMobj(actor->x, actor->y, actor->z, type); - for (i = 0; i < 16; i++) - { - mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT, - actor->y+P_RandomRange(-dist, dist)*FRACUNIT, - actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT, - type); - fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z; - fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx)); - b->momx = FixedDiv(dx, dm)*3; - b->momy = FixedDiv(dy, dm)*3; - b->momz = FixedDiv(dz, dm)*3; - if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop)) - b->flags &= ~MF_NOGRAVITY; - } -#undef dist - - if (actor->watertop != INT32_MAX) - P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH); - } -} - -// Function: A_MineRange -// Description: If the target gets too close, change the state to meleestate. -// -// var1 = Distance to alert at -// var2 = unused -// -void A_MineRange(mobj_t *actor) -{ - fixed_t dm; - INT32 locvar1 = var1; - // INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MineRange", actor)) - return; -#endif - - if (!actor->target) - return; - - dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x)); - if ((dm>>FRACBITS) < locvar1) - P_SetMobjState(actor, actor->info->meleestate); -} - -// Function: A_ConnectToGround -// Description: Create a palm tree trunk/mine chain. -// -// var1 = Object type to connect to ground -// var2 = Object type to place on ground -// -void A_ConnectToGround(mobj_t *actor) -{ - mobj_t *work; - fixed_t workz; - fixed_t workh; - INT8 dir; - angle_t ang; - INT32 locvar1 = var1; - INT32 locvar2 = var2; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ConnectToGround", actor)) - return; -#endif - - P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); - - if (actor->flags2 & MF2_OBJECTFLIP) - { - workz = actor->ceilingz - (actor->z + actor->height); - dir = -1; - } - else - { - workz = actor->floorz - actor->z; - dir = 1; - } - - if (locvar2) - { - if (actor->flags2 & MF2_OBJECTFLIP) - workz -= FixedMul(mobjinfo[locvar2].height, actor->scale); - work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2); - } - - if (!locvar1) - return; - - workh = FixedMul(mobjinfo[locvar1].height, actor->scale); - - if (actor->flags2 & MF2_OBJECTFLIP) - workz -= workh; - - ang = actor->angle + ANGLE_45; - while (dir*workz < 0) - { - work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1); - if (work) - work->angle = ang; - ang += ANGLE_90; - workz += dir*workh; - } - - if (workz != 0) - actor->z += workz; -} - -// Function: A_SpawnParticleRelative -// -// Description: Spawns a particle effect relative to the location of the actor -// -// var1: -// var1 >> 16 = x -// var1 & 65535 = y -// var2: -// var2 >> 16 = z -// var2 & 65535 = state -// -void A_SpawnParticleRelative(mobj_t *actor) -{ - INT16 x, y, z; // Want to be sure we can use negative values - statenum_t state; - mobj_t *mo; - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_SpawnParticleRelative", actor)) - return; -#endif - - CONS_Debug(DBG_GAMELOGIC, "A_SpawnParticleRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); - - x = (INT16)(locvar1>>16); - y = (INT16)(locvar1&65535); - z = (INT16)(locvar2>>16); - state = (statenum_t)(locvar2&65535); - - // Spawn objects correctly in reverse gravity. - // NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame - mo = P_SpawnMobj(actor->x + FixedMul(x<scale), - actor->y + FixedMul(y<scale), - (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), MT_PARTICLE); - - // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn - mo->angle = actor->angle; - - if (actor->eflags & MFE_VERTICALFLIP) - mo->flags2 |= MF2_OBJECTFLIP; - - P_SetMobjState(mo, state); -} - -// Function: A_MultiShotDist -// -// Description: Spawns multiple shots based on player proximity -// -// var1 = same as A_MultiShot -// var2 = same as A_MultiShot -// -void A_MultiShotDist(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_MultiShotDist", actor)) - return; -#endif - - { - UINT8 i; - // Quick! Look through players! - // Don't spawn dust unless a player is relatively close by (var1). - for (i = 0; i < MAXPLAYERS; ++i) - if (playeringame[i] && players[i].mo - && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (1600<> 16 = mobjtype of child -// var2 & 65535 = vertical momentum -// var2: -// var2 >> 16 = forward offset -// var2 & 65535 = vertical offset -// -void A_WhoCaresIfYourSonIsABee(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; - fixed_t foffsetx; - fixed_t foffsety; - mobj_t *son; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_WhoCaresIfYourSonIsABee", actor)) - return; -#endif - - A_FaceTarget(actor); - - if (actor->extravalue1) - actor->extravalue1--; - - if (actor->info->attacksound) - S_StartSound(actor, actor->info->attacksound); - - foffsetx = P_ReturnThrustX(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); - foffsety = P_ReturnThrustY(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); - - if (!(son = P_SpawnMobjFromMobj(actor, foffsetx, foffsety, (locvar2&65535)*FRACUNIT, (mobjtype_t)(locvar1 >> 16)))) - return; - - P_SetObjectMomZ(son, (locvar1 & 65535)<tracer, actor); - P_SetTarget(&son->target, actor->target); -} - -// Function: A_ParentTriesToSleep -// -// Description: If extravalue1 is less than or equal to var1, go to var2. -// -// var1 = state to go to when extravalue1 -// var2 = unused -// -void A_ParentTriesToSleep(mobj_t *actor) -{ - INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ParentTriesToSleep", actor)) - return; -#endif - - if (actor->extravalue1) - { - if (actor->info->seesound) - S_StartSound(actor, actor->info->seesound); - actor->reactiontime = 0; - P_SetMobjState(actor, locvar1); - } - else if (!actor->reactiontime) - { - actor->reactiontime = 1; - if (actor->info->activesound) // more like INactivesound doy hoy hoy - S_StartSound(actor, actor->info->activesound); - } -} - - -// Function: A_CryingToMomma -// -// Description: If you're a child, let your parent know something's happened to you through extravalue1. Also, prepare to die. -// -// var1 = unused -// var2 = unused -// -void A_CryingToMomma(mobj_t *actor) -{ - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CryingToMomma", actor)) - return; -#endif - - if (actor->tracer) - actor->tracer->extravalue1++; - - actor->momx = actor->momy = actor->momz = 0; - - P_UnsetThingPosition(actor); - if (sector_list) - { - P_DelSeclist(sector_list); - sector_list = NULL; - } - actor->flags = MF_NOBLOCKMAP|MF_NOCLIPTHING; - P_SetThingPosition(actor); -} - -// Function: A_CheckFlags2 -// -// Description: If actor->flags2 & var1, goto var2. -// -// var1 = mask -// var2 = state to go -// -void A_CheckFlags2(mobj_t *actor) -{ - INT32 locvar1 = var1; - INT32 locvar2 = var2; -#ifdef HAVE_BLUA - if (LUA_CallAction("A_CheckFlags2", actor)) - return; -#endif - - if (actor->flags2 & locvar1) - P_SetMobjState(actor, (statenum_t)locvar2); -} +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2016 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file p_enemy.c +/// \brief Enemy thinking, AI +/// Action Pointer Functions that are associated with states/frames + +#include "doomdef.h" +#include "g_game.h" +#include "p_local.h" +#include "r_main.h" +#include "r_state.h" +#include "s_sound.h" +#include "m_random.h" +#include "m_misc.h" +#include "r_things.h" +#include "i_video.h" +#include "lua_hook.h" + +#ifdef HW3SOUND +#include "hardware/hw3sound.h" +#endif + +#ifdef HAVE_BLUA +boolean LUA_CallAction(const char *action, mobj_t *actor); +#endif + +player_t *stplyr; +INT32 var1; +INT32 var2; + +// +// P_NewChaseDir related LUT. +// +static dirtype_t opposite[] = +{ + DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, + DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR +}; + +static dirtype_t diags[] = +{ + DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST +}; + +//Real Prototypes to A_* +void A_Fall(mobj_t *actor); +void A_Look(mobj_t *actor); +void A_Chase(mobj_t *actor); +void A_FaceStabChase(mobj_t *actor); +void A_FaceStabRev(mobj_t *actor); +void A_FaceStabHurl(mobj_t *actor); +void A_FaceStabMiss(mobj_t *actor); +void A_StatueBurst(mobj_t *actor); +void A_JetJawRoam(mobj_t *actor); +void A_JetJawChomp(mobj_t *actor); +void A_PointyThink(mobj_t *actor); +void A_CheckBuddy(mobj_t *actor); +void A_HoodThink(mobj_t *actor); +void A_ArrowCheck(mobj_t *actor); +void A_SnailerThink(mobj_t *actor); +void A_SharpChase(mobj_t *actor); +void A_SharpSpin(mobj_t *actor); +void A_SharpDecel(mobj_t *actor); +void A_CrushstaceanWalk(mobj_t *actor); +void A_CrushstaceanPunch(mobj_t *actor); +void A_CrushclawAim(mobj_t *actor); +void A_CrushclawLaunch(mobj_t *actor); +void A_VultureVtol(mobj_t *actor); +void A_VultureCheck(mobj_t *actor); +void A_SkimChase(mobj_t *actor); +void A_FaceTarget(mobj_t *actor); +void A_FaceTracer(mobj_t *actor); +void A_LobShot(mobj_t *actor); +void A_FireShot(mobj_t *actor); +void A_SuperFireShot(mobj_t *actor); +void A_BossFireShot(mobj_t *actor); +void A_Boss7FireMissiles(mobj_t *actor); +void A_Boss1Laser(mobj_t *actor); +void A_FocusTarget(mobj_t *actor); +void A_Boss4Reverse(mobj_t *actor); +void A_Boss4SpeedUp(mobj_t *actor); +void A_Boss4Raise(mobj_t *actor); +void A_SkullAttack(mobj_t *actor); +void A_BossZoom(mobj_t *actor); +void A_BossScream(mobj_t *actor); +void A_Scream(mobj_t *actor); +void A_Pain(mobj_t *actor); +void A_1upThinker(mobj_t *actor); +void A_MonitorPop(mobj_t *actor); +void A_GoldMonitorPop(mobj_t *actor); +void A_GoldMonitorRestore(mobj_t *actor); +void A_GoldMonitorSparkle(mobj_t *actor); +void A_Explode(mobj_t *actor); +void A_BossDeath(mobj_t *actor); +void A_CustomPower(mobj_t *actor); +void A_GiveWeapon(mobj_t *actor); +void A_RingBox(mobj_t *actor); +void A_Invincibility(mobj_t *actor); +void A_SuperSneakers(mobj_t *actor); +void A_AwardScore(mobj_t *actor); +void A_ExtraLife(mobj_t *actor); +void A_GiveShield(mobj_t *actor); +void A_GravityBox(mobj_t *actor); +void A_ScoreRise(mobj_t *actor); +void A_ParticleSpawn(mobj_t *actor); +void A_BunnyHop(mobj_t *actor); +void A_BubbleSpawn(mobj_t *actor); +void A_FanBubbleSpawn(mobj_t *actor); +void A_BubbleRise(mobj_t *actor); +void A_BubbleCheck(mobj_t *actor); +void A_AttractChase(mobj_t *actor); +void A_DropMine(mobj_t *actor); +void A_FishJump(mobj_t *actor); +void A_ThrownRing(mobj_t *actor); +void A_SetSolidSteam(mobj_t *actor); +void A_UnsetSolidSteam(mobj_t *actor); +void A_SignPlayer(mobj_t *actor); +void A_OverlayThink(mobj_t *actor); +void A_JetChase(mobj_t *actor); +void A_JetbThink(mobj_t *actor); +void A_JetgShoot(mobj_t *actor); +void A_JetgThink(mobj_t *actor); +void A_ShootBullet(mobj_t *actor); +void A_MinusDigging(mobj_t *actor); +void A_MinusPopup(mobj_t *actor); +void A_MinusCheck(mobj_t *actor); +void A_ChickenCheck(mobj_t *actor); +void A_MouseThink(mobj_t *actor); +void A_DetonChase(mobj_t *actor); +void A_CapeChase(mobj_t *actor); +void A_RotateSpikeBall(mobj_t *actor); +void A_SlingAppear(mobj_t *actor); +void A_UnidusBall(mobj_t *actor); +void A_RockSpawn(mobj_t *actor); +void A_SetFuse(mobj_t *actor); +void A_CrawlaCommanderThink(mobj_t *actor); +void A_RingExplode(mobj_t *actor); +void A_OldRingExplode(mobj_t *actor); +void A_MixUp(mobj_t *actor); +void A_RecyclePowers(mobj_t *actor); +void A_Boss2TakeDamage(mobj_t *actor); +void A_Boss7Chase(mobj_t *actor); +void A_GoopSplat(mobj_t *actor); +void A_Boss2PogoSFX(mobj_t *actor); +void A_Boss2PogoTarget(mobj_t *actor); +void A_EggmanBox(mobj_t *actor); +void A_TurretFire(mobj_t *actor); +void A_SuperTurretFire(mobj_t *actor); +void A_TurretStop(mobj_t *actor); +void A_SparkFollow(mobj_t *actor); +void A_BuzzFly(mobj_t *actor); +void A_GuardChase(mobj_t *actor); +void A_EggShield(mobj_t *actor); +void A_SetReactionTime(mobj_t *actor); +void A_Boss1Spikeballs(mobj_t *actor); +void A_Boss3TakeDamage(mobj_t *actor); +void A_Boss3Path(mobj_t *actor); +void A_LinedefExecute(mobj_t *actor); +void A_PlaySeeSound(mobj_t *actor); +void A_PlayAttackSound(mobj_t *actor); +void A_PlayActiveSound(mobj_t *actor); +void A_SmokeTrailer(mobj_t *actor); +void A_SpawnObjectAbsolute(mobj_t *actor); +void A_SpawnObjectRelative(mobj_t *actor); +void A_ChangeAngleRelative(mobj_t *actor); +void A_ChangeAngleAbsolute(mobj_t *actor); +void A_PlaySound(mobj_t *actor); +void A_FindTarget(mobj_t *actor); +void A_FindTracer(mobj_t *actor); +void A_SetTics(mobj_t *actor); +void A_SetRandomTics(mobj_t *actor); +void A_ChangeColorRelative(mobj_t *actor); +void A_ChangeColorAbsolute(mobj_t *actor); +void A_MoveRelative(mobj_t *actor); +void A_MoveAbsolute(mobj_t *actor); +void A_Thrust(mobj_t *actor); +void A_ZThrust(mobj_t *actor); +void A_SetTargetsTarget(mobj_t *actor); +void A_SetObjectFlags(mobj_t *actor); +void A_SetObjectFlags2(mobj_t *actor); +void A_RandomState(mobj_t *actor); +void A_RandomStateRange(mobj_t *actor); +void A_DualAction(mobj_t *actor); +void A_RemoteAction(mobj_t *actor); +void A_ToggleFlameJet(mobj_t *actor); +void A_OrbitNights(mobj_t *actor); +void A_GhostMe(mobj_t *actor); +void A_SetObjectState(mobj_t *actor); +void A_SetObjectTypeState(mobj_t *actor); +void A_KnockBack(mobj_t *actor); +void A_PushAway(mobj_t *actor); +void A_RingDrain(mobj_t *actor); +void A_SplitShot(mobj_t *actor); +void A_MissileSplit(mobj_t *actor); +void A_MultiShot(mobj_t *actor); +void A_InstaLoop(mobj_t *actor); +void A_Custom3DRotate(mobj_t *actor); +void A_SearchForPlayers(mobj_t *actor); +void A_CheckRandom(mobj_t *actor); +void A_CheckTargetRings(mobj_t *actor); +void A_CheckRings(mobj_t *actor); +void A_CheckTotalRings(mobj_t *actor); +void A_CheckHealth(mobj_t *actor); +void A_CheckRange(mobj_t *actor); +void A_CheckHeight(mobj_t *actor); +void A_CheckTrueRange(mobj_t *actor); +void A_CheckThingCount(mobj_t *actor); +void A_CheckAmbush(mobj_t *actor); +void A_CheckCustomValue(mobj_t *actor); +void A_CheckCusValMemo(mobj_t *actor); +void A_SetCustomValue(mobj_t *actor); +void A_UseCusValMemo(mobj_t *actor); +void A_RelayCustomValue(mobj_t *actor); +void A_CusValAction(mobj_t *actor); +void A_ForceStop(mobj_t *actor); +void A_ForceWin(mobj_t *actor); +void A_SpikeRetract(mobj_t *actor); +void A_InfoState(mobj_t *actor); +void A_Repeat(mobj_t *actor); +void A_SetScale(mobj_t *actor); +void A_RemoteDamage(mobj_t *actor); +void A_HomingChase(mobj_t *actor); +void A_TrapShot(mobj_t *actor); +void A_Boss1Chase(mobj_t *actor); +void A_Boss2Chase(mobj_t *actor); +void A_Boss2Pogo(mobj_t *actor); +void A_BossJetFume(mobj_t *actor); +void A_VileTarget(mobj_t *actor); +void A_VileAttack(mobj_t *actor); +void A_VileFire(mobj_t *actor); +void A_BrakChase(mobj_t *actor); +void A_BrakFireShot(mobj_t *actor); +void A_BrakLobShot(mobj_t *actor); +void A_NapalmScatter(mobj_t *actor); +void A_SpawnFreshCopy(mobj_t *actor); +void A_FlickySpawn(mobj_t *actor); +void A_FlickyAim(mobj_t *actor); +void A_FlickyFly(mobj_t *actor); +void A_FlickySoar(mobj_t *actor); +void A_FlickyCoast(mobj_t *actor); +void A_FlickyHop(mobj_t *actor); +void A_FlickyFlounder(mobj_t *actor); +void A_FlickyCheck(mobj_t *actor); +void A_FlickyHeightCheck(mobj_t *actor); +void A_FlickyFlutter(mobj_t *actor); +void A_FlameParticle(mobj_t *actor); +void A_FadeOverlay(mobj_t *actor); +void A_Boss5Jump(mobj_t *actor); +void A_LightBeamReset(mobj_t *actor); +void A_MineExplode(mobj_t *actor); +void A_MineRange(mobj_t *actor); +void A_ConnectToGround(mobj_t *actor); +void A_SpawnParticleRelative(mobj_t *actor); +void A_MultiShotDist(mobj_t *actor); +void A_WhoCaresIfYourSonIsABee(mobj_t *actor); +void A_ParentTriesToSleep(mobj_t *actor); +void A_CryingToMomma(mobj_t *actor); +void A_CheckFlags2(mobj_t *actor); +//for p_enemy.c + +// +// ENEMY THINKING +// Enemies are always spawned with targetplayer = -1, threshold = 0 +// Most monsters are spawned unaware of all players, but some can be made preaware. +// + +// +// P_CheckMeleeRange +// +boolean P_CheckMeleeRange(mobj_t *actor) +{ + mobj_t *pl; + fixed_t dist; + + if (!actor->target) + return false; + + pl = actor->target; + dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); + + if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius) + return false; + + // check height now, so that damn crawlas cant attack + // you if you stand on a higher ledge. + if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height)) + return false; + + if (!P_CheckSight(actor, actor->target)) + return false; + + return true; +} + +// P_CheckMeleeRange for Jettysyn Bomber. +boolean P_JetbCheckMeleeRange(mobj_t *actor) +{ + mobj_t *pl; + fixed_t dist; + + if (!actor->target) + return false; + + pl = actor->target; + dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); + + if (dist >= (actor->radius + pl->radius)*2) + return false; + + if (actor->eflags & MFE_VERTICALFLIP) + { + if (pl->z < actor->z + actor->height + FixedMul(40<scale)) + return false; + } + else + { + if (pl->z + pl->height > actor->z - FixedMul(40<scale)) + return false; + } + + return true; +} + +// P_CheckMeleeRange for CastleBot FaceStabber. +boolean P_FaceStabCheckMeleeRange(mobj_t *actor) +{ + mobj_t *pl; + fixed_t dist; + + if (!actor->target) + return false; + + pl = actor->target; + dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); + + if (dist >= (actor->radius + pl->radius)*4) + return false; + + if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height)) + return false; + + if (!P_CheckSight(actor, actor->target)) + return false; + + return true; +} + +// P_CheckMeleeRange for Skim. +boolean P_SkimCheckMeleeRange(mobj_t *actor) +{ + mobj_t *pl; + fixed_t dist; + + if (!actor->target) + return false; + + pl = actor->target; + dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y); + + if (dist >= FixedMul(MELEERANGE - 20*FRACUNIT, actor->scale) + pl->radius) + return false; + + if (actor->eflags & MFE_VERTICALFLIP) + { + if (pl->z < actor->z + actor->height + FixedMul(24<scale)) + return false; + } + else + { + if (pl->z + pl->height > actor->z - FixedMul(24<scale)) + return false; + } + + return true; +} + +// +// P_CheckMissileRange +// +boolean P_CheckMissileRange(mobj_t *actor) +{ + fixed_t dist; + + if (!actor->target) + return false; + + if (actor->reactiontime) + return false; // do not attack yet + + if (!P_CheckSight(actor, actor->target)) + return false; + + // OPTIMIZE: get this from a global checksight + dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - FixedMul(64*FRACUNIT, actor->scale); + + if (!actor->info->meleestate) + dist -= FixedMul(128*FRACUNIT, actor->scale); // no melee attack, so fire more + + dist >>= FRACBITS; + + if (actor->type == MT_EGGMOBILE) + dist >>= 1; + + if (dist > 200) + dist = 200; + + if (actor->type == MT_EGGMOBILE && dist > 160) + dist = 160; + + if (P_RandomByte() < dist) + return false; + + return true; +} + +/** Checks for water in a sector. + * Used by Skim movements. + * + * \param x X coordinate on the map. + * \param y Y coordinate on the map. + * \return True if there's water at this location, false if not. + * \sa ::MT_SKIM + */ +static boolean P_WaterInSector(mobj_t *mobj, fixed_t x, fixed_t y) +{ + sector_t *sector; + + sector = R_PointInSubsector(x, y)->sector; + + if (sector->ffloors) + { + ffloor_t *rover; + + for (rover = sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE)) + continue; + + if (*rover->topheight >= mobj->floorz && *rover->topheight <= mobj->z) + return true; // we found water!! + } + } + + return false; +} + +static const fixed_t xspeed[NUMDIRS] = {FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS)), 0, 46341>>(16-FRACBITS)}; +static const fixed_t yspeed[NUMDIRS] = {0, 46341>>(16-FRACBITS), FRACUNIT, 46341>>(16-FRACBITS), 0, -(46341>>(16-FRACBITS)), -FRACUNIT, -(46341>>(16-FRACBITS))}; + +/** Moves an actor in its current direction. + * + * \param actor Actor object to move. + * \return False if the move is blocked, otherwise true. + */ +boolean P_Move(mobj_t *actor, fixed_t speed) +{ + fixed_t tryx, tryy; + dirtype_t movedir = actor->movedir; + + if (movedir == DI_NODIR || !actor->health) + return false; + + I_Assert(movedir < NUMDIRS); + + tryx = actor->x + FixedMul(speed*xspeed[movedir], actor->scale); + if (twodlevel || actor->flags2 & MF2_TWOD) + tryy = actor->y; + else + tryy = actor->y + FixedMul(speed*yspeed[movedir], actor->scale); + + if (actor->type == MT_SKIM && !P_WaterInSector(actor, tryx, tryy)) // bail out if sector lacks water + return false; + + if (!P_TryMove(actor, tryx, tryy, false)) + { + if (actor->flags & MF_FLOAT && floatok) + { + // must adjust height + if (actor->z < tmfloorz) + actor->z += FixedMul(FLOATSPEED, actor->scale); + else + actor->z -= FixedMul(FLOATSPEED, actor->scale); + + if (actor->type == MT_JETJAW && actor->z + actor->height > actor->watertop) + actor->z = actor->watertop - actor->height; + + actor->flags2 |= MF2_INFLOAT; + return true; + } + + return false; + } + else + actor->flags2 &= ~MF2_INFLOAT; + + return true; +} + +/** Attempts to move an actor on in its current direction. + * If the move succeeds, the actor's move count is reset + * randomly to a value from 0 to 15. + * + * \param actor Actor to move. + * \return True if the move succeeds, false if the move is blocked. + */ +static boolean P_TryWalk(mobj_t *actor) +{ + if (!P_Move(actor, actor->info->speed)) + return false; + actor->movecount = P_RandomByte() & 15; + return true; +} + +void P_NewChaseDir(mobj_t *actor) +{ + fixed_t deltax, deltay; + dirtype_t d[3]; + dirtype_t tdir = DI_NODIR, olddir, turnaround; + + I_Assert(actor->target != NULL); + I_Assert(!P_MobjWasRemoved(actor->target)); + + olddir = actor->movedir; + + if (olddir >= NUMDIRS) + olddir = DI_NODIR; + + if (olddir != DI_NODIR) + turnaround = opposite[olddir]; + else + turnaround = olddir; + + deltax = actor->target->x - actor->x; + deltay = actor->target->y - actor->y; + + if (deltax > FixedMul(10*FRACUNIT, actor->scale)) + d[1] = DI_EAST; + else if (deltax < -FixedMul(10*FRACUNIT, actor->scale)) + d[1] = DI_WEST; + else + d[1] = DI_NODIR; + + if (twodlevel || actor->flags2 & MF2_TWOD) + d[2] = DI_NODIR; + if (deltay < -FixedMul(10*FRACUNIT, actor->scale)) + d[2] = DI_SOUTH; + else if (deltay > FixedMul(10*FRACUNIT, actor->scale)) + d[2] = DI_NORTH; + else + d[2] = DI_NODIR; + + // try direct route + if (d[1] != DI_NODIR && d[2] != DI_NODIR) + { + dirtype_t newdir = diags[((deltay < 0)<<1) + (deltax > 0)]; + + actor->movedir = newdir; + if ((newdir != turnaround) && P_TryWalk(actor)) + return; + } + + // try other directions + if (P_RandomChance(25*FRACUNIT/32) || abs(deltay) > abs(deltax)) + { + tdir = d[1]; + d[1] = d[2]; + d[2] = tdir; + } + + if (d[1] == turnaround) + d[1] = DI_NODIR; + if (d[2] == turnaround) + d[2] = DI_NODIR; + + if (d[1] != DI_NODIR) + { + actor->movedir = d[1]; + + if (P_TryWalk(actor)) + return; // either moved forward or attacked + } + + if (d[2] != DI_NODIR) + { + actor->movedir = d[2]; + + if (P_TryWalk(actor)) + return; + } + + // there is no direct path to the player, so pick another direction. + if (olddir != DI_NODIR) + { + actor->movedir =olddir; + + if (P_TryWalk(actor)) + return; + } + + // randomly determine direction of search + if (P_RandomChance(FRACUNIT/2)) + { + for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++) + { + if (tdir != turnaround) + { + actor->movedir = tdir; + + if (P_TryWalk(actor)) + return; + } + } + } + else + { + for (tdir = DI_SOUTHEAST; tdir >= DI_EAST; tdir--) + { + if (tdir != turnaround) + { + actor->movedir = tdir; + + if (P_TryWalk(actor)) + return; + } + } + } + + if (turnaround != DI_NODIR) + { + actor->movedir = turnaround; + + if (P_TryWalk(actor)) + return; + } + + actor->movedir = (angle_t)DI_NODIR; // cannot move +} + +/** Looks for players to chase after, aim at, or whatever. + * + * \param actor The object looking for flesh. + * \param allaround Look all around? If false, only players in a 180-degree + * range in front will be spotted. + * \param dist If > 0, checks distance + * \return True if a player is found, otherwise false. + * \sa P_SupermanLook4Players + */ +boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist) +{ + INT32 c = 0, stop; + player_t *player; + angle_t an; + + // BP: first time init, this allow minimum lastlook changes + if (actor->lastlook < 0) + actor->lastlook = P_RandomByte(); + + actor->lastlook %= MAXPLAYERS; + + stop = (actor->lastlook - 1) & PLAYERSMASK; + + for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK) + { + // done looking + if (actor->lastlook == stop) + return false; + + if (!playeringame[actor->lastlook]) + continue; + + if (c++ == 2) + return false; + + player = &players[actor->lastlook]; + + if ((netgame || multiplayer) && player->spectator) + continue; + + if (player->pflags & PF_INVIS) + continue; // ignore notarget + + if (!player->mo || P_MobjWasRemoved(player->mo)) + continue; + + if (player->mo->health <= 0) + continue; // dead + + if (dist > 0 + && P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist) + continue; // Too far away + + if (!allaround) + { + an = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; + if (an > ANGLE_90 && an < ANGLE_270) + { + dist = P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y); + // if real close, react anyway + if (dist > FixedMul(MELEERANGE, actor->scale)) + continue; // behind back + } + } + + if (!P_CheckSight(actor, player->mo)) + continue; // out of sight + + if (tracer) + P_SetTarget(&actor->tracer, player->mo); + else + P_SetTarget(&actor->target, player->mo); + return true; + } + + //return false; +} + +/** Looks for a player with a ring shield. + * Used by rings. + * + * \param actor Ring looking for a shield to be attracted to. + * \return True if a player with ring shield is found, otherwise false. + * \sa A_AttractChase + */ +static boolean P_LookForShield(mobj_t *actor) +{ + INT32 c = 0, stop; + player_t *player; + + // BP: first time init, this allow minimum lastlook changes + if (actor->lastlook < 0) + actor->lastlook = P_RandomByte(); + + actor->lastlook %= MAXPLAYERS; + + stop = (actor->lastlook - 1) & PLAYERSMASK; + + for (; ; actor->lastlook = ((actor->lastlook + 1) & PLAYERSMASK)) + { + // done looking + if (actor->lastlook == stop) + return false; + + if (!playeringame[actor->lastlook]) + continue; + + if (c++ == 2) + return false; + + player = &players[actor->lastlook]; + + if (!player->mo || player->mo->health <= 0) + continue; // dead + + //When in CTF, don't pull rings that you cannot pick up. + if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) || + (actor->type == MT_BLUETEAMRING && player->ctfteam != 2)) + continue; + + if ((player->powers[pw_shield] & SH_PROTECTELECTRIC) + && (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale))) + { + P_SetTarget(&actor->tracer, player->mo); + + if (actor->hnext) + P_SetTarget(&actor->hnext->hprev, actor->hprev); + if (actor->hprev) + P_SetTarget(&actor->hprev->hnext, actor->hnext); + + return true; + } + } + + //return false; +} + +#ifdef WEIGHTEDRECYCLER +// Compares players to see who currently has the "best" items, etc. +static int P_RecycleCompare(const void *p1, const void *p2) +{ + player_t *player1 = &players[*(const UINT8 *)p1]; + player_t *player2 = &players[*(const UINT8 *)p2]; + + // Non-shooting gametypes + if (!G_PlatformGametype()) + { + // Invincibility. + if (player1->powers[pw_invulnerability] > player2->powers[pw_invulnerability]) return -1; + else if (player2->powers[pw_invulnerability] > player1->powers[pw_invulnerability]) return 1; + + // One has a shield, the other doesn't. + if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1; + else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1; + + // Sneakers. + if (player1->powers[pw_sneakers] > player2->powers[pw_sneakers]) return -1; + else if (player2->powers[pw_sneakers] > player1->powers[pw_sneakers]) return 1; + } + else // Match, Team Match, CTF, Tag, Etc. + { + UINT8 player1_em = M_CountBits((UINT32)player1->powers[pw_emeralds], 7); + UINT8 player2_em = M_CountBits((UINT32)player2->powers[pw_emeralds], 7); + + UINT8 player1_rw = M_CountBits((UINT32)player1->ringweapons, NUM_WEAPONS-1); + UINT8 player2_rw = M_CountBits((UINT32)player2->ringweapons, NUM_WEAPONS-1); + + UINT16 player1_am = player1->powers[pw_infinityring] // max 800 + + player1->powers[pw_automaticring] // max 300 + + (player1->powers[pw_bouncering] * 3) // max 100 + + (player1->powers[pw_explosionring] * 6) // max 50 + + (player1->powers[pw_scatterring] * 3) // max 100 + + (player1->powers[pw_grenadering] * 6) // max 50 + + (player1->powers[pw_railring] * 6); // max 50 + UINT16 player2_am = player2->powers[pw_infinityring] // max 800 + + player2->powers[pw_automaticring] // max 300 + + (player2->powers[pw_bouncering] * 3) // max 100 + + (player2->powers[pw_explosionring] * 6) // max 50 + + (player2->powers[pw_scatterring] * 3) // max 100 + + (player2->powers[pw_grenadering] * 6) // max 50 + + (player2->powers[pw_railring] * 6); // max 50 + + // Super trumps everything. + if (player1->powers[pw_super] && !player2->powers[pw_super]) return -1; + else if (player2->powers[pw_super] && !player1->powers[pw_super]) return 1; + + // Emerald count if neither player is Super. + if (player1_em > player2_em) return -1; + else if (player1_em < player2_em) return 1; + + // One has a shield, the other doesn't. + // (the likelihood of a shielded player being worse off than one without one is low.) + if (player1->powers[pw_shield] && !player2->powers[pw_shield]) return -1; + else if (player2->powers[pw_shield] && !player1->powers[pw_shield]) return 1; + + // Ring weapons count + if (player1_rw > player2_rw) return -1; + else if (player1_rw < player2_rw) return 1; + + // Ring ammo if they have the same number of weapons + if (player1_am > player2_am) return -1; + else if (player1_am < player2_am) return 1; + } + + // Identical for our purposes + return 0; +} +#endif + +// Handles random monitor weights via console. +static mobjtype_t P_DoRandomBoxChances(void) +{ + mobjtype_t spawnchance[256]; + INT32 numchoices = 0, i = 0; + + if (!(netgame || multiplayer)) + { + switch (P_RandomKey(10)) + { + case 0: + return MT_RING_ICON; + case 1: + return MT_SNEAKERS_ICON; + case 2: + return MT_INVULN_ICON; + case 3: + return MT_WHIRLWIND_ICON; + case 4: + return MT_ELEMENTAL_ICON; + case 5: + return MT_ATTRACT_ICON; + case 6: + return MT_FORCE_ICON; + case 7: + return MT_ARMAGEDDON_ICON; + case 8: + return MT_1UP_ICON; + case 9: + return MT_EGGMAN_ICON; + } + return MT_NULL; + } + +#define QUESTIONBOXCHANCES(type, cvar) \ +for (i = cvar.value; i; --i) spawnchance[numchoices++] = type + QUESTIONBOXCHANCES(MT_RING_ICON, cv_superring); + QUESTIONBOXCHANCES(MT_SNEAKERS_ICON, cv_supersneakers); + QUESTIONBOXCHANCES(MT_INVULN_ICON, cv_invincibility); + QUESTIONBOXCHANCES(MT_WHIRLWIND_ICON, cv_jumpshield); + QUESTIONBOXCHANCES(MT_ELEMENTAL_ICON, cv_watershield); + QUESTIONBOXCHANCES(MT_ATTRACT_ICON, cv_ringshield); + QUESTIONBOXCHANCES(MT_FORCE_ICON, cv_forceshield); + QUESTIONBOXCHANCES(MT_ARMAGEDDON_ICON, cv_bombshield); + QUESTIONBOXCHANCES(MT_1UP_ICON, cv_1up); + QUESTIONBOXCHANCES(MT_EGGMAN_ICON, cv_eggmanbox); + QUESTIONBOXCHANCES(MT_MIXUP_ICON, cv_teleporters); + QUESTIONBOXCHANCES(MT_RECYCLER_ICON, cv_recycler); +#undef QUESTIONBOXCHANCES + + if (numchoices == 0) return MT_NULL; + return spawnchance[P_RandomKey(numchoices)]; +} + +// +// ACTION ROUTINES +// + +// Function: A_Look +// +// Description: Look for a player and set your target to them. +// +// var1: +// lower 16 bits = look all around +// upper 16 bits = distance limit +// var2 = If 1, only change to seestate. If 2, only play seesound. If 0, do both. +// +void A_Look(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Look", actor)) + return; +#endif + + if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale))) + return; + + // go into chase state + if (!locvar2) + { + P_SetMobjState(actor, actor->info->seestate); + A_PlaySeeSound(actor); + } + else if (locvar2 == 1) // Only go into seestate + P_SetMobjState(actor, actor->info->seestate); + else if (locvar2 == 2) // Only play seesound + A_PlaySeeSound(actor); +} + +// Function: A_Chase +// +// Description: Chase after your target. +// +// var1: +// 1 = don't check meleestate +// 2 = don't check missilestate +// 3 = don't check meleestate and missilestate +// var2 = unused +// +void A_Chase(mobj_t *actor) +{ + INT32 delta; + INT32 locvar1 = var1; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Chase", actor)) + return; +#endif + + I_Assert(actor != NULL); + I_Assert(!P_MobjWasRemoved(actor)); + + if (actor->reactiontime) + actor->reactiontime--; + + // modify target threshold + if (actor->threshold) + { + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjStateNF(actor, actor->info->spawnstate); + return; + } + + // do not attack twice in a row + if (actor->flags2 & MF2_JUSTATTACKED) + { + actor->flags2 &= ~MF2_JUSTATTACKED; + P_NewChaseDir(actor); + return; + } + + // check for melee attack + if (!(locvar1 & 1) && actor->info->meleestate && P_CheckMeleeRange(actor)) + { + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + + P_SetMobjState(actor, actor->info->meleestate); + return; + } + + // check for missile attack + if (!(locvar1 & 2) && actor->info->missilestate) + { + if (actor->movecount || !P_CheckMissileRange(actor)) + goto nomissile; + + P_SetMobjState(actor, actor->info->missilestate); + actor->flags2 |= MF2_JUSTATTACKED; + return; + } + +nomissile: + // possibly choose another target + if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + && P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); +} + +// Function: A_FaceStabChase +// +// Description: Unused variant of A_Chase for Castlebot Facestabber. +// +// var1 = unused +// var2 = unused +// +void A_FaceStabChase(mobj_t *actor) +{ + INT32 delta; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FaceStabChase", actor)) + return; +#endif + + if (actor->reactiontime) + actor->reactiontime--; + + // modify target threshold + if (actor->threshold) + { + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjStateNF(actor, actor->info->spawnstate); + return; + } + + // do not attack twice in a row + if (actor->flags2 & MF2_JUSTATTACKED) + { + actor->flags2 &= ~MF2_JUSTATTACKED; + P_NewChaseDir(actor); + return; + } + + // check for melee attack + if (actor->info->meleestate && P_FaceStabCheckMeleeRange(actor)) + { + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + + P_SetMobjState(actor, actor->info->meleestate); + return; + } + + // check for missile attack + if (actor->info->missilestate) + { + if (actor->movecount || !P_CheckMissileRange(actor)) + goto nomissile; + + P_SetMobjState(actor, actor->info->missilestate); + actor->flags2 |= MF2_JUSTATTACKED; + return; + } + +nomissile: + // possibly choose another target + if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + && P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); +} + +static void P_SharpDust(mobj_t *actor, mobjtype_t type, angle_t ang) +{ + mobj_t *dust; + + if (!type || !P_IsObjectOnGround(actor)) + return; + + dust = P_SpawnMobjFromMobj(actor, + -P_ReturnThrustX(actor, ang, 16<angle, actor->radius), + -P_ReturnThrustY(actor, actor->angle, actor->radius), + actor->height/3, + MT_PARTICLE); + flume->destscale = actor->scale*3; + P_SetScale(flume, flume->destscale); + P_SetTarget(&flume->target, actor); + flume->sprite = SPR_JETF; + flume->frame = FF_FULLBRIGHT; + flume->tics = 2; +} + +// Function: A_FaceStabRev +// +// Description: Facestabber rev action +// +// var1 = effective duration +// var2 = effective nextstate +// +void A_FaceStabRev(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FaceStabRev", actor)) + return; +#endif + + if (!actor->target) + { + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + if (actor->hnext) + P_SetTarget(&actor->hnext, NULL); + actor->extravalue1 = 0; + + if (!actor->reactiontime) + { + actor->reactiontime = locvar1; + S_StartSound(actor, actor->info->activesound); + } + else + { + if ((--actor->reactiontime) == 0) + { + S_StartSound(actor, actor->info->attacksound); + P_SetMobjState(actor, locvar2); + } + else + { + P_TryMove(actor, actor->x - P_ReturnThrustX(actor, actor->angle, 2<y - P_ReturnThrustY(actor, actor->angle, 2<target) + { + angle_t visang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + // Calculate new direction. + angle_t dirang = actor->angle; + angle_t diffang = visang - dirang; + + if (locvar1) // Allow homing? + { + if (diffang > ANGLE_180) + { + angle_t workang = locvar1*(InvAngle(diffang)>>5); + diffang += InvAngle(workang); + } + else + diffang += (locvar1*(diffang>>5)); + } + diffang += ANGLE_45; + + // Check the sight cone. + if (diffang < ANGLE_90) + { + actor->angle = dirang; + if (++actor->extravalue2 < 4) + actor->extravalue2 = 4; + else if (actor->extravalue2 > 26) + actor->extravalue2 = 26; + + if (P_TryMove(actor, + actor->x + P_ReturnThrustX(actor, dirang, actor->extravalue2<y + P_ReturnThrustY(actor, dirang, actor->extravalue2<extravalue1; + fixed_t basesize = FRACUNIT/MAXVAL; + mobj_t *hwork = actor; + INT32 dist = 113; + fixed_t xo = P_ReturnThrustX(actor, actor->angle, dist*basesize); + fixed_t yo = P_ReturnThrustY(actor, actor->angle, dist*basesize); + while (step > 0) + { + if (!hwork->hnext) + P_SetTarget(&hwork->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_FACESTABBERSPEAR)); + hwork = hwork->hnext; + hwork->angle = actor->angle + ANGLE_90; + hwork->destscale = FixedSqrt(basesize*step); + hwork->fuse = 2; + P_TeleportMove(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<angle); + + if (actor->extravalue1 >= MAXVAL) + actor->extravalue1 -= NUMGRADS; + + P_FaceStabFlume(actor); + return; +#undef MAXVAL +#undef NUMGRADS +#undef NUMSTEPS + } + } + } + + P_SetMobjState(actor, locvar2); + actor->reactiontime = actor->info->reactiontime; +} + +// Function: A_FaceStabMiss +// +// Description: Facestabber miss action +// +// var1 = unused +// var2 = effective nextstate +// +void A_FaceStabMiss(mobj_t *actor) +{ + //INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FaceStabMiss", actor)) + return; +#endif + + if (++actor->extravalue1 >= 3) + { + actor->extravalue2 -= 2; + actor->extravalue1 = 0; + S_StartSound(actor, sfx_s3k47); + P_SharpDust(actor, MT_SPINDUST, actor->angle); + } + + if (actor->extravalue2 <= 0 || !P_TryMove(actor, + actor->x + P_ReturnThrustX(actor, actor->angle, actor->extravalue2<y + P_ReturnThrustY(actor, actor->angle, actor->extravalue2<extravalue2 = 0; + P_SetMobjState(actor, locvar2); + } +} + +// Function: A_StatueBurst +// +// Description: For suspicious statues only... +// +// var1 = unused +// var2 = effective nextstate for created object +// +void A_StatueBurst(mobj_t *actor) +{ + //INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *new; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_StatueBurst", actor)) + return; +#endif + + if (!(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, (mobjtype_t)actor->info->raisestate))) + return; + + new->angle = actor->angle; + new->target = actor->target; + if (locvar2) + P_SetMobjState(new, (statenum_t)locvar2); + S_StopSound(actor); + S_StartSound(actor, sfx_s3k96); +} + +// Function: A_JetJawRoam +// +// Description: Roaming routine for JetJaw +// +// var1 = unused +// var2 = unused +// +void A_JetJawRoam(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetJawRoam", actor)) + return; +#endif + if (actor->reactiontime) + { + actor->reactiontime--; + P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed*FRACUNIT/4, actor->scale)); + } + else + { + actor->reactiontime = actor->info->reactiontime; + actor->angle += ANGLE_180; + } + + if (P_LookForPlayers(actor, false, false, actor->radius * 16)) + P_SetMobjState(actor, actor->info->seestate); +} + +// Function: A_JetJawChomp +// +// Description: Chase and chomp at the target, as long as it is in view +// +// var1 = unused +// var2 = unused +// +void A_JetJawChomp(mobj_t *actor) +{ + INT32 delta; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetJawChomp", actor)) + return; +#endif + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + // Stop chomping if target's dead or you can't see it + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) + || actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + { + P_SetMobjStateNF(actor, actor->info->spawnstate); + return; + } + + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); +} + +// Function: A_PointyThink +// +// Description: Thinker function for Pointy +// +// var1 = unused +// var2 = unused +// +void A_PointyThink(mobj_t *actor) +{ + INT32 i; + player_t *player = NULL; + mobj_t *ball; + TVector v; + TVector *res; + angle_t fa; + fixed_t radius = FixedMul(actor->info->radius*actor->info->reactiontime, actor->scale); + boolean firsttime = true; + INT32 sign; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_PointyThink", actor)) + return; +#endif + actor->momx = actor->momy = actor->momz = 0; + + // Find nearest player + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + if (!players[i].mo->health) + continue; + + if (!P_CheckSight(actor, players[i].mo)) + continue; + + if (firsttime) + { + firsttime = false; + player = &players[i]; + } + else + { + if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) < + P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y)) + player = &players[i]; + } + } + + if (!player) + return; + + // Okay, we found the closest player. Let's move based on his movement. + P_SetTarget(&actor->target, player->mo); + A_FaceTarget(actor); + + if (P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) < P_AproxDistance(player->mo->x + player->mo->momx - actor->x, player->mo->y + player->mo->momy - actor->y)) + sign = -1; // Player is moving away + else + sign = 1; // Player is moving closer + + if (player->mo->momx || player->mo->momy) + { + P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y), FixedMul(actor->info->speed*sign, actor->scale)); + + // Rotate our spike balls + actor->lastlook += actor->info->damage; + actor->lastlook %= FINEANGLES/4; + } + + if (!actor->tracer) // For some reason we do not have spike balls... + return; + + // Position spike balls relative to the value of 'lastlook'. + ball = actor->tracer; + + i = 0; + while (ball) + { + fa = actor->lastlook+i; + v[0] = FixedMul(FINECOSINE(fa),radius); + v[1] = 0; + v[2] = FixedMul(FINESINE(fa),radius); + v[3] = FRACUNIT; + + res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(actor->lastlook+i))); + M_Memcpy(&v, res, sizeof (v)); + res = VectorMatrixMultiply(v, *RotateZMatrix(actor->angle+ANGLE_180)); + M_Memcpy(&v, res, sizeof (v)); + + P_UnsetThingPosition(ball); + ball->x = actor->x + v[0]; + ball->y = actor->y + v[1]; + ball->z = actor->z + (actor->height>>1) + v[2]; + P_SetThingPosition(ball); + + ball = ball->tracer; + i += ANGLE_90 >> ANGLETOFINESHIFT; + } +} + +// Function: A_CheckBuddy +// +// Description: Checks if target/tracer exists/has health. If not, the object removes itself. +// +// var1: +// 0 = target +// 1 = tracer +// var2 = unused +// +void A_CheckBuddy(mobj_t *actor) +{ + INT32 locvar1 = var1; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckBuddy", actor)) + return; +#endif + if (locvar1 && (!actor->tracer || actor->tracer->health <= 0)) + P_RemoveMobj(actor); + else if (!locvar1 && (!actor->target || actor->target->health <= 0)) + P_RemoveMobj(actor); +} + +// Function: A_HoodThink +// +// Description: Thinker for Robo-Hood +// +// var1 = unused +// var2 = unused +// +void A_HoodThink(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_HoodThink", actor)) + return; +#endif + // Currently in the air... + if (!(actor->eflags & MFE_VERTICALFLIP) && actor->z > actor->floorz) + { + if (actor->momz > 0) + P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising + else + P_SetMobjStateNF(actor, actor->info->raisestate); // Falling + + return; + } + else if ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height < actor->ceilingz) + { + if (actor->momz < 0) + P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising + else + P_SetMobjStateNF(actor, actor->info->raisestate); // Falling + + return; + } + + if (actor->state == &states[actor->info->xdeathstate] + || actor->state == &states[actor->info->raisestate]) + P_SetMobjStateNF(actor, actor->info->seestate); + + if (!actor->target) + { + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + A_FaceTarget(actor); // Aiming... aiming... + + if (--actor->reactiontime > 0) + return; + + // Shoot, if not too close (cheap shots are lame) + if ((P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) > FixedMul(192*FRACUNIT, actor->scale)) + || (actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH))) // If you can't jump, might as well shoot regardless of distance! + P_SetMobjState(actor, actor->info->missilestate); + else if (!(actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH)))// But we WILL jump! + P_SetMobjState(actor, actor->info->painstate); + + actor->reactiontime = actor->info->reactiontime; +} + +// Function: A_ArrowCheck +// +// Description: Checks arrow direction and adjusts sprite accordingly +// +// var1 = unused +// var2 = unused +// +void A_ArrowCheck(mobj_t *actor) +{ + fixed_t x,y,z; + angle_t angle; + fixed_t dist; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ArrowCheck", actor)) + return; +#endif + + // Movement vector + x = actor->momx; + y = actor->momy; + z = actor->momz; + + // Calculate the angle of movement. + /* + Z + / | + / | + / | + 0------dist(X,Y) + */ + + dist = P_AproxDistance(x, y); + + angle = R_PointToAngle2(0, 0, dist, z); + + if (angle > ANG20 && angle <= ANGLE_180) + P_SetMobjStateNF(actor, actor->info->raisestate); + else if (angle < ANG340 && angle > ANGLE_180) + P_SetMobjStateNF(actor, actor->info->xdeathstate); + else + P_SetMobjStateNF(actor, actor->info->spawnstate); +} + +// Function: A_SnailerThink +// +// Description: Thinker function for Snailer +// +// var1 = unused +// var2 = unused +// +void A_SnailerThink(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SnailerThink", actor)) + return; +#endif + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (!P_LookForPlayers(actor, true, false, 0)) + return; + } + + // We now have a target. Oh bliss, rapture, and contentment! + + if (actor->target->z + actor->target->height > actor->z - FixedMul(32*FRACUNIT, actor->scale) + && actor->target->z < actor->z + actor->height + FixedMul(32*FRACUNIT, actor->scale) + && !(leveltime % (TICRATE*2))) + { + angle_t an; + fixed_t z; + + // Actor shouldn't face target, so we'll do things a bit differently here + + an = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle; + + z = actor->z + actor->height/2; + + if (an > ANGLE_45 && an < ANGLE_315) // fire as close as you can to the target, even if too sharp an angle from your front + { + fixed_t dist; + fixed_t dx, dy; + + dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y); + + if (an > ANGLE_45 && an <= ANGLE_90) // fire at 45 degrees to the left + { + dx = actor->x + P_ReturnThrustX(actor, actor->angle + ANGLE_45, dist); + dy = actor->y + P_ReturnThrustY(actor, actor->angle + ANGLE_45, dist); + } + else if (an >= ANGLE_270 && an < ANGLE_315) // fire at 45 degrees to the right + { + dx = actor->x + P_ReturnThrustX(actor, actor->angle - ANGLE_45, dist); + dy = actor->y + P_ReturnThrustY(actor, actor->angle - ANGLE_45, dist); + } + else // fire straight ahead + { + dx = actor->x + P_ReturnThrustX(actor, actor->angle, dist); + dy = actor->y + P_ReturnThrustY(actor, actor->angle, dist); + } + + P_SpawnPointMissile(actor, dx, dy, actor->target->z, MT_ROCKET, actor->x, actor->y, z); + } + else + P_SpawnXYZMissile(actor, actor->target, MT_ROCKET, actor->x, actor->y, z); + } + + if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z > actor->z) + || (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) > (actor->z + actor->height))) + actor->momz += FixedMul(actor->info->speed, actor->scale); + else if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->target->z < actor->z) + || (actor->eflags & MFE_VERTICALFLIP && (actor->target->z + actor->target->height) < (actor->z + actor->height))) + actor->momz -= FixedMul(actor->info->speed, actor->scale); + + actor->momz /= 2; +} + +// Function: A_SharpChase +// +// Description: Thinker/Chase routine for Spincushions +// +// var1 = unused +// var2 = unused +// +void A_SharpChase(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SharpChase", actor)) + return; +#endif + + if (actor->reactiontime) + { + INT32 delta; + + actor->reactiontime--; + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); + } + else + { + actor->threshold = actor->info->painchance; + P_SetMobjState(actor, actor->info->missilestate); + S_StartSound(actor, actor->info->attacksound); + } +} + +// Function: A_SharpSpin +// +// Description: Spin chase routine for Spincushions +// +// var1 = object # to spawn as dust (if not provided not done) +// var2 = if nonzero, do the old-style spinning using this as the angle difference +// +void A_SharpSpin(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + angle_t oldang = actor->angle; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SharpSpin", actor)) + return; +#endif + + if (actor->threshold && actor->target) + { + angle_t ang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_Thrust(actor, ang, actor->info->speed*actor->scale); + if (locvar2) + actor->angle += locvar2; // ANGLE_22h; + else + actor->angle = ang; + actor->threshold--; + if (leveltime & 1) + S_StartSound(actor, actor->info->painsound); + } + else + { + actor->reactiontime = actor->info->reactiontime; + P_SetMobjState(actor, actor->info->meleestate); + } + + P_SharpDust(actor, locvar1, oldang); +} + +// Function: A_SharpDecel +// +// Description: Slow down the Spincushion +// +// var1 = unused +// var2 = unused +// +void A_SharpDecel(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SharpDecel", actor)) + return; +#endif + + if (actor->momx > 2 || actor->momy > 2) + { + actor->momx >>= 1; + actor->momy >>= 1; + } + else + P_SetMobjState(actor, actor->info->xdeathstate); +} + +// Function: A_CrushstaceanWalk +// +// Description: Crushstacean movement +// +// var1 = speed (actor info's speed if 0) +// var2 = state to switch to when blocked (spawnstate if 0) +// +void A_CrushstaceanWalk(mobj_t *actor) +{ + INT32 locvar1 = (var1 ? var1 : (INT32)actor->info->speed); + INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); + angle_t ang = actor->angle + ((actor->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushstaceanWalk", actor)) + return; +#endif + + actor->reactiontime--; + + if (!P_TryMove(actor, + actor->x + P_ReturnThrustX(actor, ang, locvar1*actor->scale), + actor->y + P_ReturnThrustY(actor, ang, locvar1*actor->scale), + false) + || (actor->reactiontime-- <= 0)) + { + actor->flags2 ^= MF2_AMBUSH; + P_SetMobjState(actor, locvar2); + actor->reactiontime = actor->info->reactiontime; + } +} + +// Function: A_CrushstaceanPunch +// +// Description: Crushstacean attack +// +// var1 = unused +// var2 = state to go to if unsuccessful (spawnstate if 0) +// +void A_CrushstaceanPunch(mobj_t *actor) +{ + //INT32 locvar1 = var1; + INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushstaceanPunch", actor)) + return; +#endif + + if (!actor->tracer) + return; + + if (!actor->target) + { + P_SetMobjState(actor, locvar2); + return; + } + + actor->tracer->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_SetMobjState(actor->tracer, actor->tracer->info->missilestate); + actor->tracer->extravalue1 = actor->tracer->extravalue2 = 0; + S_StartSound(actor, actor->info->attacksound); +} + +// Function: A_CrushclawAim +// +// Description: Crushstacean claw aiming +// +// var1 = sideways offset +// var2 = vertical offset +// +void A_CrushclawAim(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *crab = actor->tracer; + angle_t ang; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushclawAim", actor)) + return; +#endif + + if (!crab) + { + P_RemoveMobj(actor); + return; // there is only one step and it is crab + } + + if (crab->target || P_LookForPlayers(crab, true, false, 600*crab->scale)) + ang = R_PointToAngle2(crab->x, crab->y, crab->target->x, crab->target->y); + else + ang = crab->angle + ((crab->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); + ang -= actor->angle; + +#define anglimit ANGLE_22h +#define angfactor 5 + if (ang < ANGLE_180) + { + if (ang > anglimit) + ang = anglimit; + ang /= angfactor; + } + else + { + ang = InvAngle(ang); + if (ang > anglimit) + ang = anglimit; + ang = InvAngle(ang/angfactor); + } + actor->angle += ang; +#undef anglimit +#undef angfactor + + P_TeleportMove(actor, + crab->x + P_ReturnThrustX(actor, actor->angle, locvar1*crab->scale), + crab->y + P_ReturnThrustY(actor, actor->angle, locvar1*crab->scale), + crab->z + locvar2*crab->scale); + + if (!crab->target || !crab->info->missilestate || (statenum_t)(crab->state-states) == crab->info->missilestate) + return; + + if (((ang + ANG1) < ANG2) || P_AproxDistance(crab->x - crab->target->x, crab->y - crab->target->y) < 333*crab->scale) + P_SetMobjState(crab, crab->info->missilestate); +} + +// Function: A_CrushclawLaunch +// +// Description: Crushstacean claw launching +// +// var1: +// 0 - forwards +// anything else - backwards +// var2 = state to change to when done +// +void A_CrushclawLaunch(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *crab = actor->tracer; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrushclawLaunch", actor)) + return; +#endif + + if (!crab) + { + mobj_t *chainnext; + while (actor) + { + chainnext = actor->target; + P_RemoveMobj(actor); + actor = chainnext; + } + return; // there is only one step and it is crab + } + + if (!actor->extravalue1) + { + S_StartSound(actor, actor->info->activesound); + actor->extravalue1 = ((locvar1) ? -1 : 32); + } + else if (actor->extravalue1 != 1) + actor->extravalue1 -= 1; + +#define CSEGS 5 + if (!actor->target) + { + mobj_t *prevchain = actor; + UINT8 i = 0; + for (i = 0; (i < CSEGS); i++) + { + mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate); + prevchain->target = newchain; + prevchain = newchain; + } + actor->target->angle = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y); + } + + if ((!locvar1) && crab->target) + { +#define anglimit ANGLE_22h +#define angfactor 7 + angle_t ang = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y) - actor->target->angle; + if (ang < ANGLE_180) + { + if (ang > anglimit) + ang = anglimit; + ang /= angfactor; + } + else + { + ang = InvAngle(ang); + if (ang > anglimit) + ang = anglimit; + ang /= angfactor; + ang = InvAngle(ang); + } + actor->target->angle += ang; + actor->angle = actor->target->angle; + } + + actor->extravalue2 += actor->extravalue1; + + if (!P_TryMove(actor, + actor->target->x + P_ReturnThrustX(actor, actor->target->angle, actor->extravalue2*actor->scale), + actor->target->y + P_ReturnThrustY(actor, actor->target->angle, actor->extravalue2*actor->scale), + true) + && !locvar1) + { + actor->extravalue1 = 0; + actor->extravalue2 = FixedHypot(actor->x - actor->target->x, actor->y - actor->target->y)>>FRACBITS; + P_SetMobjState(actor, locvar2); + S_StopSound(actor); + S_StartSound(actor, sfx_s3k49); + } + else + { + actor->z = actor->target->z; + if ((!locvar1 && (actor->extravalue2 > 256)) || (locvar1 && (actor->extravalue2 < 16))) + { + if (locvar1) // In case of retracting, resume crab and remove the chain. + { + mobj_t *chain = actor->target, *chainnext; + while (chain) + { + chainnext = chain->target; + P_RemoveMobj(chain); + chain = chainnext; + } + actor->extravalue2 = 0; + actor->angle = R_PointToAngle2(crab->x, crab->y, actor->x, actor->y); + P_SetTarget(&actor->target, NULL); + P_SetTarget(&crab->target, NULL); + P_SetMobjState(crab, crab->state->nextstate); + } + actor->extravalue1 = 0; + P_SetMobjState(actor, locvar2); + S_StopSound(actor); + if (!locvar1) + S_StartSound(actor, sfx_s3k64); + } + } + + if (!actor->target) + return; + + { + mobj_t *chain = actor->target->target; + fixed_t dx = (actor->x - actor->target->x)/CSEGS, dy = (actor->y - actor->target->y)/CSEGS, dz = (actor->z - actor->target->z)/CSEGS; + fixed_t idx = dx, idy = dy, idz = dz; + while (chain) + { + P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz); + chain->watertop = chain->z; + idx += dx; + idy += dy; + idz += dz; + chain = chain->target; + } + } +#undef CSEGS +} + +// Function: A_VultureVtol +// +// Description: Vulture rising up to match target's height +// +// var1 = unused +// var2 = unused +// +void A_VultureVtol(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureVtol", actor)) + return; +#endif + + if (!actor->target) + return; + + actor->flags |= MF_NOGRAVITY; + actor->flags |= MF_FLOAT; + + A_FaceTarget(actor); + + S_StopSound(actor); + + if (actor->z < actor->target->z+(actor->target->height/4) && actor->z + actor->height < actor->ceilingz) + actor->momz = FixedMul(2*FRACUNIT, actor->scale); + else if (actor->z > (actor->target->z+(actor->target->height/4)*3) && actor->z > actor->floorz) + actor->momz = FixedMul(-2*FRACUNIT, actor->scale); + else + { + // Attack! + actor->momz = 0; + P_SetMobjState(actor, actor->info->missilestate); + S_StartSound(actor, actor->info->activesound); + } +} + +// Function: A_VultureCheck +// +// Description: If the vulture is stopped, look for a new target +// +// var1 = unused +// var2 = unused +// +void A_VultureCheck(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureCheck", actor)) + return; +#endif + + if (actor->momx || actor->momy) + return; + + actor->flags &= ~MF_NOGRAVITY; // Fall down + + if (actor->z <= actor->floorz) + { + actor->angle -= ANGLE_180; // turn around + P_SetMobjState(actor, actor->info->spawnstate); + } +} + +// Function: A_SkimChase +// +// Description: Thinker/Chase routine for Skims +// +// var1 = unused +// var2 = unused +// +void A_SkimChase(mobj_t *actor) +{ + INT32 delta; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SkimChase", actor)) + return; +#endif + if (actor->reactiontime) + actor->reactiontime--; + + // modify target threshold + if (actor->threshold) + { + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + P_LookForPlayers(actor, true, false, 0); + + // the spawnstate for skims already calls this function so just return either way + // without changing state + return; + } + + // do not attack twice in a row + if (actor->flags2 & MF2_JUSTATTACKED) + { + actor->flags2 &= ~MF2_JUSTATTACKED; + P_NewChaseDir(actor); + return; + } + + // check for melee attack + if (actor->info->meleestate && P_SkimCheckMeleeRange(actor)) + { + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + + P_SetMobjState(actor, actor->info->meleestate); + return; + } + + // check for missile attack + if (actor->info->missilestate) + { + if (actor->movecount || !P_CheckMissileRange(actor)) + goto nomissile; + + P_SetMobjState(actor, actor->info->missilestate); + actor->flags2 |= MF2_JUSTATTACKED; + return; + } + +nomissile: + // possibly choose another target + if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + && P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); +} + +// Function: A_FaceTarget +// +// Description: Immediately turn to face towards your target. +// +// var1 = unused +// var2 = unused +// +void A_FaceTarget(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FaceTarget", actor)) + return; +#endif + if (!actor->target) + return; + + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); +} + +// Function: A_FaceTracer +// +// Description: Immediately turn to face towards your tracer. +// +// var1 = unused +// var2 = unused +// +void A_FaceTracer(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FaceTracer", actor)) + return; +#endif + if (!actor->tracer) + return; + + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); +} + +// Function: A_LobShot +// +// Description: Lob an object at your target. +// +// var1 = object # to lob +// var2: +// var2 >> 16 = height offset +// var2 & 65535 = airtime +// +void A_LobShot(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2 >> 16; + mobj_t *shot, *hitspot; + angle_t an; + fixed_t z; + fixed_t dist; + fixed_t vertical, horizontal; + fixed_t airtime = var2 & 65535; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_LobShot", actor)) + return; +#endif + if (!actor->target) + return; + + A_FaceTarget(actor); + + if (actor->eflags & MFE_VERTICALFLIP) + { + z = actor->z + actor->height - FixedMul(locvar2*FRACUNIT, actor->scale); + if (actor->type == MT_BLACKEGGMAN) + z -= FixedMul(mobjinfo[locvar1].height, actor->scale/2); + else + z -= FixedMul(mobjinfo[locvar1].height, actor->scale); + } + else + z = actor->z + FixedMul(locvar2*FRACUNIT, actor->scale); + + shot = P_SpawnMobj(actor->x, actor->y, z, locvar1); + + if (actor->type == MT_BLACKEGGMAN) + { + shot->destscale = actor->scale/2; + P_SetScale(shot, actor->scale/2); + } + else + { + shot->destscale = actor->scale; + P_SetScale(shot, actor->scale); + } + + // Keep track of where it's going to land + hitspot = P_SpawnMobj(actor->target->x&(64*FRACUNIT-1), actor->target->y&(64*FRACUNIT-1), actor->target->subsector->sector->floorheight, MT_NULL); + hitspot->tics = airtime; + P_SetTarget(&shot->tracer, hitspot); + + P_SetTarget(&shot->target, actor); // where it came from + + shot->angle = an = actor->angle; + an >>= ANGLETOFINESHIFT; + + dist = P_AproxDistance(actor->target->x - shot->x, actor->target->y - shot->y); + + horizontal = dist / airtime; + vertical = FixedMul((gravity*airtime)/2, shot->scale); + + shot->momx = FixedMul(horizontal, FINECOSINE(an)); + shot->momy = FixedMul(horizontal, FINESINE(an)); + shot->momz = vertical; + +/* Try to adjust when destination is not the same height + if (actor->z != actor->target->z) + { + fixed_t launchhyp; + fixed_t diff; + fixed_t orig; + + diff = actor->z - actor->target->z; + { + launchhyp = P_AproxDistance(horizontal, vertical); + + orig = FixedMul(FixedDiv(vertical, horizontal), diff); + + CONS_Debug(DBG_GAMELOGIC, "orig: %d\n", (orig)>>FRACBITS); + + horizontal = dist / airtime; + vertical = (gravity*airtime)/2; + } + dist -= orig; + shot->momx = FixedMul(horizontal, FINECOSINE(an)); + shot->momy = FixedMul(horizontal, FINESINE(an)); + shot->momz = vertical; +*/ + + if (shot->info->seesound) + S_StartSound(shot, shot->info->seesound); + + if (!(actor->flags & MF_BOSS)) + { + if (ultimatemode) + actor->reactiontime = actor->info->reactiontime*TICRATE; + else + actor->reactiontime = actor->info->reactiontime*TICRATE*2; + } +} + +// Function: A_FireShot +// +// Description: Shoot an object at your target. +// +// var1 = object # to shoot +// var2 = height offset +// +void A_FireShot(mobj_t *actor) +{ + fixed_t z; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FireShot", actor)) + return; +#endif + if (!actor->target) + return; + + A_FaceTarget(actor); + + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); + + P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z); + + if (!(actor->flags & MF_BOSS)) + { + if (ultimatemode) + actor->reactiontime = actor->info->reactiontime*TICRATE; + else + actor->reactiontime = actor->info->reactiontime*TICRATE*2; + } +} + +// Function: A_SuperFireShot +// +// Description: Shoot an object at your target that will even stall Super Sonic. +// +// var1 = object # to shoot +// var2 = height offset +// +void A_SuperFireShot(mobj_t *actor) +{ + fixed_t z; + mobj_t *mo; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SuperFireShot", actor)) + return; +#endif + if (!actor->target) + return; + + A_FaceTarget(actor); + + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); + + mo = P_SpawnXYZMissile(actor, actor->target, locvar1, actor->x, actor->y, z); + + if (mo) + mo->flags2 |= MF2_SUPERFIRE; + + if (!(actor->flags & MF_BOSS)) + { + if (ultimatemode) + actor->reactiontime = actor->info->reactiontime*TICRATE; + else + actor->reactiontime = actor->info->reactiontime*TICRATE*2; + } +} + +// Function: A_BossFireShot +// +// Description: Shoot an object at your target ala Bosses: +// +// var1 = object # to shoot +// var2: +// 0 - Boss 1 Left side +// 1 - Boss 1 Right side +// 2 - Boss 3 Left side upper +// 3 - Boss 3 Left side lower +// 4 - Boss 3 Right side upper +// 5 - Boss 3 Right side lower +// +void A_BossFireShot(mobj_t *actor) +{ + fixed_t x, y, z; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BossFireShot", actor)) + return; +#endif + if (!actor->target) + return; + + A_FaceTarget(actor); + + switch (locvar2) + { + case 0: + x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(48*FRACUNIT, actor->scale); + break; + case 1: + x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(48*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(48*FRACUNIT, actor->scale); + break; + case 2: + x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(42*FRACUNIT, actor->scale); + break; + case 3: + x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(30*FRACUNIT, actor->scale); + break; + case 4: + x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(56*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(42*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(42*FRACUNIT, actor->scale); + break; + case 5: + x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(58*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(30*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(30*FRACUNIT, actor->scale); + break; + default: + x = actor->x; + y = actor->y; + z = actor->z + actor->height/2; + break; + } + + P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z); +} + +// Function: A_Boss7FireMissiles +// +// Description: Shoot 4 missiles of a specific object type at your target ala Black Eggman +// +// var1 = object # to shoot +// var2 = firing sound +// +void A_Boss7FireMissiles(mobj_t *actor) +{ + mobj_t dummymo; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss7FireMissiles", actor)) + return; +#endif + + if (!actor->target) + { + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + A_FaceTarget(actor); + + S_StartSound(NULL, locvar2); + + // set dummymo's coordinates + dummymo.x = actor->target->x; + dummymo.y = actor->target->y; + dummymo.z = actor->target->z + FixedMul(16*FRACUNIT, actor->scale); // raised height + + P_SpawnXYZMissile(actor, &dummymo, locvar1, + actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->z + FixedDiv(actor->height, 3*FRACUNIT/2)); + + P_SpawnXYZMissile(actor, &dummymo, locvar1, + actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->z + FixedDiv(actor->height, 3*FRACUNIT/2)); + + P_SpawnXYZMissile(actor, &dummymo, locvar1, + actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->z + actor->height/2); + + P_SpawnXYZMissile(actor, &dummymo, locvar1, + actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedDiv(actor->radius, 3*FRACUNIT/2)+FixedMul(4*FRACUNIT, actor->scale)), + actor->z + actor->height/2); +} + +// Function: A_Boss1Laser +// +// Description: Shoot an object at your target ala Bosses: +// +// var1 = object # to shoot +// var2: +// 0 - Boss 1 Left side +// 1 - Boss 1 Right side +// +void A_Boss1Laser(mobj_t *actor) +{ + fixed_t x, y, z, floorz, speed; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + INT32 i; + angle_t angle; + mobj_t *point; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss1Laser", actor)) + return; +#endif + if (!actor->target) + return; + + switch (locvar2) + { + case 0: + x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height; + else + z = actor->z + FixedMul(56*FRACUNIT, actor->scale); + break; + case 1: + x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height; + else + z = actor->z + FixedMul(56*FRACUNIT, actor->scale); + break; + default: + x = actor->x; + y = actor->y; + z = actor->z + actor->height/2; + break; + } + + if (!(actor->flags2 & MF2_FIRING)) + { + actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); + if (mobjinfo[locvar1].seesound) + S_StartSound(actor, mobjinfo[locvar1].seesound); + if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) + { + point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); + point->angle = actor->angle; + point->fuse = actor->tics+1; + P_SetTarget(&point->target, actor->target); + P_SetTarget(&actor->target, point); + } + } + /* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path + else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) + actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/ + + if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH) + angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); + else + angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); + point = P_SpawnMobj(x, y, z, locvar1); + P_SetTarget(&point->target, actor); + point->angle = actor->angle; + speed = point->radius*2; + point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed); + point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed)); + point->momy = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINESINE(point->angle>>ANGLETOFINESHIFT), speed)); + + for (i = 0; i < 256; i++) + { + mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type); + mo->angle = point->angle; + P_UnsetThingPosition(mo); + mo->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY; + P_SetThingPosition(mo); + + x = point->x, y = point->y, z = point->z; + if (P_RailThinker(point)) + break; + } + + floorz = P_FloorzAtPos(x, y, z, mobjinfo[MT_EGGMOBILE_FIRE].height); + if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1) + { + point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE); + point->target = actor; + point->destscale = 3*FRACUNIT; + point->scalespeed = FRACUNIT>>2; + point->fuse = TICRATE; + } + + if (actor->tics > 1) + actor->flags2 |= MF2_FIRING; + else + actor->flags2 &= ~MF2_FIRING; +} + +// Function: A_FocusTarget +// +// Description: Home in on your target. +// +// var1: +// 0 - accelerative focus with friction +// 1 - steady focus with fixed movement speed +// anything else - don't move +// var2: +// 0 - don't trace target, just move forwards +// & 1 - change horizontal angle +// & 2 - change vertical angle +// +void A_FocusTarget(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FocusTarget", actor)) + return; +#endif + + if (actor->target) + { + fixed_t speed = FixedMul(actor->info->speed, actor->scale); + fixed_t dist = (locvar2 ? R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) : speed+1); + angle_t hangle = ((locvar2 & 1) ? R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) : actor->angle); + angle_t vangle = ((locvar2 & 2) ? R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist) : ANGLE_90); + switch(locvar1) + { + case 0: + { + actor->momx -= actor->momx>>4, actor->momy -= actor->momy>>4, actor->momz -= actor->momz>>4; + actor->momz += FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed); + actor->momx += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed)); + actor->momy += FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed)); + } + break; + case 1: + if (dist > speed) + { + actor->momz = FixedMul(FINECOSINE(vangle>>ANGLETOFINESHIFT), speed); + actor->momx = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hangle>>ANGLETOFINESHIFT), speed)); + actor->momy = FixedMul(FINESINE(vangle>>ANGLETOFINESHIFT), FixedMul(FINESINE(hangle>>ANGLETOFINESHIFT), speed)); + } + else + { + actor->momx = 0, actor->momy = 0, actor->momz = 0; + actor->z = actor->target->z + (actor->target->height>>1); + P_TryMove(actor, actor->target->x, actor->target->y, true); + } + break; + default: + break; + } + } +} + +// Function: A_Boss4Reverse +// +// Description: Reverse arms direction. +// +// var1 = sfx to play +// var2 = unused +// +void A_Boss4Reverse(mobj_t *actor) +{ + sfxenum_t locvar1 = (sfxenum_t)var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss4Reverse", actor)) + return; +#endif + S_StartSound(NULL, locvar1); + actor->reactiontime = 0; + if (actor->movedir == 1) + actor->movedir = 2; + else + actor->movedir = 1; +} + +// Function: A_Boss4SpeedUp +// +// Description: Speed up arms +// +// var1 = sfx to play +// var2 = unused +// +void A_Boss4SpeedUp(mobj_t *actor) +{ + sfxenum_t locvar1 = (sfxenum_t)var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss4SpeedUp", actor)) + return; +#endif + S_StartSound(NULL, locvar1); + actor->reactiontime = 2; +} + +// Function: A_Boss4Raise +// +// Description: Raise helmet +// +// var1 = sfx to play +// var2 = unused +// +void A_Boss4Raise(mobj_t *actor) +{ + sfxenum_t locvar1 = (sfxenum_t)var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss4Raise", actor)) + return; +#endif + S_StartSound(NULL, locvar1); + actor->reactiontime = 1; +} + +// Function: A_SkullAttack +// +// Description: Fly at the player like a missile. +// +// var1: +// 0 - Fly at the player +// 1 - Fly away from the player +// 2 - Strafe in relation to the player +// var2: +// 0 - Fly horizontally and vertically +// 1 - Fly horizontal-only (momz = 0) +// +#define SKULLSPEED (20*FRACUNIT) + +void A_SkullAttack(mobj_t *actor) +{ + mobj_t *dest; + angle_t an; + INT32 dist; + INT32 speed; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SkullAttack", actor)) + return; +#endif + if (!actor->target) + return; + + speed = FixedMul(SKULLSPEED, actor->scale); + + dest = actor->target; + actor->flags2 |= MF2_SKULLFLY; + if (actor->info->activesound) + S_StartSound(actor, actor->info->activesound); + A_FaceTarget(actor); + + if (locvar1 == 1) + actor->angle += ANGLE_180; + else if (locvar1 == 2) + actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90; + + an = actor->angle >> ANGLETOFINESHIFT; + + actor->momx = FixedMul(speed, FINECOSINE(an)); + actor->momy = FixedMul(speed, FINESINE(an)); + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + dist = dist / speed; + + if (dist < 1) + dist = 1; + + actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist; + + if (locvar1 == 1) + actor->momz = -actor->momz; + if (locvar2 == 1) + actor->momz = 0; +} + +// Function: A_BossZoom +// +// Description: Like A_SkullAttack, but used by Boss 1. +// +// var1 = unused +// var2 = unused +// +void A_BossZoom(mobj_t *actor) +{ + mobj_t *dest; + angle_t an; + INT32 dist; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BossZoom", actor)) + return; +#endif + if (!actor->target) + return; + + dest = actor->target; + actor->flags2 |= MF2_SKULLFLY; + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + A_FaceTarget(actor); + an = actor->angle >> ANGLETOFINESHIFT; + actor->momx = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINECOSINE(an)); + actor->momy = FixedMul(FixedMul(actor->info->speed*5*FRACUNIT, actor->scale), FINESINE(an)); + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + dist = dist / FixedMul(actor->info->speed*5*FRACUNIT, actor->scale); + + if (dist < 1) + dist = 1; + actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist; +} + +// Function: A_BossScream +// +// Description: Spawns explosions and plays appropriate sounds around the defeated boss. +// +// var1: +// 0 - Use movecount to spawn explosions evenly +// 1 - Use P_Random to spawn explosions at complete random +// var2 = Object to spawn. Default is MT_BOSSEXPLODE. +// +void A_BossScream(mobj_t *actor) +{ + mobj_t *mo; + fixed_t x, y, z; + angle_t fa; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobjtype_t explodetype; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BossScream", actor)) + return; +#endif + switch (locvar1) + { + default: + case 0: + actor->movecount += 4*16; + actor->movecount %= 360; + fa = (FixedAngle(actor->movecount*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; + break; + case 1: + fa = (FixedAngle(P_RandomKey(360)*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; + break; + } + x = actor->x + FixedMul(FINECOSINE(fa),actor->radius); + y = actor->y + FixedMul(FINESINE(fa),actor->radius); + + // Determine what mobj to spawn. If undefined or invalid, use MT_BOSSEXPLODE as default. + if (locvar2 <= 0 || locvar2 >= NUMMOBJTYPES) + explodetype = MT_BOSSEXPLODE; + else + explodetype = (mobjtype_t)locvar2; + + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - mobjinfo[explodetype].height - FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale); + + mo = P_SpawnMobj(x, y, z, explodetype); + if (actor->eflags & MFE_VERTICALFLIP) + mo->flags2 |= MF2_OBJECTFLIP; + mo->destscale = actor->scale; + P_SetScale(mo, mo->destscale); + if (actor->info->deathsound) + S_StartSound(mo, actor->info->deathsound); +} + +// Function: A_Scream +// +// Description: Starts the death sound of the object. +// +// var1 = unused +// var2 = unused +// +void A_Scream(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Scream", actor)) + return; +#endif + if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL)) + S_StartScreamSound(actor, sfx_mario2); + else if (actor->info->deathsound) + S_StartScreamSound(actor, actor->info->deathsound); +} + +// Function: A_Pain +// +// Description: Starts the pain sound of the object. +// +// var1 = unused +// var2 = unused +// +void A_Pain(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Pain", actor)) + return; +#endif + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); + + actor->flags2 &= ~MF2_FIRING; + actor->flags2 &= ~MF2_SUPERFIRE; +} + +// Function: A_Fall +// +// Description: Changes a dying object's flags to reflect its having fallen to the ground. +// +// var1 = unused +// var2 = unused +// +void A_Fall(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Fall", actor)) + return; +#endif + // actor is on ground, it can be walked over + actor->flags &= ~MF_SOLID; + + // fall through the floor + actor->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; + + // So change this if corpse objects + // are meant to be obstacles. +} + +#define LIVESBOXDISPLAYPLAYER // Use displayplayer instead of closest player + +// Function: A_1upThinker +// +// Description: Used by the 1up box to show the player's face. +// +// var1 = unused +// var2 = unused +// +void A_1upThinker(mobj_t *actor) +{ + INT32 i; + fixed_t dist = INT32_MAX; + fixed_t temp; + INT32 closestplayer = -1; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_1upThinker", actor)) + return; +#endif + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].bot || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + if ((netgame || multiplayer) && players[i].playerstate != PST_LIVE) + continue; + + temp = P_AproxDistance(players[i].mo->x-actor->x, players[i].mo->y-actor->y); + + if (temp < dist) + { + closestplayer = i; + dist = temp; + } + } + + if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0) + { // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite. + if (actor->tracer) { + P_RemoveMobj(actor->tracer); + actor->tracer = NULL; + } + return; + } + + // We're using the overlay, so use the overlay 1up box (no text) + actor->sprite = SPR_TV1P; + + if (!actor->tracer) + { + P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY)); + P_SetTarget(&actor->tracer->target, actor); + actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame + P_SetMobjState(actor->tracer, actor->info->seestate); + + // The overlay is going to be one tic early turning off and on + // because it's going to get its thinker run the frame we spawned it. + // So make it take one tic longer if it just spawned. + ++actor->tracer->tics; + } + + actor->tracer->color = players[closestplayer].mo->color; + actor->tracer->skin = &skins[players[closestplayer].skin]; +} + +// Function: A_MonitorPop +// +// Description: Used by monitors when they explode. +// +// var1 = unused +// var2 = unused +// +void A_MonitorPop(mobj_t *actor) +{ + mobjtype_t item = 0; + mobj_t *newmobj; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MonitorPop", actor)) + return; +#endif + + // Spawn the "pop" explosion. + if (actor->info->deathsound) + S_StartSound(actor, actor->info->deathsound); + P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_EXPLODE); + + // We're dead now. De-solidify. + actor->health = 0; + P_UnsetThingPosition(actor); + actor->flags &= ~MF_SOLID; + actor->flags |= MF_NOCLIP; + P_SetThingPosition(actor); + + if (actor->info->damage == MT_UNKNOWN) + { + // MT_UNKNOWN is random. Because it's unknown to us... get it? + item = P_DoRandomBoxChances(); + + if (item == MT_NULL) + { + CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n")); + return; + } + } + else + item = actor->info->damage; + + if (item == 0) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n"); + return; + } + + newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item); + P_SetTarget(&newmobj->target, actor->target); // Transfer target + + if (item == MT_1UP_ICON) + { + if (actor->tracer) // Remove the old lives icon. + P_RemoveMobj(actor->tracer); + + if (!newmobj->target + || !newmobj->target->player + || !newmobj->target->skin + || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) + {} // No lives icon for this player, use the default. + else + { // Spawn the lives icon. + mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&livesico->target, newmobj); + P_SetTarget(&newmobj->tracer, livesico); + + livesico->color = newmobj->target->player->mo->color; + livesico->skin = &skins[newmobj->target->player->skin]; + P_SetMobjState(livesico, newmobj->info->seestate); + + // We're using the overlay, so use the overlay 1up sprite (no text) + newmobj->sprite = SPR_TV1P; + } + } +} + +// Function: A_GoldMonitorPop +// +// Description: Used by repeating monitors when they turn off. They don't really pop, but, you know... +// +// var1 = unused +// var2 = unused +// +void A_GoldMonitorPop(mobj_t *actor) +{ + mobjtype_t item = 0; + mobj_t *newmobj; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GoldMonitorPop", actor)) + return; +#endif + + // Don't spawn the "pop" explosion, because the monitor isn't broken. + if (actor->info->deathsound) + S_StartSound(actor, actor->info->deathsound); + //P_SpawnMobjFromMobj(actor, 0, 0, actor.height/4, MT_EXPLODE); + + // Remove our flags for a bit. + // Players can now stand on top of us. + P_UnsetThingPosition(actor); + actor->flags &= ~(MF_MONITOR|MF_SHOOTABLE); + P_SetThingPosition(actor); + + // Don't count this box in statistics. Sorry. + if (actor->target && actor->target->player) + --actor->target->player->numboxes; + actor->fuse = 0; // Don't let the monitor code screw us up. + + if (actor->info->damage == MT_UNKNOWN) + { + // MT_UNKNOWN is random. Because it's unknown to us... get it? + item = P_DoRandomBoxChances(); + + if (item == MT_NULL) + { + CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n")); + return; + } + } + else + item = actor->info->damage; + + if (item == 0) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_GoldMonitorPop\n"); + return; + } + + // Note: the icon spawns 1 fracunit higher + newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 14*FRACUNIT, item); + P_SetTarget(&newmobj->target, actor->target); // Transfer target + + if (item == MT_1UP_ICON) + { + if (actor->tracer) // Remove the old lives icon. + P_RemoveMobj(actor->tracer); + + if (!newmobj->target + || !newmobj->target->player + || !newmobj->target->skin + || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) + {} // No lives icon for this player, use the default. + else + { // Spawn the lives icon. + mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&livesico->target, newmobj); + P_SetTarget(&newmobj->tracer, livesico); + + livesico->color = newmobj->target->player->mo->color; + livesico->skin = &skins[newmobj->target->player->skin]; + P_SetMobjState(livesico, newmobj->info->seestate); + + // We're using the overlay, so use the overlay 1up sprite (no text) + newmobj->sprite = SPR_TV1P; + } + } +} + +// Function: A_GoldMonitorRestore +// +// Description: A repeating monitor is coming back to life. Reset monitor flags, etc. +// +// var1 = unused +// var2 = unused +// +void A_GoldMonitorRestore(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GoldMonitorRestore", actor)) + return; +#endif + + actor->flags |= MF_MONITOR|MF_SHOOTABLE; + actor->health = 1; // Just in case. +} + +// Function: A_GoldMonitorSparkle +// +// Description: Spawns the little sparkly effect around big monitors. Looks pretty, doesn't it? +// +// var1 = unused +// var2 = unused +// +void A_GoldMonitorSparkle(mobj_t *actor) +{ + fixed_t i, ngangle, xofs, yofs; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GoldMonitorSparkle", actor)) + return; +#endif + + ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS); + xofs = FINESINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); + yofs = FINECOSINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); + + for (i = FRACUNIT*2; i <= FRACUNIT*3; i += FRACUNIT/2) + P_SetObjectMomZ(P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE), i, false); +} + +// Function: A_Explode +// +// Description: Explodes an object, doing damage to any objects nearby. The target is used as the cause of the explosion. Damage value is used as explosion range. +// +// var1 = damagetype +// var2 = unused +// +void A_Explode(mobj_t *actor) +{ + INT32 locvar1 = var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Explode", actor)) + return; +#endif + P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1); +} + +// Function: A_BossDeath +// +// Description: Possibly trigger special effects when boss dies. +// +// var1 = unused +// var2 = unused +// +void A_BossDeath(mobj_t *mo) +{ + thinker_t *th; + mobj_t *mo2; + line_t junk; + INT32 i; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BossDeath", mo)) + return; +#endif + + P_LinedefExecute(LE_BOSSDEAD, mo, NULL); + mo->health = 0; + + // Boss is dead (but not necessarily fleeing...) + // Lua may use this to ignore bosses after they start fleeing + mo->flags2 |= MF2_BOSSDEAD; + + // make sure there is a player alive for victory + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && ((players[i].mo && players[i].mo->health) + || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) + break; + + if (i == MAXPLAYERS) + return; // no one left alive, so do not end game + + // scan the remaining thinkers to see + // if all bosses are dead + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + if (mo2 != mo && (mo2->flags & MF_BOSS) && mo2->health > 0) + goto bossjustdie; // other boss not dead - just go straight to dying! + } + + // victory! + P_LinedefExecute(LE_ALLBOSSESDEAD, mo, NULL); + if (mo->flags2 & MF2_BOSSNOTRAP) + { + for (i = 0; i < MAXPLAYERS; i++) + P_DoPlayerExit(&players[i]); + } + else + { + // Bring the egg trap up to the surface + junk.tag = 680; + EV_DoElevator(&junk, elevateHighest, false); + junk.tag = 681; + EV_DoElevator(&junk, elevateUp, false); + junk.tag = 682; + EV_DoElevator(&junk, elevateHighest, false); + } + +bossjustdie: +#ifdef HAVE_BLUA + if (LUAh_BossDeath(mo)) + return; + else if (P_MobjWasRemoved(mo)) + return; +#endif + if (mo->type == MT_BLACKEGGMAN || mo->type == MT_CYBRAKDEMON) + { + mo->flags |= MF_NOCLIP; + mo->flags &= ~MF_SPECIAL; + + S_StartSound(NULL, sfx_befall); + } + else if (mo->type == MT_KOOPA) + { + junk.tag = 650; + EV_DoCeiling(&junk, raiseToHighest); + return; + } + else // eggmobiles + { + // Stop exploding and prepare to run. + P_SetMobjState(mo, mo->info->xdeathstate); + if (P_MobjWasRemoved(mo)) + return; + + P_SetTarget(&mo->target, NULL); + + // Flee! Flee! Find a point to escape to! If none, just shoot upward! + // scan the thinkers to find the runaway point + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type == MT_BOSSFLYPOINT) + { + // If this one's closer then the last one, go for it. + if (!mo->target || + P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) < + P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z)) + P_SetTarget(&mo->target, mo2); + // Otherwise... Don't! + } + } + + mo->flags |= MF_NOGRAVITY|MF_NOCLIP; + mo->flags |= MF_NOCLIPHEIGHT; + + if (mo->target) + { + mo->angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y); + mo->flags2 |= MF2_BOSSFLEE; + mo->momz = FixedMul(FixedDiv(mo->target->z - mo->z, P_AproxDistance(mo->x-mo->target->x,mo->y-mo->target->y)), FixedMul(2*FRACUNIT, mo->scale)); + } + else + mo->momz = FixedMul(2*FRACUNIT, mo->scale); + } + + if (mo->type == MT_EGGMOBILE2) + { + mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), + mo->y + P_ReturnThrustY(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), + mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK1].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK1); // Right tank + mo2->angle = mo->angle; + mo2->destscale = mo->scale; + P_SetScale(mo2, mo2->destscale); + if (mo->eflags & MFE_VERTICALFLIP) + { + mo2->eflags |= MFE_VERTICALFLIP; + mo2->flags2 |= MF2_OBJECTFLIP; + } + P_InstaThrust(mo2, mo2->angle - ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale)); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + + mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), + mo->y + P_ReturnThrustY(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), + mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK2].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK2); // Left tank + mo2->angle = mo->angle; + mo2->destscale = mo->scale; + P_SetScale(mo2, mo2->destscale); + if (mo->eflags & MFE_VERTICALFLIP) + { + mo2->eflags |= MFE_VERTICALFLIP; + mo2->flags2 |= MF2_OBJECTFLIP; + } + P_InstaThrust(mo2, mo2->angle + ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale)); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + + mo2 = P_SpawnMobj(mo->x, mo->y, + mo->z + ((mo->eflags & MFE_VERTICALFLIP)? mobjinfo[MT_BOSSSPIGOT].height-FixedMul(32*FRACUNIT,mo->scale): mo->height + FixedMul(32*FRACUNIT, mo->scale)), MT_BOSSSPIGOT); + mo2->angle = mo->angle; + mo2->destscale = mo->scale; + P_SetScale(mo2, mo2->destscale); + if (mo->eflags & MFE_VERTICALFLIP) + { + mo2->eflags |= MFE_VERTICALFLIP; + mo2->flags2 |= MF2_OBJECTFLIP; + } + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + return; + } +} + +// Function: A_CustomPower +// +// Description: Provides a custom powerup. Target (must be a player) is awarded the powerup. Reactiontime of the object is used as an index to the powers array. +// +// var1 = Power index # +// var2 = Power duration in tics +// +void A_CustomPower(mobj_t *actor) +{ + player_t *player; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + boolean spawnshield = false; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CustomPower", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + if (locvar1 >= NUMPOWERS) + { + CONS_Debug(DBG_GAMELOGIC, "Power #%d out of range!\n", locvar1); + return; + } + + player = actor->target->player; + + if (locvar1 == pw_shield && player->powers[pw_shield] != locvar2) + spawnshield = true; + + player->powers[locvar1] = (UINT16)locvar2; + if (actor->info->seesound) + S_StartSound(player->mo, actor->info->seesound); + + if (spawnshield) //workaround for a bug + P_SpawnShieldOrb(player); +} + +// Function: A_GiveWeapon +// +// Description: Gives the player the specified weapon panels. +// +// var1 = Weapon index # +// var2 = unused +// +void A_GiveWeapon(mobj_t *actor) +{ + player_t *player; + INT32 locvar1 = var1; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GiveWeapon", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + if (locvar1 >= 1<<(NUM_WEAPONS-1)) + { + CONS_Debug(DBG_GAMELOGIC, "Weapon #%d out of range!\n", locvar1); + return; + } + + player = actor->target->player; + + player->ringweapons |= locvar1; + if (actor->info->seesound) + S_StartSound(player->mo, actor->info->seesound); +} + +// Function: A_RingBox +// +// Description: Awards the player 10 rings. +// +// var1 = unused +// var2 = unused +// +void A_RingBox(mobj_t *actor) +{ + player_t *player; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RingBox", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + player = actor->target->player; + + P_GivePlayerRings(player, actor->info->reactiontime); + if (actor->info->seesound) + S_StartSound(player->mo, actor->info->seesound); +} + +// Function: A_Invincibility +// +// Description: Awards the player invincibility. +// +// var1 = unused +// var2 = unused +// +void A_Invincibility(mobj_t *actor) +{ + player_t *player; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Invincibility", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + player = actor->target->player; + player->powers[pw_invulnerability] = invulntics + 1; + + if (P_IsLocalPlayer(player) && !player->powers[pw_super]) + { + S_StopMusic(); + if (mariomode) + G_GhostAddColor(GHC_INVINCIBLE); + strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14); + S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]); + S_ChangeMusicInternal((mariomode) ? "_minv" : "_inv", false); + } +} + +// Function: A_SuperSneakers +// +// Description: Awards the player super sneakers. +// +// var1 = unused +// var2 = unused +// +void A_SuperSneakers(mobj_t *actor) +{ + player_t *player; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SuperSneakers", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + player = actor->target->player; + + actor->target->player->powers[pw_sneakers] = sneakertics + 1; + + if (P_IsLocalPlayer(player) && !player->powers[pw_super]) + { + if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)) + S_SpeedMusic(1.4f); + else + { + S_StopMusic(); + S_ChangeMusicInternal("_shoes", false); + } + strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12); + S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]); + } +} + +// Function: A_AwardScore +// +// Description: Adds a set amount of points to the player's score. +// +// var1 = unused +// var2 = unused +// +void A_AwardScore(mobj_t *actor) +{ + player_t *player; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_AwardScore", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + player = actor->target->player; + + P_AddPlayerScore(player, actor->info->reactiontime); + if (actor->info->seesound) + S_StartSound(player->mo, actor->info->seesound); +} + +// Function: A_ExtraLife +// +// Description: Awards the player an extra life. +// +// var1 = unused +// var2 = unused +// +void A_ExtraLife(mobj_t *actor) +{ + player_t *player; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ExtraLife", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + player = actor->target->player; + + if (actor->type == MT_1UP_ICON && actor->tracer) + { + // We're using the overlay, so use the overlay 1up sprite (no text) + actor->sprite = SPR_TV1P; + } + + if (ultimatemode) //I don't THINK so! + { + S_StartSound(player->mo, sfx_lose); + return; + } + + P_GiveCoopLives(player, 1, true); +} + +// Function: A_GiveShield +// +// Description: Awards the player a specified shield. +// +// var1 = Shield type (make with SH_ constants) +// var2 = unused +// +void A_GiveShield(mobj_t *actor) +{ + player_t *player; + UINT16 locvar1 = var1; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GiveShield", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + player = actor->target->player; + + P_SwitchShield(player, locvar1); + S_StartSound(player->mo, actor->info->seesound); +} + +// Function: A_GravityBox +// +// Description: Awards the player gravity boots. +// +// var1 = unused +// var2 = unused +// +void A_GravityBox(mobj_t *actor) +{ + player_t *player; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GravityBox", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + player = actor->target->player; + + S_StartSound(player, actor->info->activesound); + + player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1); +} + +// Function: A_ScoreRise +// +// Description: Makes the little score logos rise. Speed value sets speed. +// +// var1 = unused +// var2 = unused +// +void A_ScoreRise(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ScoreRise", actor)) + return; +#endif + // make logo rise! + P_SetObjectMomZ(actor, actor->info->speed, false); +} + +// Function: A_ParticleSpawn +// +// Description: Hyper-specialised function for spawning a particle for MT_PARTICLEGEN. +// +// var1 = unused +// var2 = unused +// +void A_ParticleSpawn(mobj_t *actor) +{ + INT32 i = 0; + mobj_t *spawn; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ParticleSpawn", actor)) + return; +#endif + if (!actor->health) + return; + + if (!actor->lastlook) + return; + + if (!actor->threshold) + return; + + for (i = 0; i < actor->lastlook; i++) + { + spawn = P_SpawnMobj( + actor->x + FixedMul(FixedMul(actor->friction, actor->scale), FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), + actor->y + FixedMul(FixedMul(actor->friction, actor->scale), FINESINE(actor->angle>>ANGLETOFINESHIFT)), + actor->z, + (mobjtype_t)actor->threshold); + P_SetScale(spawn, actor->scale); + spawn->momz = FixedMul(actor->movefactor, spawn->scale); + spawn->destscale = spawn->scale/100; + spawn->scalespeed = spawn->scale/actor->health; + spawn->tics = (tic_t)actor->health; + spawn->flags2 |= (actor->flags2 & MF2_OBJECTFLIP); + spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + + actor->angle += actor->movedir; + } + + actor->angle += (angle_t)actor->movecount; + actor->tics = (tic_t)actor->reactiontime; +} + +// Function: A_BunnyHop +// +// Description: Makes object hop like a bunny. +// +// var1 = jump strength +// var2 = horizontal movement +// +void A_BunnyHop(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BunnyHop", actor)) + return; +#endif + if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) + || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) + { + P_SetObjectMomZ(actor, locvar1*FRACUNIT, false); + P_InstaThrust(actor, actor->angle, FixedMul(locvar2*FRACUNIT, actor->scale)); // Launch the hopping action! PHOOM!! + } +} + +// Function: A_BubbleSpawn +// +// Description: Spawns a randomly sized bubble from the object's location. Only works underwater. +// +// var1 = Distance to look for players. If no player is in this distance, bubbles aren't spawned. (Ambush overrides) +// var2 = unused +// +void A_BubbleSpawn(mobj_t *actor) +{ + INT32 i, locvar1 = var1; + UINT8 prandom; + mobj_t *bubble = NULL; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BubbleSpawn", actor)) + return; +#endif + if (!(actor->eflags & MFE_UNDERWATER)) + { + // Don't draw or spawn bubbles above water + actor->flags2 |= MF2_DONTDRAW; + return; + } + actor->flags2 &= ~MF2_DONTDRAW; + + if (!(actor->flags2 & MF2_AMBUSH)) + { + // Quick! Look through players! + // Don't spawn bubbles unless a player is relatively close by (var1). + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].mo + && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<x, actor->y, actor->z + (actor->height / 2), MT_EXTRALARGEBUBBLE); + else if (prandom > 128) + bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_SMALLBUBBLE); + else if (prandom < 128 && prandom > 96) + bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_MEDIUMBUBBLE); + + if (bubble) + { + bubble->destscale = actor->scale; + P_SetScale(bubble, actor->scale); + } +} + +// Function: A_FanBubbleSpawn +// +// Description: Spawns bubbles from fans, if they're underwater. +// +// var1 = Distance to look for players. If no player is in this distance, bubbles aren't spawned. (Ambush overrides) +// var2 = unused +// +void A_FanBubbleSpawn(mobj_t *actor) +{ + INT32 i, locvar1 = var1; + UINT8 prandom; + mobj_t *bubble = NULL; + fixed_t hz = actor->z + (4*actor->height)/5; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FanBubbleSpawn", actor)) + return; +#endif + if (!(actor->eflags & MFE_UNDERWATER)) + return; + + if (!(actor->flags2 & MF2_AMBUSH)) + { + // Quick! Look through players! + // Don't spawn bubbles unless a player is relatively close by (var2). + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].mo + && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (locvar1<x, actor->y, hz, MT_SMALLBUBBLE); + else if ((prandom & 0xF0) == 0xF0) + bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_MEDIUMBUBBLE); + + if (bubble) + { + bubble->destscale = actor->scale; + P_SetScale(bubble, actor->scale); + } +} + +// Function: A_BubbleRise +// +// Description: Raises a bubble +// +// var1: +// 0 = Bend around the water abit, looking more realistic +// 1 = Rise straight up +// var2 = rising speed +// +void A_BubbleRise(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BubbleRise", actor)) + return; +#endif + if (actor->type == MT_EXTRALARGEBUBBLE) + P_SetObjectMomZ(actor, FixedDiv(6*FRACUNIT,5*FRACUNIT), false); // make bubbles rise! + else + { + P_SetObjectMomZ(actor, locvar2, true); // make bubbles rise! + + // Move around slightly to make it look like it's bending around the water + if (!locvar1) + { + UINT8 prandom = P_RandomByte(); + if (!(prandom & 0x7)) // *****000 + { + P_InstaThrust(actor, prandom & 0x70 ? actor->angle + ANGLE_90 : actor->angle, + FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale)); + } + else if (!(prandom & 0x38)) // **000*** + { + P_InstaThrust(actor, prandom & 0x70 ? actor->angle - ANGLE_90 : actor->angle - ANGLE_180, + FixedMul(prandom & 0xF0 ? FRACUNIT/2 : -FRACUNIT/2, actor->scale)); + } + } + } +} + +// Function: A_BubbleCheck +// +// Description: Checks if a bubble should be drawn or not. Bubbles are not drawn above water. +// +// var1 = unused +// var2 = unused +// +void A_BubbleCheck(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BubbleCheck", actor)) + return; +#endif + if (actor->eflags & MFE_UNDERWATER) + actor->flags2 &= ~MF2_DONTDRAW; // underwater so draw + else + actor->flags2 |= MF2_DONTDRAW; // above water so don't draw +} + +// Function: A_AttractChase +// +// Description: Makes a ring chase after a player with a ring shield and also causes spilled rings to flicker. +// +// var1 = unused +// var2 = unused +// +void A_AttractChase(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_AttractChase", actor)) + return; +#endif + if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) + return; + + // spilled rings flicker before disappearing + if (leveltime & 1 && actor->type == (mobjtype_t)actor->info->reactiontime && actor->fuse && actor->fuse < 2*TICRATE) + actor->flags2 |= MF2_DONTDRAW; + else + actor->flags2 &= ~MF2_DONTDRAW; + + // Turn flingrings back into regular rings if attracted. + if (actor->tracer && actor->tracer->player + && !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) + { + mobj_t *newring; + newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); + newring->momx = actor->momx; + newring->momy = actor->momy; + newring->momz = actor->momz; + P_RemoveMobj(actor); + return; + } + + P_LookForShield(actor); // Go find 'em, boy! + + if (!actor->tracer + || !actor->tracer->player + || !actor->tracer->health + || !P_CheckSight(actor, actor->tracer)) // You have to be able to SEE it...sorta + { + // Lost attracted rings don't through walls anymore. + actor->flags &= ~MF_NOCLIP; + P_SetTarget(&actor->tracer, NULL); + return; + } + + // If a FlingRing gets attracted by a shield, change it into a normal ring. + if (actor->type == (mobjtype_t)actor->info->reactiontime) + { + P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); + P_RemoveMobj(actor); + return; + } + + // Keep stuff from going down inside floors and junk + actor->flags &= ~MF_NOCLIPHEIGHT; + + // Let attracted rings move through walls and such. + actor->flags |= MF_NOCLIP; + + P_Attract(actor, actor->tracer, false); +} + +// Function: A_DropMine +// +// Description: Drops a mine. Raisestate specifies the object # to use for the mine. +// +// var1 = height offset +// var2: +// lower 16 bits = proximity check distance (0 disables) +// upper 16 bits = 0 to check proximity with target, 1 for tracer +// +void A_DropMine(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t z; + mobj_t *mine; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_DropMine", actor)) + return; +#endif + + if (locvar2 & 65535) + { + fixed_t dist; + mobj_t *target; + + if (locvar2 >> 16) + target = actor->tracer; + else + target = actor->target; + + if (!target) + return; + + dist = P_AproxDistance(actor->x-target->x, actor->y-target->y)>>FRACBITS; + + if (dist > FixedMul((locvar2 & 65535), actor->scale)) + return; + } + + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - mobjinfo[actor->info->raisestate].height - FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul((locvar1*FRACUNIT) - 12*FRACUNIT, actor->scale); + + // Use raisestate instead of MT_MINE + mine = P_SpawnMobj(actor->x, actor->y, z, (mobjtype_t)actor->info->raisestate); + if (actor->eflags & MFE_VERTICALFLIP) + mine->eflags |= MFE_VERTICALFLIP; + mine->momz = actor->momz + actor->pmomz; + + S_StartSound(actor, actor->info->attacksound); +} + +// Function: A_FishJump +// +// Description: Makes the stupid harmless fish in Greenflower Zone jump. +// +// var1 = Jump strength (in FRACBITS), if specified. Otherwise, uses the angle value. +// var2 = unused +// +void A_FishJump(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FishJump", actor)) + return; +#endif + + if (locvar2) + { + fixed_t rad = actor->radius>>FRACBITS; + P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale))) + { + fixed_t jumpval; + + if (locvar1) + jumpval = var1; + else + jumpval = FixedMul(AngleFixed(actor->angle)/4, actor->scale); + + if (!jumpval) jumpval = FixedMul(44*(FRACUNIT/4), actor->scale); + actor->momz = jumpval; + P_SetMobjStateNF(actor, actor->info->seestate); + } + + if (actor->momz < 0 + && (actor->state < &states[actor->info->meleestate] || actor->state > &states[actor->info->xdeathstate])) + P_SetMobjStateNF(actor, actor->info->meleestate); +} + +// Function:A_ThrownRing +// +// Description: Thinker for thrown rings/sparkle trail +// +// var1 = unused +// var2 = unused +// +void A_ThrownRing(mobj_t *actor) +{ + INT32 c = 0; + INT32 stop; + player_t *player; + fixed_t dist; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ThrownRing", actor)) + return; +#endif + + if (leveltime % (TICRATE/7) == 0) + { + mobj_t *ring = NULL; + + if (actor->flags2 & MF2_EXPLOSION) + { + if (actor->momx != 0 || actor->momy != 0) + ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOKE); + // Else spawn nothing because it's totally stationary and constantly smoking would be weird -SH + } + else if (actor->flags2 & MF2_AUTOMATIC) + ring = P_SpawnGhostMobj(actor); + else if (!(actor->flags2 & MF2_RAILRING)) + ring = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPARK); + + if (ring) + { + /* + P_SetTarget(&ring->target, actor); + ring->color = actor->color; //copy color + */ + ring->destscale = actor->scale; + P_SetScale(ring, actor->scale); + } + } + + // A_GrenadeRing beeping lives once moooooore -SH + if (actor->type == MT_THROWNGRENADE && actor->fuse % TICRATE == 0) + S_StartSound(actor, actor->info->attacksound); + + // decrement bounce ring time + if (actor->flags2 & MF2_BOUNCERING) + { + if (actor->fuse) + actor->fuse--; + else { + P_RemoveMobj(actor); + return; + } + } + + // spilled rings (and thrown bounce) flicker before disappearing + if (leveltime & 1 && actor->fuse > 0 && actor->fuse < 2*TICRATE + && actor->type != MT_THROWNGRENADE) + actor->flags2 |= MF2_DONTDRAW; + else + actor->flags2 &= ~MF2_DONTDRAW; + + if (actor->tracer && actor->tracer->health <= 0) + P_SetTarget(&actor->tracer, NULL); + + // Updated homing ring special capability + // If you have a ring shield, all rings thrown + // at you become homing (except rail)! + if (actor->tracer) + { + // A non-homing ring getting attracted by a + // magnetic player. If he gets too far away, make + // sure to stop the attraction! + if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) + && P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x, + actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale))) + { + P_SetTarget(&actor->tracer, NULL); + } + + if (actor->tracer && (actor->tracer->health) + && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow. + { + const INT32 temp = actor->threshold; + actor->threshold = 32000; + P_HomingAttack(actor, actor->tracer); + actor->threshold = temp; + return; + } + } + + // first time init, this allow minimum lastlook changes + if (actor->lastlook < 0) + actor->lastlook = P_RandomByte(); + + actor->lastlook %= MAXPLAYERS; + + stop = (actor->lastlook - 1) & PLAYERSMASK; + + for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK) + { + // done looking + if (actor->lastlook == stop) + return; + + if (!playeringame[actor->lastlook]) + continue; + + if (c++ == 2) + return; + + player = &players[actor->lastlook]; + + if (!player->mo) + continue; + + if (player->mo->health <= 0) + continue; // dead + + if ((netgame || multiplayer) && player->spectator) + continue; // spectator + + if (actor->target && actor->target->player) + { + if (player->mo == actor->target) + continue; + + // Don't home in on teammates. + if (gametype == GT_CTF + && actor->target->player->ctfteam == player->ctfteam) + continue; + } + + dist = P_AproxDistance(P_AproxDistance(player->mo->x-actor->x, + player->mo->y-actor->y), player->mo->z-actor->z); + + // check distance + if (actor->flags2 & MF2_RAILRING) + { + if (dist > FixedMul(RING_DIST/2, player->mo->scale)) + continue; + } + else if (dist > FixedMul(RING_DIST, player->mo->scale)) + continue; + + // do this after distance check because it's more computationally expensive + if (!P_CheckSight(actor, player->mo)) + continue; // out of sight + + if ((player->powers[pw_shield] & SH_PROTECTELECTRIC) + && dist < FixedMul(RING_DIST/4, player->mo->scale)) + P_SetTarget(&actor->tracer, player->mo); + return; + } + + return; +} + +// Function: A_SetSolidSteam +// +// Description: Makes steam solid so it collides with the player to boost them. +// +// var1 = unused +// var2 = unused +// +void A_SetSolidSteam(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetSolidSteam", actor)) + return; +#endif + actor->flags &= ~MF_NOCLIP; + actor->flags |= MF_SOLID; + if (!(actor->flags2 & MF2_AMBUSH)) + { + if (P_RandomChance(FRACUNIT/8)) + { + if (actor->info->deathsound) + S_StartSound(actor, actor->info->deathsound); // Hiss! + } + else + { + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); + } + } + + P_SetObjectMomZ (actor, 1, true); +} + +// Function: A_UnsetSolidSteam +// +// Description: Makes an object non-solid and also noclip. Used by the steam. +// +// var1 = unused +// var2 = unused +// +void A_UnsetSolidSteam(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_UnsetSolidSteam", actor)) + return; +#endif + actor->flags &= ~MF_SOLID; + actor->flags |= MF_NOCLIP; +} + +// Function: A_SignPlayer +// +// Description: Changes the state of a level end sign to reflect the player that hit it. +// +// var1 = unused +// var2 = unused +// +void A_SignPlayer(mobj_t *actor) +{ + mobj_t *ov; + skin_t *skin; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SignPlayer", actor)) + return; +#endif + if (!actor->target) + return; + + if (!actor->target->player) + return; + + skin = &skins[actor->target->player->skin]; + + if ((actor->target->player->skincolor == skin->prefcolor) && (skin->prefoppositecolor)) // Set it as the skin's preferred oppositecolor? + { + actor->color = skin->prefoppositecolor; + /* + If you're here from the comment above Color_Opposite, + the following line is the one which is dependent on the + array being symmetrical. It gets the opposite of the + opposite of your desired colour just so it can get the + brightness frame for the End Sign. It's not a great + design choice, but it's constant time array access and + the idea that the colours should be OPPOSITES is kind + of in the name. If you have a better idea, feel free + to let me know. ~toast 2016/07/20 + */ + actor->frame += (15 - Color_Opposite[(Color_Opposite[(skin->prefoppositecolor - 1)*2] - 1)*2 + 1]); + } + else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor. + { + actor->color = Color_Opposite[(actor->target->player->skincolor - 1)*2]; + actor->frame += (15 - Color_Opposite[(actor->target->player->skincolor - 1)*2 + 1]); + } + + if (skin->sprites[SPR2_SIGN].numframes) + { + // spawn an overlay of the player's face. + ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY); + P_SetTarget(&ov->target, actor); + ov->color = actor->target->player->skincolor; + ov->skin = skin; + P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN + } +} + +// Function: A_OverlayThink +// +// Description: Moves the overlay to the position of its target. +// +// var1 = unused +// var2 = invert, z offset +// +void A_OverlayThink(mobj_t *actor) +{ + fixed_t destx, desty; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_OverlayThink", actor)) + return; +#endif + if (!actor->target) + return; + + if (!splitscreen && rendermode != render_soft) + { + angle_t viewingangle; + + if (players[displayplayer].awayviewtics) + viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); + else if (!camera.chase && players[displayplayer].mo) + viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); + else + viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, camera.x, camera.y); + + destx = actor->target->x + P_ReturnThrustX(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale)); + desty = actor->target->y + P_ReturnThrustY(actor->target, viewingangle, FixedMul(FRACUNIT, actor->scale)); + } + else + { + destx = actor->target->x; + desty = actor->target->y; + } + P_UnsetThingPosition(actor); + actor->x = destx; + actor->y = desty; + P_SetThingPosition(actor); + if (actor->eflags & MFE_VERTICALFLIP) + actor->z = actor->target->z + actor->target->height - mobjinfo[actor->type].height - ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; + else + actor->z = actor->target->z + ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; + actor->angle = actor->target->angle; + actor->eflags = actor->target->eflags; + + actor->momx = actor->target->momx; + actor->momy = actor->target->momy; + actor->momz = actor->target->momz; // assume target has correct momz! Do not use P_SetObjectMomZ! +} + +// Function: A_JetChase +// +// Description: A_Chase for Jettysyns +// +// var1 = unused +// var2 = unused +// +void A_JetChase(mobj_t *actor) +{ + fixed_t thefloor; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetChase", actor)) + return; +#endif + + if (actor->flags2 & MF2_AMBUSH) + return; + + if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz + && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) + thefloor = actor->watertop; + else + thefloor = actor->floorz; + + if (actor->reactiontime) + actor->reactiontime--; + + if (P_RandomChance(FRACUNIT/32)) + { + actor->momx = actor->momx / 2; + actor->momy = actor->momy / 2; + actor->momz = actor->momz / 2; + } + + // Bounce if too close to floor or ceiling - + // ideal for Jetty-Syns above you on 3d floors + if (actor->momz && ((actor->z - FixedMul((32<scale)) < thefloor) && !((thefloor + FixedMul(32*FRACUNIT, actor->scale) + actor->height) > actor->ceilingz)) + actor->momz = -actor->momz/2; + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + actor->momx = actor->momy = actor->momz = 0; + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + // modify target threshold + if (actor->threshold) + { + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + // turn towards movement direction if not there yet + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + + if ((multiplayer || netgame) && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target))) + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + // If the player is over 3072 fracunits away, then look for another player + if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), + actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale))) + { + return; // got a new target + } + + // chase towards player + if (ultimatemode) + P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/2, actor->scale)); + else + P_Thrust(actor, actor->angle, FixedMul(actor->info->speed/4, actor->scale)); + + // must adjust height + if (ultimatemode) + { + if (actor->z < (actor->target->z + actor->target->height + FixedMul((64<scale))) + actor->momz += FixedMul(FRACUNIT/2, actor->scale); + else + actor->momz -= FixedMul(FRACUNIT/2, actor->scale); + } + else + { + if (actor->z < (actor->target->z + actor->target->height + FixedMul((32<scale))) + actor->momz += FixedMul(FRACUNIT/2, actor->scale); + else + actor->momz -= FixedMul(FRACUNIT/2, actor->scale); + } +} + +// Function: A_JetbThink +// +// Description: Thinker for Jetty-Syn bombers +// +// var1 = unused +// var2 = unused +// +void A_JetbThink(mobj_t *actor) +{ + sector_t *nextsector; + fixed_t thefloor; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetbThink", actor)) + return; +#endif + + if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz + && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) + thefloor = actor->watertop; + else + thefloor = actor->floorz; + + if (actor->target) + { + A_JetChase(actor); + // check for melee attack + if (actor->info->raisestate + && (actor->z > (actor->floorz + FixedMul((32<scale))) + && P_JetbCheckMeleeRange(actor) && !actor->reactiontime + && (actor->target->z >= actor->floorz)) + { + mobj_t *bomb; + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + + // use raisestate instead of MT_MINE + bomb = P_SpawnMobj(actor->x, actor->y, actor->z - FixedMul((32<scale), (mobjtype_t)actor->info->raisestate); + + P_SetTarget(&bomb->target, actor); + bomb->destscale = actor->scale; + P_SetScale(bomb, actor->scale); + actor->reactiontime = TICRATE; // one second + S_StartSound(actor, actor->info->attacksound); + } + } + else if (((actor->z - FixedMul((32<scale)) < thefloor) && !((thefloor + FixedMul((32<scale) + actor->height) > actor->ceilingz)) + actor->z = thefloor+FixedMul((32<scale); + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector; + + // Move downwards or upwards to go through a passageway. + if (nextsector->ceilingheight < actor->z + actor->height) + actor->momz -= FixedMul(5*FRACUNIT, actor->scale); + else if (nextsector->floorheight > actor->z) + actor->momz += FixedMul(5*FRACUNIT, actor->scale); +} + +// Function: A_JetgShoot +// +// Description: Firing function for Jetty-Syn gunners. +// +// var1 = unused +// var2 = unused +// +void A_JetgShoot(mobj_t *actor) +{ + fixed_t dist; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetgShoot", actor)) + return; +#endif + + if (!actor->target) + return; + + if (actor->reactiontime) + return; + + dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); + + if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale)) + return; + + if (dist < FixedMul(64*FRACUNIT, actor->scale)) + return; + + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate); + + if (ultimatemode) + actor->reactiontime = actor->info->reactiontime*TICRATE; + else + actor->reactiontime = actor->info->reactiontime*TICRATE*2; + + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); +} + +// Function: A_ShootBullet +// +// Description: Shoots a bullet. Raisestate defines object # to use as projectile. +// +// var1 = unused +// var2 = unused +// +void A_ShootBullet(mobj_t *actor) +{ + fixed_t dist; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ShootBullet", actor)) + return; +#endif + + if (!actor->target) + return; + + dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z); + + if (dist > FixedMul(actor->info->painchance*FRACUNIT, actor->scale)) + return; + + A_FaceTarget(actor); + P_SpawnMissile(actor, actor->target, (mobjtype_t)actor->info->raisestate); + + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); +} + +// Function: A_MinusDigging +// +// Description: Minus digging in the ground. +// +// var1 = unused +// var2 = unused +// +void A_MinusDigging(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MinusDigging", actor)) + return; +#endif + actor->flags &= ~MF_SPECIAL; + actor->flags &= ~MF_SHOOTABLE; + + if (!actor->target) + { + A_Look(actor); + return; + } + + if (actor->reactiontime) + { + actor->reactiontime--; + return; + } + + // Dirt trail + P_SpawnGhostMobj(actor); + + actor->flags |= MF_NOCLIPTHING; + var1 = 3; + A_Chase(actor); + actor->flags &= ~MF_NOCLIPTHING; + + // Play digging sound + if (!(leveltime & 15)) + S_StartSound(actor, actor->info->activesound); + + // If we're close enough to our target, pop out of the ground + if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < actor->radius + && abs(actor->target->z - actor->z) < 2*actor->height) + P_SetMobjState(actor, actor->info->missilestate); + + // Snap to ground + if (actor->eflags & MFE_VERTICALFLIP) + actor->z = actor->ceilingz - actor->height; + else + actor->z = actor->floorz; +} + +// Function: A_MinusPopup +// +// Description: Minus popping out of the ground. +// +// var1 = unused +// var2 = unused +// +void A_MinusPopup(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MinusPopup", actor)) + return; +#endif + P_SetObjectMomZ(actor, 10*FRACUNIT, false); + + actor->flags |= MF_SPECIAL; + actor->flags |= MF_SHOOTABLE; + + // Sound for busting out of the ground. + S_StartSound(actor, actor->info->attacksound); +} + +// Function: A_MinusCheck +// +// Description: If the minus hits the floor, dig back into the ground. +// +// var1 = unused +// var2 = unused +// +void A_MinusCheck(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MinusCheck", actor)) + return; +#endif + if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) + || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)) + { + actor->flags &= ~MF_SPECIAL; + actor->flags &= ~MF_SHOOTABLE; + actor->reactiontime = TICRATE; + P_SetMobjState(actor, actor->info->seestate); + return; + } + + // 'Falling' animation + if (P_MobjFlip(actor)*actor->momz < 0 && actor->state < &states[actor->info->meleestate]) + P_SetMobjState(actor, actor->info->meleestate); +} + +// Function: A_ChickenCheck +// +// Description: Resets the chicken once it hits the floor again. +// +// var1 = unused +// var2 = unused +// +void A_ChickenCheck(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChickenCheck", actor)) + return; +#endif + if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) + || (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height >= actor->ceilingz)) + { + if (!(actor->momx || actor->momy || actor->momz) + && actor->state > &states[actor->info->seestate]) + { + A_Chase(actor); + P_SetMobjState(actor, actor->info->seestate); + } + + actor->momx >>= 2; + actor->momy >>= 2; + } +} + +// Function: A_JetgThink +// +// Description: Thinker for Jetty-Syn Gunners +// +// var1 = unused +// var2 = unused +// +void A_JetgThink(mobj_t *actor) +{ + sector_t *nextsector; + + fixed_t thefloor; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_JetgThink", actor)) + return; +#endif + + if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz + && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) + thefloor = actor->watertop; + else + thefloor = actor->floorz; + + if (actor->target) + { + if (P_RandomChance(FRACUNIT/8) && !actor->reactiontime) + P_SetMobjState(actor, actor->info->missilestate); + else + A_JetChase (actor); + } + else if (actor->z - FixedMul((32<scale) < thefloor && !(thefloor + FixedMul((32<scale) + + actor->height > actor->ceilingz)) + { + actor->z = thefloor + FixedMul((32<scale); + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector; + + // Move downwards or upwards to go through a passageway. + if (nextsector->ceilingheight < actor->z + actor->height) + actor->momz -= FixedMul(5*FRACUNIT, actor->scale); + else if (nextsector->floorheight > actor->z) + actor->momz += FixedMul(5*FRACUNIT, actor->scale); +} + +// Function: A_MouseThink +// +// Description: Thinker for scurrying mice. +// +// var1 = unused +// var2 = unused +// +void A_MouseThink(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MouseThink", actor)) + return; +#endif + + if (actor->reactiontime) + actor->reactiontime--; + + if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z == actor->floorz) + || (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height == actor->ceilingz)) + && !actor->reactiontime) + { + if (twodlevel || actor->flags2 & MF2_TWOD) + { + if (P_RandomChance(FRACUNIT/2)) + actor->angle += ANGLE_180; + } + else if (P_RandomChance(FRACUNIT/2)) + actor->angle += ANGLE_90; + else + actor->angle -= ANGLE_90; + + P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale)); + actor->reactiontime = TICRATE/5; + } +} + +// Function: A_DetonChase +// +// Description: Chases a Deton after a player. +// +// var1 = unused +// var2 = unused +// +void A_DetonChase(mobj_t *actor) +{ + angle_t exact; + fixed_t xydist, dist; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_DetonChase", actor)) + return; +#endif + + // modify tracer threshold + if (!actor->tracer || actor->tracer->health <= 0) + actor->threshold = 0; + else + actor->threshold = 1; + + if (!actor->tracer || !(actor->tracer->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, true, 0)) + return; // got a new target + + actor->momx = actor->momy = actor->momz = 0; + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + if (multiplayer && !actor->threshold && P_LookForPlayers(actor, true, true, 0)) + return; // got a new target + + // Face movement direction if not doing so + exact = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); + actor->angle = exact; + /*if (exact != actor->angle) + { + if (exact - actor->angle > ANGLE_180) + { + actor->angle -= actor->info->raisestate; + if (exact - actor->angle < ANGLE_180) + actor->angle = exact; + } + else + { + actor->angle += actor->info->raisestate; + if (exact - actor->angle > ANGLE_180) + actor->angle = exact; + } + }*/ + // movedir is up/down angle: how much it has to go up as it goes over to the player + xydist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); + exact = R_PointToAngle2(0, 0, xydist, actor->tracer->z - actor->z); + actor->movedir = exact; + /*if (exact != actor->movedir) + { + if (exact - actor->movedir > ANGLE_180) + { + actor->movedir -= actor->info->raisestate; + if (exact - actor->movedir < ANGLE_180) + actor->movedir = exact; + } + else + { + actor->movedir += actor->info->raisestate; + if (exact - actor->movedir > ANGLE_180) + actor->movedir = exact; + } + }*/ + + // check for melee attack + if (actor->tracer) + { + if (P_AproxDistance(actor->tracer->x-actor->x, actor->tracer->y-actor->y) < actor->radius+actor->tracer->radius) + { + if (!((actor->tracer->z > actor->z + actor->height) || (actor->z > actor->tracer->z + actor->tracer->height))) + { + P_ExplodeMissile(actor); + return; + } + } + } + + // chase towards player + if ((dist = P_AproxDistance(xydist, actor->tracer->z-actor->z)) + > FixedMul((actor->info->painchance << FRACBITS), actor->scale)) + { + P_SetTarget(&actor->tracer, NULL); // Too far away + return; + } + + if (actor->reactiontime == 0) + { + actor->reactiontime = actor->info->reactiontime; + return; + } + + if (actor->reactiontime > 1) + { + actor->reactiontime--; + return; + } + + if (actor->reactiontime > 0) + { + actor->reactiontime = -42; + + if (actor->info->seesound) + S_StartScreamSound(actor, actor->info->seesound); + } + + if (actor->reactiontime == -42) + { + fixed_t xyspeed; + + actor->reactiontime = -42; + + exact = actor->movedir>>ANGLETOFINESHIFT; + xyspeed = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINECOSINE(exact)); + actor->momz = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINESINE(exact)); + + exact = actor->angle>>ANGLETOFINESHIFT; + actor->momx = FixedMul(xyspeed, FINECOSINE(exact)); + actor->momy = FixedMul(xyspeed, FINESINE(exact)); + + // Variable re-use + xyspeed = (P_AproxDistance(actor->tracer->x - actor->x, P_AproxDistance(actor->tracer->y - actor->y, actor->tracer->z - actor->z))>>(FRACBITS+6)); + + if (xyspeed < 1) + xyspeed = 1; + + if (leveltime % xyspeed == 0) + S_StartSound(actor, sfx_deton); + } +} + +// Function: A_CapeChase +// +// Description: Set an object's location to its target or tracer. +// +// var1: +// 0 = Use target +// 1 = Use tracer +// upper 16 bits = Z offset +// var2: +// upper 16 bits = forward/backward offset +// lower 16 bits = sideways offset +// +void A_CapeChase(mobj_t *actor) +{ + mobj_t *chaser; + fixed_t foffsetx, foffsety, boffsetx, boffsety; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + angle_t angle; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CapeChase", actor)) + return; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_CapeChase called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); + + if (locvar1 & 65535) + chaser = actor->tracer; + else + chaser = actor->target; + + if (!chaser || (chaser->health <= 0)) + { + if (chaser) + CONS_Debug(DBG_GAMELOGIC, "Hmm, the guy I'm chasing (object type %d) has no health.. so I'll die too!\n", chaser->type); + + P_RemoveMobj(actor); + return; + } + + angle = (chaser->player ? chaser->player->drawangle : chaser->angle); + + foffsetx = P_ReturnThrustX(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + foffsety = P_ReturnThrustY(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + + boffsetx = P_ReturnThrustX(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); + boffsety = P_ReturnThrustY(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); + + P_UnsetThingPosition(actor); + actor->x = chaser->x + foffsetx + boffsetx; + actor->y = chaser->y + foffsety + boffsety; + if (chaser->eflags & MFE_VERTICALFLIP) + { + actor->eflags |= MFE_VERTICALFLIP; + actor->flags2 |= MF2_OBJECTFLIP; + actor->z = chaser->z + chaser->height - actor->height - FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale); + } + else + { + actor->eflags &= ~MFE_VERTICALFLIP; + actor->flags2 &= ~MF2_OBJECTFLIP; + actor->z = chaser->z + FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale); + } + actor->angle = angle; + P_SetThingPosition(actor); +} + +// Function: A_RotateSpikeBall +// +// Description: Rotates a spike ball around its target/tracer. +// +// var1: +// 0 = Use target +// 1 = Use tracer +// var2 = unused +// +void A_RotateSpikeBall(mobj_t *actor) +{ + INT32 locvar1 = var1; + const fixed_t radius = FixedMul(12*actor->info->speed, actor->scale); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RotateSpikeBall", actor)) + return; +#endif + + if (actor->type == MT_SPECIALSPIKEBALL) // don't remove this, these spikeballs share the same states as the rotating spikeballs + return; + + if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen. + { + CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Spikeball has no target\n"); + P_RemoveMobj(actor); + return; + } + + if (!actor->info->speed) + { + CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Object has no speed.\n"); + return; + } + + actor->angle += FixedAngle(actor->info->speed); + P_UnsetThingPosition(actor); + { + const angle_t fa = actor->angle>>ANGLETOFINESHIFT; + if (!locvar1) + { + actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius); + actor->y = actor->target->y + FixedMul(FINESINE(fa),radius); + actor->z = actor->target->z + actor->target->height/2; + } + else + { + actor->x = actor->tracer->x + FixedMul(FINECOSINE(fa),radius); + actor->y = actor->tracer->y + FixedMul(FINESINE(fa),radius); + actor->z = actor->tracer->z + actor->tracer->height/2; + } + P_SetThingPosition(actor); + } +} + +// Function: A_UnidusBall +// +// Description: Rotates a spike ball around its target. +// +// var1: +// 0 = Don't throw +// 1 = Throw +// 2 = Throw when target leaves MF2_SKULLFLY. +// var2 = unused +// +void A_UnidusBall(mobj_t *actor) +{ + INT32 locvar1 = var1; + boolean canthrow = false; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_UnidusBall", actor)) + return; +#endif + + actor->angle += ANGLE_11hh; + + if (actor->movecount) + { + if (P_AproxDistance(actor->momx, actor->momy) < FixedMul(actor->info->damage/2, actor->scale)) + P_ExplodeMissile(actor); + return; + } + + if (!actor->target || !actor->target->health) + { + CONS_Debug(DBG_GAMELOGIC, "A_UnidusBall: Removing unthrown spikeball from nonexistant Unidus\n"); + P_RemoveMobj(actor); + return; + } + + P_UnsetThingPosition(actor); + { + const angle_t angle = actor->movedir + FixedAngle(actor->info->speed*(leveltime%360)); + const UINT16 fa = angle>>ANGLETOFINESHIFT; + + actor->x = actor->target->x + FixedMul(FINECOSINE(fa),actor->threshold); + actor->y = actor->target->y + FixedMul( FINESINE(fa),actor->threshold); + actor->z = actor->target->z + actor->target->height/2 - actor->height/2; + + if (locvar1 == 1 && actor->target->target) + { + const angle_t tang = R_PointToAngle2(actor->target->x, actor->target->y, actor->target->target->x, actor->target->target->y); + const angle_t mina = tang-ANGLE_11hh; + canthrow = (angle-mina < FixedAngle(actor->info->speed*3)); + } + } + P_SetThingPosition(actor); + + if (locvar1 == 1 && canthrow) + { + if (P_AproxDistance(actor->target->target->x - actor->target->x, actor->target->target->y - actor->target->y) > FixedMul(MISSILERANGE>>1, actor->scale) + || !P_CheckSight(actor, actor->target->target)) + return; + + actor->movecount = actor->info->damage>>FRACBITS; + actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING); + P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->target->target->x, actor->target->target->y), FixedMul(actor->info->damage, actor->scale)); + } + else if (locvar1 == 2) + { + boolean skull = (actor->target->flags2 & MF2_SKULLFLY) == MF2_SKULLFLY; + if (actor->target->state == &states[actor->target->info->painstate]) + { + P_KillMobj(actor, NULL, NULL, 0); + return; + } + switch(actor->extravalue2) + { + case 0: // at least one frame where not dashing + if (!skull) ++actor->extravalue2; + else break; + /* FALLTHRU */ + case 1: // at least one frame where ARE dashing + if (skull) ++actor->extravalue2; + else break; + /* FALLTHRU */ + case 2: // not dashing again? + if (skull) break; + // launch. + { + mobj_t *target = actor->target; + if (actor->target->target) + target = actor->target->target; + actor->movecount = actor->info->damage>>FRACBITS; + actor->flags &= ~(MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING); + P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, target->x, target->y), FixedMul(actor->info->damage, actor->scale)); + } + default: // from our compiler appeasement program (CAP). + break; + } + } +} + +// Function: A_RockSpawn +// +// Spawns rocks at a specified interval +// +// var1 = unused +// var2 = unused +void A_RockSpawn(mobj_t *actor) +{ + mobj_t *mo; + mobjtype_t type; + INT32 i = P_FindSpecialLineFromTag(12, (INT16)actor->threshold, -1); + line_t *line; + fixed_t dist; + fixed_t randomoomph; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RockSpawn", actor)) + return; +#endif + + if (i == -1) + { + CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: Unable to find parameter line 12 (tag %d)!\n", actor->threshold); + return; + } + + line = &lines[i]; + + if (!(sides[line->sidenum[0]].textureoffset >> FRACBITS)) + { + CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: No X-offset detected! (tag %d)!\n", actor->threshold); + return; + } + + dist = P_AproxDistance(line->dx, line->dy)/16; + + if (dist < 1) + dist = 1; + + type = MT_ROCKCRUMBLE1 + (sides[line->sidenum[0]].rowoffset >> FRACBITS); + + if (line->flags & ML_NOCLIMB) + randomoomph = P_RandomByte() * (FRACUNIT/32); + else + randomoomph = 0; + + mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK); + P_SetMobjState(mo, mobjinfo[type].spawnstate); + mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); + + P_InstaThrust(mo, mo->angle, dist + randomoomph); + mo->momz = dist + randomoomph; + + var1 = sides[line->sidenum[0]].textureoffset >> FRACBITS; + A_SetTics(actor); +} + +// +// Function: A_SlingAppear +// +// Appears a sling. +// +// var1 = unused +// var2 = unused +// +void A_SlingAppear(mobj_t *actor) +{ + UINT8 mlength = 4; + mobj_t *spawnee, *hprev; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SlingAppear", actor)) + return; +#endif + + P_UnsetThingPosition(actor); + actor->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT); + P_SetThingPosition(actor); + actor->lastlook = 128; + actor->movecount = actor->lastlook; + actor->threshold = 0; + actor->movefactor = actor->threshold; + actor->friction = 128; + + hprev = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLGRABCHAIN); + P_SetTarget(&hprev->tracer, actor); + P_SetTarget(&hprev->hprev, actor); + P_SetTarget(&actor->hnext, hprev); + hprev->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; + hprev->movecount = mlength; + + mlength--; + + while (mlength > 0) + { + spawnee = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLMACECHAIN); + P_SetTarget(&spawnee->tracer, actor); + P_SetTarget(&spawnee->hprev, hprev); + P_SetTarget(&hprev->hnext, spawnee); + hprev = spawnee; + + spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; + spawnee->movecount = mlength; + + mlength--; + } +} + +// Function: A_SetFuse +// +// Description: Sets the actor's fuse timer if not set already. May also change state when fuse reaches the last tic, otherwise by default the actor will die or disappear. (Replaces A_SnowBall) +// +// var1 = fuse timer duration (in tics). +// var2: +// lower 16 bits = if > 0, state to change to when fuse = 1 +// upper 16 bits: 0 = (default) don't set fuse unless 0, 1 = force change, 2 = force no change +// +void A_SetFuse(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetFuse", actor)) + return; +#endif + + if ((!actor->fuse || (locvar2 >> 16)) && (locvar2 >> 16) != 2) // set the actor's fuse value + actor->fuse = locvar1; + + if (actor->fuse == 1 && (locvar2 & 65535)) // change state on the very last tic (fuse is handled before actions in P_MobjThinker) + { + actor->fuse = 0; // don't die/disappear the next tic! + P_SetMobjState(actor, locvar2 & 65535); + } +} + +// Function: A_CrawlaCommanderThink +// +// Description: Thinker for Crawla Commander. +// +// var1 = shoot bullets? +// var2 = "pogo mode" speed +// +void A_CrawlaCommanderThink(mobj_t *actor) +{ + fixed_t dist; + sector_t *nextsector; + fixed_t thefloor; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + boolean hovermode = (actor->health > 1 || actor->fuse); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CrawlaCommanderThink", actor)) + return; +#endif + + if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz + && actor->z > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) + thefloor = actor->watertop; + else + thefloor = actor->floorz; + + if (!actor->fuse && actor->flags2 & MF2_FRET) + { + if (actor->info->painsound) + S_StartSound(actor, actor->info->painsound); + + actor->fuse = TICRATE/2; + actor->momz = 0; + + P_InstaThrust(actor, actor->angle-ANGLE_180, FixedMul(5*FRACUNIT, actor->scale)); + } + + if (actor->reactiontime > 0) + actor->reactiontime--; + + if (actor->fuse < 2) + { + actor->fuse = 0; + actor->flags2 &= ~MF2_FRET; + } + + // Hover mode + if (hovermode) + { + if (actor->z < thefloor + FixedMul(16*FRACUNIT, actor->scale)) + actor->momz += FixedMul(FRACUNIT, actor->scale); + else if (actor->z < thefloor + FixedMul(32*FRACUNIT, actor->scale)) + actor->momz += FixedMul(FRACUNIT/2, actor->scale); + else + actor->momz += FixedMul(16, actor->scale); + } + + if (!actor->target) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + if (actor->state != &states[actor->info->spawnstate]) + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y); + + if (actor->target->player && (!hovermode || actor->reactiontime <= 2*TICRATE)) + { + if (dist < FixedMul(64<<(FRACBITS+(hovermode ? 1 : 0)), actor->scale) + && ((actor->target->player->pflags & PF_JUMPED) || (actor->target->player->pflags & PF_SPINNING))) + { + // Auugh! She's trying to kill you! Strafe! STRAAAAFFEEE!! + P_InstaThrust(actor, actor->angle - ANGLE_180, FixedMul(20*FRACUNIT, actor->scale)); + return; + } + } + + if (locvar1) + { + if (actor->health < 2 && P_RandomChance(FRACUNIT/128)) + P_SpawnMissile(actor, actor->target, locvar1); + } + + // Face the player + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + + if (actor->threshold && dist > FixedMul(256*FRACUNIT, actor->scale)) + actor->momx = actor->momy = 0; + + if (actor->reactiontime && actor->reactiontime <= 2*TICRATE && dist > actor->target->radius - FixedMul(FRACUNIT, actor->scale)) + { + actor->threshold = 0; + + // Roam around, somewhat in the player's direction. + actor->angle += (P_RandomByte()<<10); + actor->angle -= (P_RandomByte()<<10); + + if (hovermode) + { + fixed_t mom; + P_Thrust(actor, actor->angle, 2*actor->scale); + mom = P_AproxDistance(actor->momx, actor->momy); + if (mom > 20*actor->scale) + { + mom += 20*actor->scale; + mom >>= 1; + P_InstaThrust(actor, R_PointToAngle2(0, 0, actor->momx, actor->momy), mom); + } + } + } + else if (!actor->reactiontime) + { + if (hovermode && !(actor->flags2 & MF2_FRET)) // Hover Mode + { + if (dist < FixedMul(512*FRACUNIT, actor->scale)) + { + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_InstaThrust(actor, actor->angle, FixedMul(40*FRACUNIT, actor->scale)); + actor->threshold = 1; + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); + } + } + actor->reactiontime = 3*TICRATE + (P_RandomByte()>>2); + } + + if (actor->health == 1) + P_Thrust(actor, actor->angle, 1); + + // Pogo Mode + if (!hovermode && actor->z <= actor->floorz) + { + if (actor->info->activesound) + S_StartSound(actor, actor->info->activesound); + + if (dist < FixedMul(256*FRACUNIT, actor->scale)) + { + actor->momz = FixedMul(locvar2, actor->scale); + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_InstaThrust(actor, actor->angle, FixedMul(locvar2/8, actor->scale)); + // pogo on player + } + else + { + UINT8 prandom = P_RandomByte(); + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); + P_InstaThrust(actor, actor->angle, FixedDiv(FixedMul(locvar2, actor->scale), 3*FRACUNIT/2)); + actor->momz = FixedMul(locvar2, actor->scale); // Bounce up in air + } + } + + nextsector = R_PointInSubsector(actor->x + actor->momx, actor->y + actor->momy)->sector; + + // Move downwards or upwards to go through a passageway. + if (nextsector->floorheight > actor->z && nextsector->floorheight - actor->z < FixedMul(128*FRACUNIT, actor->scale)) + actor->momz += (nextsector->floorheight - actor->z) / 4; +} + +// Function: A_RingExplode +// +// Description: An explosion ring exploding +// +// var1 = unused +// var2 = unused +// +void A_RingExplode(mobj_t *actor) +{ + mobj_t *mo2; + thinker_t *th; + angle_t d; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RingExplode", actor)) + return; +#endif + + for (d = 0; d < 16; d++) + P_SpawnParaloop(actor->x, actor->y, actor->z + actor->height, FixedMul(actor->info->painchance, actor->scale), 16, MT_NIGHTSPARKLE, S_NULL, d*(ANGLE_22h), true); + + S_StartSound(actor, sfx_prloop); + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2 == actor) // Don't explode yourself! Endless loop! + continue; + + if (P_AproxDistance(P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y), mo2->z - actor->z) > FixedMul(actor->info->painchance, actor->scale)) + continue; + + if (mo2->flags & MF_SHOOTABLE) + { + actor->flags2 |= MF2_DEBRIS; + P_DamageMobj(mo2, actor, actor->target, 1, 0); + continue; + } + } + return; +} + +// Function: A_OldRingExplode +// +// Description: An explosion ring exploding, 1.09.4 style +// +// var1 = object # to explode as debris +// var2 = unused +// +void A_OldRingExplode(mobj_t *actor) { + UINT8 i; + mobj_t *mo; + const fixed_t ns = FixedMul(20 * FRACUNIT, actor->scale); + INT32 locvar1 = var1; + //INT32 locvar2 = var2; + boolean changecolor = (actor->target && actor->target->player); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_OldRingExplode", actor)) + return; +#endif + + for (i = 0; i < 32; i++) + { + const angle_t fa = (i*FINEANGLES/16) & FINEMASK; + + mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + P_SetTarget(&mo->target, actor->target); // Transfer target so player gets the points + + mo->momx = FixedMul(FINECOSINE(fa),ns); + mo->momy = FixedMul(FINESINE(fa),ns); + + if (i > 15) + { + if (i & 1) + mo->momz = ns; + else + mo->momz = -ns; + } + + mo->flags2 |= MF2_DEBRIS; + mo->fuse = TICRATE/5; + + if (changecolor) + { + if (gametype != GT_CTF) + mo->color = actor->target->color; //copy color + else if (actor->target->player->ctfteam == 2) + mo->color = skincolor_bluering; + } + } + + mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + + P_SetTarget(&mo->target, actor->target); + mo->momz = ns; + mo->flags2 |= MF2_DEBRIS; + mo->fuse = TICRATE/5; + + if (changecolor) + { + if (gametype != GT_CTF) + mo->color = actor->target->color; //copy color + else if (actor->target->player->ctfteam == 2) + mo->color = skincolor_bluering; + } + + mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + + P_SetTarget(&mo->target, actor->target); + mo->momz = -ns; + mo->flags2 |= MF2_DEBRIS; + mo->fuse = TICRATE/5; + + if (changecolor) + { + if (gametype != GT_CTF) + mo->color = actor->target->color; //copy color + else if (actor->target->player->ctfteam == 2) + mo->color = skincolor_bluering; + } +} + +// Function: A_MixUp +// +// Description: Mix up all of the player positions. +// +// var1 = unused +// var2 = unused +// +void A_MixUp(mobj_t *actor) +{ + boolean teleported[MAXPLAYERS]; + INT32 i, numplayers = 0, prandom = 0; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MixUp", actor)) + return; +#else + (void)actor; +#endif + + if (!multiplayer) + return; + + // No mix-up monitors in hide and seek or time only race. + // The random factor is okay for other game modes, but in these, it is cripplingly unfair. + if (gametype == GT_HIDEANDSEEK || gametype == GT_RACE) + { + S_StartSound(actor, sfx_lose); + return; + } + + numplayers = 0; + memset(teleported, 0, sizeof (teleported)); + + // Count the number of players in the game + // and grab their xyz coords + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE + && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) + { + if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators + continue; + + numplayers++; + } + + if (numplayers <= 1) // Not enough players to mix up. + { + S_StartSound(actor, sfx_lose); + return; + } + else if (numplayers == 2) // Special case -- simple swap + { + fixed_t x, y, z; + angle_t angle; + INT32 one = -1, two = 0; // default value 0 to make the compiler shut up + + // Zoom tube stuff + mobj_t *tempthing = NULL; //tracer + UINT16 carry1,carry2; //carry + INT32 transspeed; //player speed + + // Starpost stuff + INT16 starpostx, starposty, starpostz; + INT32 starpostnum; + tic_t starposttime; + angle_t starpostangle; + + INT32 mflags2; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE + && !players[i].exiting && !players[i].powers[pw_super]) + { + if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators + continue; + + if (one == -1) + one = i; + else + { + two = i; + break; + } + } + + //get this done first! + tempthing = players[one].mo->tracer; + P_SetTarget(&players[one].mo->tracer, players[two].mo->tracer); + P_SetTarget(&players[two].mo->tracer, tempthing); + + //zoom tubes use player->speed to determine direction and speed + transspeed = players[one].speed; + players[one].speed = players[two].speed; + players[two].speed = transspeed; + + //set flags variables now but DON'T set them. + carry1 = (players[one].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[one].powers[pw_carry]); + carry2 = (players[two].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[two].powers[pw_carry]); + + x = players[one].mo->x; + y = players[one].mo->y; + z = players[one].mo->z; + angle = players[one].mo->angle; + + starpostx = players[one].starpostx; + starposty = players[one].starposty; + starpostz = players[one].starpostz; + starpostangle = players[one].starpostangle; + starpostnum = players[one].starpostnum; + starposttime = players[one].starposttime; + + mflags2 = players[one].mo->flags2; + + P_MixUp(players[one].mo, players[two].mo->x, players[two].mo->y, players[two].mo->z, players[two].mo->angle, + players[two].starpostx, players[two].starposty, players[two].starpostz, + players[two].starpostnum, players[two].starposttime, players[two].starpostangle, + players[two].mo->flags2); + + P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz, + starpostnum, starposttime, starpostangle, + mflags2); + + //carry set after mixup. Stupid P_ResetPlayer() takes away some of the stuff we look for... + //but not all of it! So we need to make sure they aren't set wrong or anything. + players[one].powers[pw_carry] = carry2; + players[two].powers[pw_carry] = carry1; + + teleported[one] = true; + teleported[two] = true; + } + else + { + fixed_t position[MAXPLAYERS][3]; + angle_t anglepos[MAXPLAYERS]; + INT32 pindex[MAXPLAYERS], counter = 0, teleportfrom = 0; + + // Zoom tube stuff + mobj_t *transtracer[MAXPLAYERS]; //tracer + //pflags_t transflag[MAXPLAYERS]; //cyan pink white pink cyan + UINT16 transcarry[MAXPLAYERS]; //player carry + INT32 transspeed[MAXPLAYERS]; //player speed + + // Star post stuff + INT16 spposition[MAXPLAYERS][3]; + INT32 starpostnum[MAXPLAYERS]; + tic_t starposttime[MAXPLAYERS]; + angle_t starpostangle[MAXPLAYERS]; + + INT32 flags2[MAXPLAYERS]; + + for (i = 0; i < MAXPLAYERS; i++) + { + position[i][0] = position[i][1] = position[i][2] = anglepos[i] = pindex[i] = -1; + teleported[i] = false; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && players[i].playerstate == PST_LIVE + && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) + { + if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators + continue; + + position[counter][0] = players[i].mo->x; + position[counter][1] = players[i].mo->y; + position[counter][2] = players[i].mo->z; + pindex[counter] = i; + anglepos[counter] = players[i].mo->angle; + players[i].mo->momx = players[i].mo->momy = players[i].mo->momz = + players[i].rmomx = players[i].rmomy = 1; + players[i].cmomx = players[i].cmomy = 0; + + transcarry[counter] = (players[i].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[i].powers[pw_carry]); + transspeed[counter] = players[i].speed; + transtracer[counter] = players[i].mo->tracer; + + spposition[counter][0] = players[i].starpostx; + spposition[counter][1] = players[i].starposty; + spposition[counter][2] = players[i].starpostz; + starpostnum[counter] = players[i].starpostnum; + starposttime[counter] = players[i].starposttime; + starpostangle[counter] = players[i].starpostangle; + + flags2[counter] = players[i].mo->flags2; + + counter++; + } + } + + counter = 0; + + // Mix them up! + for (;;) + { + if (counter > 255) // fail-safe to avoid endless loop + break; + prandom = P_RandomByte(); + prandom %= numplayers; // I love modular arithmetic, don't you? + if (prandom) // Make sure it's not a useless mix + break; + counter++; + } + + counter = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && players[i].playerstate == PST_LIVE + && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) + { + if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators + continue; + + teleportfrom = (counter + prandom) % numplayers; + + //speed and tracer come before... + players[i].speed = transspeed[teleportfrom]; + P_SetTarget(&players[i].mo->tracer, transtracer[teleportfrom]); + + P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom], + spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2], + starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom], + flags2[teleportfrom]); + + //...carry after. same reasoning. + players[i].powers[pw_carry] = transcarry[teleportfrom]; + + teleported[i] = true; + counter++; + } + } + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (teleported[i]) + { + if (playeringame[i] && players[i].playerstate == PST_LIVE + && players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE) + { + if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators + continue; + + P_SetThingPosition(players[i].mo); + +#ifdef ESLOPE + players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); + players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); +#else + players[i].mo->floorz = players[i].mo->subsector->sector->floorheight; + players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight; +#endif + + P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y); + } + } + } + + // Play the 'bowrwoosh!' sound + S_StartSound(NULL, sfx_mixup); +} + +// Function: A_RecyclePowers +// +// Description: Take all player's powers, and swap 'em. +// +// var1 = unused +// var2 = unused +// +void A_RecyclePowers(mobj_t *actor) +{ + INT32 i, j, k, numplayers = 0; + +#ifdef WEIGHTEDRECYCLER + UINT8 beneficiary = 255; +#endif + UINT8 playerslist[MAXPLAYERS]; + UINT8 postscramble[MAXPLAYERS]; + + UINT16 powers[MAXPLAYERS][NUMPOWERS]; + INT32 weapons[MAXPLAYERS]; + INT32 weaponheld[MAXPLAYERS]; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RecyclePowers", actor)) + return; +#endif + +#if !defined(WEIGHTEDRECYCLER) && !defined(HAVE_BLUA) + // actor is used in all scenarios but this one, funny enough + (void)actor; +#endif + + if (!multiplayer) + { + S_StartSound(actor, sfx_lose); + return; + } + + numplayers = 0; + + // Count the number of players in the game + for (i = 0, j = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE + && !players[i].exiting && !((netgame || multiplayer) && players[i].spectator)) + { +#ifndef WEIGHTEDRECYCLER + if (players[i].powers[pw_super]) + continue; // Ignore super players +#endif + + numplayers++; + postscramble[j] = playerslist[j] = (UINT8)i; + +#ifdef WEIGHTEDRECYCLER + // The guy who started the recycle gets the best result + if (actor && actor->target && actor->target->player && &players[i] == actor->target->player) + beneficiary = (UINT8)i; +#endif + + // Save powers + for (k = 0; k < NUMPOWERS; k++) + powers[i][k] = players[i].powers[k]; + //1.1: ring weapons too + weapons[i] = players[i].ringweapons; + weaponheld[i] = players[i].currentweapon; + + j++; + } + } + + if (numplayers <= 1) + { + S_StartSound(actor, sfx_lose); + return; //nobody to touch! + } + + //shuffle the post scramble list, whee! + // hardcoded 0-1 to 1-0 for two players + if (numplayers == 2) + { + postscramble[0] = playerslist[1]; + postscramble[1] = playerslist[0]; + } + else + for (j = 0; j < numplayers; j++) + { + UINT8 tempint; + + i = j + ((P_RandomByte() + leveltime) % (numplayers - j)); + tempint = postscramble[j]; + postscramble[j] = postscramble[i]; + postscramble[i] = tempint; + } + +#ifdef WEIGHTEDRECYCLER + //the joys of qsort... + if (beneficiary != 255) { + qsort(playerslist, numplayers, sizeof(UINT8), P_RecycleCompare); + + // now, make sure the benificiary is in the best slot + // swap out whatever poor sap was going to get the best items + for (i = 0; i < numplayers; i++) + { + if (postscramble[i] == beneficiary) + { + postscramble[i] = postscramble[0]; + postscramble[0] = beneficiary; + break; + } + } + } +#endif + + // now assign! + for (i = 0; i < numplayers; i++) + { + UINT8 send_pl = playerslist[i]; + UINT8 recv_pl = postscramble[i]; + + // debugF + CONS_Debug(DBG_GAMELOGIC, "sending player %hu's items to %hu\n", (UINT16)send_pl, (UINT16)recv_pl); + + for (j = 0; j < NUMPOWERS; j++) + { + if (j == pw_flashing || j == pw_underwater || j == pw_spacetime || j == pw_carry + || j == pw_tailsfly || j == pw_extralife || j == pw_nocontrol || j == pw_super) + continue; + players[recv_pl].powers[j] = powers[send_pl][j]; + } + + //1.1: weapon rings too + players[recv_pl].ringweapons = weapons[send_pl]; + players[recv_pl].currentweapon = weaponheld[send_pl]; + + P_SpawnShieldOrb(&players[recv_pl]); + if (P_IsLocalPlayer(&players[recv_pl])) + P_RestoreMusic(&players[recv_pl]); + P_FlashPal(&players[recv_pl], PAL_RECYCLE, 10); + } + + S_StartSound(NULL, sfx_gravch); //heh, the sound effect I used is already in +} + +// Function: A_Boss1Chase +// +// Description: Like A_Chase, but for Boss 1. +// +// var1 = unused +// var2 = unused +// +void A_Boss1Chase(mobj_t *actor) +{ + INT32 delta; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss1Chase", actor)) + return; +#endif + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjStateNF(actor, actor->info->spawnstate); + return; + } + + if (actor->reactiontime) + actor->reactiontime--; + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + // do not attack twice in a row + if (actor->flags2 & MF2_JUSTATTACKED) + { + actor->flags2 &= ~MF2_JUSTATTACKED; + P_NewChaseDir(actor); + return; + } + + if (actor->movecount) + goto nomissile; + + if (!P_CheckMissileRange(actor)) + goto nomissile; + + if (actor->reactiontime <= 0) + { + if (actor->health > actor->info->damage) + { + if (P_RandomChance(FRACUNIT/2)) + P_SetMobjState(actor, actor->info->missilestate); + else + P_SetMobjState(actor, actor->info->meleestate); + } + else + { + P_LinedefExecute(LE_PINCHPHASE, actor, NULL); + P_SetMobjState(actor, actor->info->raisestate); + } + + actor->flags2 |= MF2_JUSTATTACKED; + actor->reactiontime = actor->info->reactiontime; + return; + } + + // ? +nomissile: + // possibly choose another target + if (multiplayer && P_RandomChance(FRACUNIT/128)) + { + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + } + + if (actor->flags & MF_FLOAT && !(actor->flags2 & MF2_SKULLFLY)) + { // Float up/down to your target's position. Stay above them, but not out of jump range. + fixed_t target_min = actor->target->floorz+FixedMul(64*FRACUNIT, actor->scale); + if (target_min < actor->target->z - actor->height) + target_min = actor->target->z - actor->height; + if (target_min < actor->floorz+FixedMul(33*FRACUNIT, actor->scale)) + target_min = actor->floorz+FixedMul(33*FRACUNIT, actor->scale); + if (actor->z > target_min+FixedMul(16*FRACUNIT, actor->scale)) + actor->momz = FixedMul((-actor->info->speed<<(FRACBITS-1)), actor->scale); + else if (actor->z < target_min) + actor->momz = FixedMul(actor->info->speed<<(FRACBITS-1), actor->scale); + else + actor->momz = FixedMul(actor->momz,7*FRACUNIT/8); + } + + // chase towards player + if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) > actor->radius+actor->target->radius) + { + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); + } + // too close, don't want to chase. + else if (--actor->movecount < 0) + { + // A mini-A_FaceTarget based on P_NewChaseDir. + // Yes, it really is this simple when you get down to it. + fixed_t deltax, deltay; + + deltax = actor->target->x - actor->x; + deltay = actor->target->y - actor->y; + + actor->movedir = diags[((deltay < 0)<<1) + (deltax > 0)]; + actor->movecount = P_RandomByte() & 15; + } +} + +// Function: A_Boss2Chase +// +// Description: Really doesn't 'chase', but rather goes in a circle. +// +// var1 = unused +// var2 = unused +// +void A_Boss2Chase(mobj_t *actor) +{ + fixed_t radius; + boolean reverse = false; + INT32 speedvar; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2Chase", actor)) + return; +#endif + + if (actor->health <= 0) + return; + + // Startup randomness + if (actor->reactiontime <= -666) + actor->reactiontime = 2*TICRATE + P_RandomByte(); + + // When reactiontime hits zero, he will go the other way + if (--actor->reactiontime <= 0) + { + reverse = true; + actor->reactiontime = 2*TICRATE + P_RandomByte(); + } + + P_SetTarget(&actor->target, P_GetClosestAxis(actor)); + + if (!actor->target) // This should NEVER happen. + { + CONS_Debug(DBG_GAMELOGIC, "Boss2 has no target!\n"); + A_BossDeath(actor); + return; + } + + radius = actor->target->radius; + + if (reverse) + { + actor->watertop = -actor->watertop; + actor->extravalue1 = 18; + if (actor->flags2 & MF2_AMBUSH) + actor->extravalue1 -= (actor->info->spawnhealth - actor->health)*2; + actor->extravalue2 = actor->extravalue1; + } + + // Turnaround + if (actor->extravalue1 > 0) + { + --actor->extravalue1; + + // Set base angle + { + const angle_t fa = (actor->target->angle + FixedAngle(actor->watertop))>>ANGLETOFINESHIFT; + const fixed_t fc = FixedMul(FINECOSINE(fa),radius); + const fixed_t fs = FixedMul(FINESINE(fa),radius); + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs); + } + + // Now turn you around! + // Note that the start position is the final position, we move it back around + // to intermediary positions... + actor->angle -= FixedAngle(FixedMul(FixedDiv(180<extravalue2<extravalue1<flags2 & MF2_AMBUSH) + speedvar = actor->health; + else + speedvar = actor->info->spawnhealth; + + actor->target->angle += // Don't use FixedAngleC! + FixedAngle(FixedDiv(FixedMul(actor->watertop, (actor->info->spawnhealth*(FRACUNIT/4)*3)), speedvar*FRACUNIT)); + + P_UnsetThingPosition(actor); + { + const angle_t fa = actor->target->angle>>ANGLETOFINESHIFT; + const fixed_t fc = FixedMul(FINECOSINE(fa),radius); + const fixed_t fs = FixedMul(FINESINE(fa),radius); + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs); + actor->x = actor->target->x + fc; + actor->y = actor->target->y + fs; + } + P_SetThingPosition(actor); + + // Spray goo once every second + if (leveltime % (speedvar*15/10)-1 == 0) + { + const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale); + mobj_t *goop; + fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale); + angle_t fa; + // actor->movedir is used to determine the last + // direction goo was sprayed in. There are 8 possible + // directions to spray. (45-degree increments) + + actor->movedir++; + actor->movedir %= NUMDIRS; + fa = (actor->movedir*FINEANGLES/8) & FINEMASK; + + goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance); + goop->momx = FixedMul(FINECOSINE(fa),ns); + goop->momy = FixedMul(FINESINE(fa),ns); + goop->momz = FixedMul(4*FRACUNIT, actor->scale); + goop->fuse = 10*TICRATE; + + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + + if (P_RandomChance(FRACUNIT/2)) + { + goop->momx *= 2; + goop->momy *= 2; + } + else if (P_RandomChance(129*FRACUNIT/256)) + { + goop->momx *= 3; + goop->momy *= 3; + } + + actor->flags2 |= MF2_JUSTATTACKED; + } + } +} + +// Function: A_Boss2Pogo +// +// Description: Pogo part of Boss 2 AI. +// +// var1 = unused +// var2 = unused +// +void A_Boss2Pogo(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2Pogo", actor)) + return; +#endif + if (actor->z <= actor->floorz + FixedMul(8*FRACUNIT, actor->scale) && actor->momz <= 0) + { + if (actor->state != &states[actor->info->raisestate]) + P_SetMobjState(actor, actor->info->raisestate); + // Pogo Mode + } + else if (actor->momz < 0 && actor->reactiontime) + { + const fixed_t ns = FixedMul(3 * FRACUNIT, actor->scale); + mobj_t *goop; + fixed_t fz = actor->z+actor->height+FixedMul(24*FRACUNIT, actor->scale); + angle_t fa; + INT32 i; + // spray in all 8 directions! + for (i = 0; i < 8; i++) + { + actor->movedir++; + actor->movedir %= NUMDIRS; + fa = (actor->movedir*FINEANGLES/8) & FINEMASK; + + goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance); + goop->momx = FixedMul(FINECOSINE(fa),ns); + goop->momy = FixedMul(FINESINE(fa),ns); + goop->momz = FixedMul(4*FRACUNIT, actor->scale); + + goop->fuse = 10*TICRATE; + } + actor->reactiontime = 0; // we already shot goop, so don't do it again! + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + actor->flags2 |= MF2_JUSTATTACKED; + } +} + +// Function: A_Boss2TakeDamage +// +// Description: Special function for Boss 2 so you can't just sit and destroy him. +// +// var1 = Invincibility duration +// var2 = unused +// +void A_Boss2TakeDamage(mobj_t *actor) +{ + INT32 locvar1 = var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2TakeDamage", actor)) + return; +#endif + A_Pain(actor); + actor->reactiontime = 1; // turn around + if (locvar1 == 0) // old A_Invincibilerize behavior + actor->movecount = TICRATE; + else + actor->movecount = locvar1; // become flashing invulnerable for this long. +} + +// Function: A_Boss7Chase +// +// Description: Like A_Chase, but for Black Eggman +// +// var1 = unused +// var2 = unused +// +void A_Boss7Chase(mobj_t *actor) +{ + INT32 delta; + INT32 i; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss7Chase", actor)) + return; +#endif + + if (actor->z != actor->floorz) + return; + + // Self-adjust if stuck on the edge + if (actor->tracer) + { + if (P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y) > 128*FRACUNIT - actor->radius) + P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y), FRACUNIT); + } + + if (actor->flags2 & MF2_FRET) + { + P_SetMobjState(actor, S_BLACKEGG_DESTROYPLAT1); + S_StartSound(0, sfx_s3k53); + actor->flags2 &= ~MF2_FRET; + return; + } + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + // Is a player on top of us? + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + if (players[i].mo->health <= 0) + continue; + + if (P_AproxDistance(players[i].mo->x - actor->x, players[i].mo->y - actor->y) > actor->radius) + continue; + + if (players[i].mo->z > actor->z + actor->height - 2*FRACUNIT + && players[i].mo->z < actor->z + actor->height + 32*FRACUNIT) + { + // Punch him! + P_SetMobjState(actor, actor->info->meleestate); + S_StartSound(0, sfx_begrnd); // warning sound + return; + } + } + + if (actor->health <= actor->info->damage + && actor->target + && actor->target->player + && (actor->target->player->powers[pw_carry] == CR_GENERIC)) + { + A_FaceTarget(actor); + P_SetMobjState(actor, S_BLACKEGG_SHOOT1); + actor->movecount = TICRATE + P_RandomByte()/2; + return; + } + + if (actor->reactiontime) + actor->reactiontime--; + + if (actor->reactiontime <= 0 && actor->z == actor->floorz) + { + // Here, we'll call P_RandomByte() and decide what kind of attack to do + switch(actor->threshold) + { + case 0: // Lob cannon balls + if (actor->z < 1056*FRACUNIT) + { + A_FaceTarget(actor); + P_SetMobjState(actor, actor->info->xdeathstate); + actor->movecount = 7*TICRATE + P_RandomByte(); + break; + } + actor->threshold++; + /* FALLTHRU */ + case 1: // Chaingun Goop + A_FaceTarget(actor); + P_SetMobjState(actor, S_BLACKEGG_SHOOT1); + + if (actor->health > actor->info->damage) + actor->movecount = TICRATE + P_RandomByte()/3; + else + actor->movecount = TICRATE + P_RandomByte()/2; + break; + case 2: // Homing Missile + A_FaceTarget(actor); + P_SetMobjState(actor, actor->info->missilestate); + S_StartSound(0, sfx_beflap); + break; + } + + actor->threshold++; + actor->threshold %= 3; + return; + } + + // possibly choose another target + if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + && P_BossTargetPlayer(actor, false)) + return; // got a new target + + if (leveltime & 1) + { + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); + } +} + +// Function: A_GoopSplat +// +// Description: Black Eggman goop hits a target and sticks around for awhile. +// +// var1 = unused +// var2 = unused +// +void A_GoopSplat(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GoopSplat", actor)) + return; +#endif + P_UnsetThingPosition(actor); + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + actor->flags = MF_SPECIAL; // Not a typo + P_SetThingPosition(actor); +} + +// Function: A_Boss2PogoSFX +// +// Description: Pogoing for Boss 2 +// +// var1 = pogo jump strength +// var2 = idle pogo speed +// +void A_Boss2PogoSFX(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2PogoSFX", actor)) + return; +#endif + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + return; + } + + // Boing! + if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(256*FRACUNIT, actor->scale)) + { + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_InstaThrust(actor, actor->angle, FixedMul(actor->info->speed, actor->scale)); + // pogo on player + } + else + { + UINT8 prandom = P_RandomByte(); + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); + P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); + } + if (actor->info->activesound) S_StartSound(actor, actor->info->activesound); + actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air + actor->reactiontime = 1; +} + +// Function: A_Boss2PogoTarget +// +// Description: Pogoing for Boss 2, tries to actually land on the player directly. +// +// var1 = pogo jump strength +// var2 = idle pogo speed +// +void A_Boss2PogoTarget(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss2PogoTarget", actor)) + return; +#endif + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) || (actor->target->player && actor->target->player->powers[pw_flashing]) + || P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) >= FixedMul(512*FRACUNIT, actor->scale)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 512*FRACUNIT)) + ; // got a new target + else if (P_LookForPlayers(actor, true, false, 0)) + ; // got a new target + else + return; + } + + // Target hit, retreat! + if (actor->target->player->powers[pw_flashing] > TICRATE || actor->flags2 & MF2_FRET) + { + UINT8 prandom = P_RandomByte(); + actor->z++; // unstick from the floor + actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it. + P_InstaThrust(actor, actor->angle+ANGLE_180, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed + } + // Try to land on top of the player. + else if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(512*FRACUNIT, actor->scale)) + { + fixed_t airtime, gravityadd, zoffs; + + // check gravity in the sector (for later math) + P_CheckGravity(actor, true); + gravityadd = actor->momz; + + actor->z++; // unstick from the floor + actor->momz = FixedMul(locvar1 + (locvar1>>2), actor->scale); // Bounce up in air + + /*badmath = 0; + airtime = 0; + do { + badmath += momz; + momz += gravityadd; + airtime++; + } while(badmath > 0); + airtime = 2*airtime<momz<<1, gravityadd)<<1; // going from 0 to 0 is much simpler + zoffs = (P_GetPlayerHeight(actor->target->player)>>1) + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height, + airtime = FixedDiv((-actor->momz - FixedSqrt(FixedMul(actor->momz,actor->momz)+zoffs)), gravityadd)<<1; // to try and land on their head rather than on their feet + + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + P_InstaThrust(actor, actor->angle, FixedDiv(P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y), airtime)); + } + // Wander semi-randomly towards the player to get closer. + else + { + UINT8 prandom = P_RandomByte(); + actor->z++; // unstick from the floor + actor->momz = FixedMul(locvar1, actor->scale); // Bounce up in air + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) + (P_RandomChance(FRACUNIT/2) ? -prandom : +prandom); // Pick a direction, and randomize it. + P_InstaThrust(actor, actor->angle, FixedMul(FixedMul(actor->info->speed,(locvar2)), actor->scale)); // Move at wandering speed + } + // Boing! + if (actor->info->activesound) S_StartSound(actor, actor->info->activesound); + + if (actor->info->missilestate) // spawn the pogo stick collision box + { + mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate); + pogo->target = actor; + } + + actor->reactiontime = 1; +} + +// Function: A_EggmanBox +// +// Description: Harms the player +// +// var1 = unused +// var2 = unused +// +void A_EggmanBox(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_EggmanBox", actor)) + return; +#endif + if (!actor->target || !actor->target->player) + { + CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n"); + return; + } + + P_DamageMobj(actor->target, actor, actor, 1, 0); // Ow! +} + +// Function: A_TurretFire +// +// Description: Initiates turret fire. +// +// var1 = object # to repeatedly fire +// var2 = distance threshold +// +void A_TurretFire(mobj_t *actor) +{ + INT32 count = 0; + fixed_t dist; + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_TurretFire", actor)) + return; +#endif + + if (locvar2) + dist = FixedMul(locvar2*FRACUNIT, actor->scale); + else + dist = FixedMul(2048*FRACUNIT, actor->scale); + + if (!locvar1) + locvar1 = MT_TURRETLASER; + + while (P_SupermanLook4Players(actor) && count < MAXPLAYERS) + { + if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist) + { + actor->flags2 |= MF2_FIRING; + actor->extravalue1 = locvar1; + break; + } + + count++; + } +} + +// Function: A_SuperTurretFire +// +// Description: Initiates turret fire that even stops Super Sonic. +// +// var1 = object # to repeatedly fire +// var2 = distance threshold +// +void A_SuperTurretFire(mobj_t *actor) +{ + INT32 count = 0; + fixed_t dist; + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SuperTurretFire", actor)) + return; +#endif + + if (locvar2) + dist = FixedMul(locvar2*FRACUNIT, actor->scale); + else + dist = FixedMul(2048*FRACUNIT, actor->scale); + + if (!locvar1) + locvar1 = MT_TURRETLASER; + + while (P_SupermanLook4Players(actor) && count < MAXPLAYERS) + { + if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < dist) + { + actor->flags2 |= MF2_FIRING; + actor->flags2 |= MF2_SUPERFIRE; + actor->extravalue1 = locvar1; + break; + } + + count++; + } +} + +// Function: A_TurretStop +// +// Description: Stops the turret fire. +// +// var1 = Don't play activesound? +// var2 = unused +// +void A_TurretStop(mobj_t *actor) +{ + INT32 locvar1 = var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_TurretStop", actor)) + return; +#endif + + actor->flags2 &= ~MF2_FIRING; + actor->flags2 &= ~MF2_SUPERFIRE; + + if (actor->target && actor->info->activesound && !locvar1) + S_StartSound(actor, actor->info->activesound); +} + +// Function: A_SparkFollow +// +// Description: Used by the hyper sparks to rotate around their target. +// +// var1 = unused +// var2 = unused +// +void A_SparkFollow(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SparkFollow", actor)) + return; +#endif + + if ((!actor->target || (actor->target->health <= 0)) + || (actor->target->player && !actor->target->player->powers[pw_super])) + { + P_RemoveMobj(actor); + return; + } + + actor->angle += FixedAngle(actor->info->damage*FRACUNIT); + P_UnsetThingPosition(actor); + { + const angle_t fa = actor->angle>>ANGLETOFINESHIFT; + actor->x = actor->target->x + FixedMul(FINECOSINE(fa),FixedMul(actor->info->speed, actor->scale)); + actor->y = actor->target->y + FixedMul(FINESINE(fa),FixedMul(actor->info->speed, actor->scale)); + if (actor->target->eflags & MFE_VERTICALFLIP) + actor->z = actor->target->z + actor->target->height - FixedDiv(actor->target->height,3*FRACUNIT); + else + actor->z = actor->target->z + FixedDiv(actor->target->height,3*FRACUNIT) - actor->height; + } + P_SetThingPosition(actor); +} + +// Function: A_BuzzFly +// +// Description: Makes an object slowly fly after a player, in the manner of a Buzz. +// +// var1 = sfx to play +// var2 = length of sfx, set to threshold if played +// +void A_BuzzFly(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BuzzFly", actor)) + return; +#endif + if (actor->flags2 & MF2_AMBUSH) + return; + + if (actor->reactiontime) + actor->reactiontime--; + + // modify target threshold + if (actor->threshold) + { + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + actor->momz = actor->momy = actor->momx = 0; + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + // turn towards movement direction if not there yet + actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + + if (actor->target->health <= 0 || (!actor->threshold && !P_CheckSight(actor, actor->target))) + { + if ((multiplayer || netgame) && P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale))) + return; // got a new target + + actor->momx = actor->momy = actor->momz = 0; + P_SetMobjState(actor, actor->info->spawnstate); // Go back to looking around + return; + } + + // If the player is over 3072 fracunits away, then look for another player + if (P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), + actor->target->z - actor->z) > FixedMul(3072*FRACUNIT, actor->scale)) + { + if (multiplayer || netgame) + P_LookForPlayers(actor, true, false, FixedMul(3072*FRACUNIT, actor->scale)); // maybe get a new target + + return; + } + + // chase towards player + { + INT32 dist, realspeed; + const fixed_t mf = 5*(FRACUNIT/4); + + if (ultimatemode) + realspeed = FixedMul(FixedMul(actor->info->speed,mf), actor->scale); + else + realspeed = FixedMul(actor->info->speed, actor->scale); + + dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, + actor->target->y - actor->y), actor->target->z - actor->z); + + if (dist < 1) + dist = 1; + + actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), realspeed); + actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), realspeed); + actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), realspeed); + + if (actor->z+actor->momz >= actor->waterbottom && actor->watertop > actor->floorz + && actor->z+actor->momz > actor->watertop - FixedMul(256*FRACUNIT, actor->scale) + && actor->z+actor->momz <= actor->watertop) + { + actor->momz = 0; + actor->z = actor->watertop; + } + } + + if (locvar1 != sfx_None && !actor->threshold) + { + S_StartSound(actor, locvar1); + actor->threshold = locvar2; + } +} + +// Function: A_GuardChase +// +// Description: Modified A_Chase for Egg Guard +// +// var1 = unused +// var2 = unused +// +void A_GuardChase(mobj_t *actor) +{ + INT32 delta; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GuardChase", actor)) + return; +#endif + + if (actor->reactiontime) + actor->reactiontime--; + + if (actor->threshold != 42) // In formation... + { + fixed_t speed; + + if (!actor->tracer || !actor->tracer->health) + { + P_SetTarget(&actor->tracer, NULL); + actor->threshold = 42; + P_SetMobjState(actor, actor->info->painstate); + actor->flags |= MF_SPECIAL|MF_SHOOTABLE; + return; + } + + speed = actor->extravalue1*actor->scale; + + if (actor->flags2 & MF2_AMBUSH) + speed <<= 1; + + if (speed + && !P_TryMove(actor, + actor->x + P_ReturnThrustX(actor, actor->angle, speed), + actor->y + P_ReturnThrustY(actor, actor->angle, speed), + false) + && speed > 0) // can't be the same check as previous so that P_TryMove gets to happen. + { + if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_OBJECTSPECIAL)) + actor->angle += ANGLE_90; + else if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_EXTRA)) + actor->angle -= ANGLE_90; + else + actor->angle += ANGLE_180; + } + + if (actor->extravalue1 < actor->info->speed) + actor->extravalue1++; + } + else // Break ranks! + { + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjStateNF(actor, actor->info->spawnstate); + return; + } + + // possibly choose another target + if (multiplayer && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + && P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, (actor->flags2 & MF2_AMBUSH) ? actor->info->speed * 2 : actor->info->speed)) + { + P_NewChaseDir(actor); + actor->movecount += 5; // Increase tics before change in direction allowed. + } + } + + // Now that we've moved, its time for our shield to move! + // Otherwise it'll never act as a proper overlay. + if (actor->tracer && actor->tracer->state + && actor->tracer->state->action.acp1) + { + var1 = actor->tracer->state->var1, var2 = actor->tracer->state->var2; + actor->tracer->state->action.acp1(actor->tracer); + } +} + +// Function: A_EggShield +// +// Description: Modified A_Chase for Egg Guard's shield +// +// var1 = unused +// var2 = unused +// +void A_EggShield(mobj_t *actor) +{ + INT32 i; + player_t *player; + fixed_t blockdist; + fixed_t newx, newy; + fixed_t movex, movey; + angle_t angle; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_EggShield", actor)) + return; +#endif + + if (!actor->target || !actor->target->health) + { + P_RemoveMobj(actor); + return; + } + + newx = actor->target->x + P_ReturnThrustX(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale)); + newy = actor->target->y + P_ReturnThrustY(actor, actor->target->angle, FixedMul(FRACUNIT, actor->scale)); + + movex = newx - actor->x; + movey = newy - actor->y; + + actor->angle = actor->target->angle; + if (actor->target->eflags & MFE_VERTICALFLIP) + { + actor->eflags |= MFE_VERTICALFLIP; + actor->z = actor->target->z + actor->target->height - actor->height; + } + else + actor->z = actor->target->z; + + actor->destscale = actor->target->destscale; + P_SetScale(actor, actor->target->scale); + + actor->floorz = actor->target->floorz; + actor->ceilingz = actor->target->ceilingz; + + if (!movex && !movey) + return; + + P_UnsetThingPosition(actor); + actor->x = newx; + actor->y = newy; + P_SetThingPosition(actor); + + // Search for players to push + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + player = &players[i]; + + if (!player->mo) + continue; + + if (player->mo->z > actor->z + actor->height) + continue; + + if (player->mo->z + player->mo->height < actor->z) + continue; + + blockdist = actor->radius + player->mo->radius; + + if (abs(actor->x - player->mo->x) >= blockdist || abs(actor->y - player->mo->y) >= blockdist) + continue; // didn't hit it + + angle = R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; + + if (angle > ANGLE_90 && angle < ANGLE_270) + continue; + + // Blocked by the shield + player->mo->momx += movex; + player->mo->momy += movey; + return; + } +} + + +// Function: A_SetReactionTime +// +// Description: Sets the object's reaction time. +// +// var1 = 1 (use value in var2); 0 (use info table value) +// var2 = if var1 = 1, then value to set +// +void A_SetReactionTime(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetReactionTime", actor)) + return; +#endif + if (var1) + actor->reactiontime = var2; + else + actor->reactiontime = actor->info->reactiontime; +} + +// Function: A_Boss1Spikeballs +// +// Description: Boss 1 spikeball spawning loop. +// +// var1 = ball number +// var2 = total balls +// +void A_Boss1Spikeballs(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *ball; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss1Spikeballs", actor)) + return; +#endif + + ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL); + P_SetTarget(&ball->target, actor); + ball->movedir = FixedAngle(FixedMul(FixedDiv(locvar1<threshold = ball->radius + actor->radius + ball->info->painchance; + + S_StartSound(ball, ball->info->seesound); + var1 = ball->state->var1, var2 = ball->state->var2; + ball->state->action.acp1(ball); +} + +// Function: A_Boss3TakeDamage +// +// Description: Called when Boss 3 takes damage. +// +// var1 = movecount value +// var2 = unused +// +void A_Boss3TakeDamage(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss3TakeDamage", actor)) + return; +#endif + actor->movecount = var1; + + if (actor->target && actor->target->spawnpoint) + actor->threshold = actor->target->spawnpoint->extrainfo; +} + +// Function: A_Boss3Path +// +// Description: Does pathfinding along Boss 3's nodes. +// +// var1 = unused +// var2 = unused +// +void A_Boss3Path(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss3Path", actor)) + return; +#endif + + if (actor->tracer && actor->tracer->health && actor->tracer->movecount) + actor->movecount |= 1; + else if (actor->movecount & 1) + actor->movecount = 0; + + if (actor->movecount & 2) // We've reached a firing point? + { + // Wait here and pretend to be angry or something. + actor->momx = 0; + actor->momy = 0; + actor->momz = 0; + P_SetTarget(&actor->target, actor->tracer->target); + var1 = 0, var2 = 0; + A_FaceTarget(actor); + if (actor->tracer->state == &states[actor->tracer->info->missilestate]) + P_SetMobjState(actor, actor->info->missilestate); + return; + } + else if (actor->threshold >= 0) // Traveling mode + { + thinker_t *th; + mobj_t *mo2; + fixed_t dist, dist2; + fixed_t speed; + + P_SetTarget(&actor->target, NULL); + + // scan the thinkers + // to find a point that matches + // the number + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold) + { + P_SetTarget(&actor->target, mo2); + break; + } + } + + if (!actor->target) // Should NEVER happen + { + CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d\n", actor->threshold); + return; + } + + dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z); + + if (dist < 1) + dist = 1; + + if (actor->tracer && ((actor->tracer->movedir) + || (actor->tracer->health <= actor->tracer->info->damage))) + speed = actor->info->speed * 2; + else + speed = actor->info->speed; + + actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), speed); + actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), speed); + actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), speed); + + if (actor->momx != 0 || actor->momy != 0) + actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); + + dist2 = P_AproxDistance(P_AproxDistance(actor->target->x - (actor->x + actor->momx), actor->target->y - (actor->y + actor->momy)), actor->target->z - (actor->z + actor->momz)); + + if (dist2 < 1) + dist2 = 1; + + if ((dist >> FRACBITS) <= (dist2 >> FRACBITS)) + { + // If further away, set XYZ of mobj to waypoint location + P_UnsetThingPosition(actor); + actor->x = actor->target->x; + actor->y = actor->target->y; + actor->z = actor->target->z; + actor->momx = actor->momy = actor->momz = 0; + P_SetThingPosition(actor); + + if (actor->threshold == 0) + { + P_RemoveMobj(actor); // Cycle completed. Dummy removed. + return; + } + + // Set to next waypoint in sequence + if (actor->target->spawnpoint) + { + // From the center point, choose one of the five paths + if (actor->target->spawnpoint->angle == 0) + { + P_RemoveMobj(actor); // Cycle completed. Dummy removed. + return; + } + else + actor->threshold = actor->target->spawnpoint->extrainfo; + + // If the deaf flag is set, go into firing mode + if (actor->target->spawnpoint->options & MTF_AMBUSH) + actor->movecount |= 2; + } + else // This should never happen, as well + CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy waypoint has no spawnpoint associated with it.\n"); + } + } +} + +// Function: A_LinedefExecute +// +// Description: Object's location is used to set the calling sector. The tag used is var1. Optionally, if var2 is set, the actor's angle (multiplied by var2) is added to the tag number as well. +// +// var1 = tag +// var2 = add angle to tag (optional) +// +void A_LinedefExecute(mobj_t *actor) +{ + INT32 tagnum; + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_LinedefExecute", actor)) + return; +#endif + + tagnum = locvar1; + // state numbers option is no more, custom states cannot be guaranteed to stay the same number anymore, now that they can be defined by names instead + + if (locvar2) + tagnum += locvar2*(AngleFixed(actor->angle)>>FRACBITS); + + CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecute: Running mobjtype %d's sector with tag %d\n", actor->type, tagnum); + + // tag 32768 displayed in map editors is actually tag -32768, tag 32769 is -32767, 65535 is -1 etc. + P_LinedefExecute((INT16)tagnum, actor, actor->subsector->sector); +} + +// Function: A_PlaySeeSound +// +// Description: Plays the object's seesound. +// +// var1 = unused +// var2 = unused +// +void A_PlaySeeSound(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_PlaySeeSound", actor)) + return; +#endif + if (actor->info->seesound) + S_StartScreamSound(actor, actor->info->seesound); +} + +// Function: A_PlayAttackSound +// +// Description: Plays the object's attacksound. +// +// var1 = unused +// var2 = unused +// +void A_PlayAttackSound(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_PlayAttackSound", actor)) + return; +#endif + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); +} + +// Function: A_PlayActiveSound +// +// Description: Plays the object's activesound. +// +// var1 = unused +// var2 = unused +// +void A_PlayActiveSound(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_PlayActiveSound", actor)) + return; +#endif + if (actor->info->activesound) + S_StartSound(actor, actor->info->activesound); +} + +// Function: A_SmokeTrailer +// +// Description: Adds smoke trails to an object. +// +// var1 = object # to spawn as smoke +// var2 = unused +// +void A_SmokeTrailer(mobj_t *actor) +{ + mobj_t *th; + INT32 locvar1 = var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SmokeTrailer", actor)) + return; +#endif + + if (leveltime % 4) + return; + + // add the smoke behind the rocket + if (actor->eflags & MFE_VERTICALFLIP) + { + th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z + actor->height - FixedMul(mobjinfo[locvar1].height, actor->scale), locvar1); + th->flags2 |= MF2_OBJECTFLIP; + } + else + th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z, locvar1); + P_SetObjectMomZ(th, FRACUNIT, false); + th->destscale = actor->scale; + P_SetScale(th, actor->scale); + th->tics -= P_RandomByte() & 3; + if (th->tics < 1) + th->tics = 1; +} + +// Function: A_SpawnObjectAbsolute +// +// Description: Spawns an object at an absolute position +// +// var1: +// var1 >> 16 = x +// var1 & 65535 = y +// var2: +// var2 >> 16 = z +// var2 & 65535 = type +// +void A_SpawnObjectAbsolute(mobj_t *actor) +{ + INT16 x, y, z; // Want to be sure we can use negative values + mobjtype_t type; + mobj_t *mo; + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnObjectAbsolute", actor)) + return; +#endif + + x = (INT16)(locvar1>>16); + y = (INT16)(locvar1&65535); + z = (INT16)(locvar2>>16); + type = (mobjtype_t)(locvar2&65535); + + mo = P_SpawnMobj(x<angle = actor->angle; + + if (actor->eflags & MFE_VERTICALFLIP) + mo->flags2 |= MF2_OBJECTFLIP; +} + +// Function: A_SpawnObjectRelative +// +// Description: Spawns an object relative to the location of the actor +// +// var1: +// var1 >> 16 = x +// var1 & 65535 = y +// var2: +// var2 >> 16 = z +// var2 & 65535 = type +// +void A_SpawnObjectRelative(mobj_t *actor) +{ + INT16 x, y, z; // Want to be sure we can use negative values + mobjtype_t type; + mobj_t *mo; + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnObjectRelative", actor)) + return; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_SpawnObjectRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); + + x = (INT16)(locvar1>>16); + y = (INT16)(locvar1&65535); + z = (INT16)(locvar2>>16); + type = (mobjtype_t)(locvar2&65535); + + // Spawn objects correctly in reverse gravity. + // NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame + mo = P_SpawnMobj(actor->x + FixedMul(x<scale), + actor->y + FixedMul(y<scale), + (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), type); + + // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn + mo->angle = actor->angle; + + if (actor->eflags & MFE_VERTICALFLIP) + mo->flags2 |= MF2_OBJECTFLIP; + +} + +// Function: A_ChangeAngleRelative +// +// Description: Changes the angle to a random relative value between the min and max. Set min and max to the same value to eliminate randomness +// +// var1 = min +// var2 = max +// +void A_ChangeAngleRelative(mobj_t *actor) +{ + // Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of + // getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result + // rather than the ranges, so <0 and >360 work as possible values. -Red + INT32 locvar1 = var1; + INT32 locvar2 = var2; + //angle_t angle = (P_RandomByte()+1)<<24; + const fixed_t amin = locvar1*FRACUNIT; + const fixed_t amax = locvar2*FRACUNIT; + //const angle_t amin = FixedAngle(locvar1*FRACUNIT); + //const angle_t amax = FixedAngle(locvar2*FRACUNIT); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeAngleRelative", actor)) + return; +#endif + +#ifdef PARANOIA + if (amin > amax) + I_Error("A_ChangeAngleRelative: var1 is greater then var2"); +#endif +/* + if (angle < amin) + angle = amin; + if (angle > amax) + angle = amax;*/ + + actor->angle += FixedAngle(P_RandomRange(amin, amax)); +} + +// Function: A_ChangeAngleAbsolute +// +// Description: Changes the angle to a random absolute value between the min and max. Set min and max to the same value to eliminate randomness +// +// var1 = min +// var2 = max +// +void A_ChangeAngleAbsolute(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + //angle_t angle = (P_RandomByte()+1)<<24; + const fixed_t amin = locvar1*FRACUNIT; + const fixed_t amax = locvar2*FRACUNIT; + //const angle_t amin = FixedAngle(locvar1*FRACUNIT); + //const angle_t amax = FixedAngle(locvar2*FRACUNIT); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeAngleAbsolute", actor)) + return; +#endif + +#ifdef PARANOIA + if (amin > amax) + I_Error("A_ChangeAngleAbsolute: var1 is greater then var2"); +#endif +/* + if (angle < amin) + angle = amin; + if (angle > amax) + angle = amax;*/ + + actor->angle = FixedAngle(P_RandomRange(amin, amax)); +} + +// Function: A_PlaySound +// +// Description: Plays a sound +// +// var1 = sound # to play +// var2: +// 0 = Play sound without an origin +// 1 = Play sound using calling object as origin +// +void A_PlaySound(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_PlaySound", actor)) + return; +#endif + + S_StartSound(locvar2 ? actor : NULL, locvar1); +} + +// Function: A_FindTarget +// +// Description: Finds the nearest/furthest mobj of the specified type and sets actor->target to it. +// +// var1 = mobj type +// var2 = if (0) nearest; else furthest; +// +void A_FindTarget(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *targetedmobj = NULL; + thinker_t *th; + mobj_t *mo2; + fixed_t dist1 = 0, dist2 = 0; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FindTarget", actor)) + return; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); + + // scan the thinkers + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type == (mobjtype_t)locvar1) + { + if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS)) + continue; // Ignore spectators + if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0) + continue; // Ignore dead things + if (targetedmobj == NULL) + { + targetedmobj = mo2; + dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); + } + else + { + dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); + + if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2)) + { + targetedmobj = mo2; + dist2 = dist1; + } + } + } + } + + if (!targetedmobj) + { + CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Unable to find the specified object to target.\n"); + return; // Oops, nothing found.. + } + + CONS_Debug(DBG_GAMELOGIC, "A_FindTarget: Found a target.\n"); + + P_SetTarget(&actor->target, targetedmobj); +} + +// Function: A_FindTracer +// +// Description: Finds the nearest/furthest mobj of the specified type and sets actor->tracer to it. +// +// var1 = mobj type +// var2 = if (0) nearest; else furthest; +// +void A_FindTracer(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *targetedmobj = NULL; + thinker_t *th; + mobj_t *mo2; + fixed_t dist1 = 0, dist2 = 0; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FindTracer", actor)) + return; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); + + // scan the thinkers + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type == (mobjtype_t)locvar1) + { + if (mo2->player && (mo2->player->spectator || mo2->player->pflags & PF_INVIS)) + continue; // Ignore spectators + if ((mo2->player || mo2->flags & MF_ENEMY) && mo2->health <= 0) + continue; // Ignore dead things + if (targetedmobj == NULL) + { + targetedmobj = mo2; + dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); + } + else + { + dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); + + if ((!locvar2 && dist1 < dist2) || (locvar2 && dist1 > dist2)) + { + targetedmobj = mo2; + dist2 = dist1; + } + } + } + } + + if (!targetedmobj) + { + CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Unable to find the specified object to target.\n"); + return; // Oops, nothing found.. + } + + CONS_Debug(DBG_GAMELOGIC, "A_FindTracer: Found a target.\n"); + + P_SetTarget(&actor->tracer, targetedmobj); +} + +// Function: A_SetTics +// +// Description: Sets the animation tics of an object +// +// var1 = tics to set to +// var2 = if this is set, and no var1 is supplied, the mobj's threshold value will be used. +// +void A_SetTics(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetTics", actor)) + return; +#endif + + if (locvar1) + actor->tics = locvar1; + else if (locvar2) + actor->tics = actor->threshold; +} + +// Function: A_SetRandomTics +// +// Description: Sets the animation tics of an object to a random value +// +// var1 = lower bound +// var2 = upper bound +// +void A_SetRandomTics(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetRandomTics", actor)) + return; +#endif + + actor->tics = P_RandomRange(locvar1, locvar2); +} + +// Function: A_ChangeColorRelative +// +// Description: Changes the color of an object +// +// var1 = if (var1 > 0), find target and add its color value to yours +// var2 = if (var1 = 0), color value to add +// +void A_ChangeColorRelative(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeColorRelative", actor)) + return; +#endif + + if (locvar1) + { + // Have you ever seen anything so hideous? + if (actor->target) + actor->color = (UINT8)(actor->color + actor->target->color); + } + else + actor->color = (UINT8)(actor->color + locvar2); +} + +// Function: A_ChangeColorAbsolute +// +// Description: Changes the color of an object by an absolute value. Note: 0 is default colormap. +// +// var1 = if (var1 > 0), set your color to your target's color +// var2 = if (var1 = 0), color value to set to +// +void A_ChangeColorAbsolute(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ChangeColorAbsolute", actor)) + return; +#endif + + if (locvar1) + { + if (actor->target) + actor->color = actor->target->color; + } + else + actor->color = (UINT8)locvar2; +} + +// Function: A_MoveRelative +// +// Description: Moves an object (wrapper for P_Thrust) +// +// var1 = angle +// var2 = force +// +void A_MoveRelative(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MoveRelative", actor)) + return; +#endif + + P_Thrust(actor, actor->angle+FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); +} + +// Function: A_MoveAbsolute +// +// Description: Moves an object (wrapper for P_InstaThrust) +// +// var1 = angle +// var2 = force +// +void A_MoveAbsolute(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MoveAbsolute", actor)) + return; +#endif + + P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); +} + +// Function: A_Thrust +// +// Description: Pushes the object horizontally at its current angle. +// +// var1 = amount of force +// var2 = If 1, xy momentum is lost. If 0, xy momentum is kept +// +void A_Thrust(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Thrust", actor)) + return; +#endif + + if (!locvar1) + CONS_Debug(DBG_GAMELOGIC, "A_Thrust: Var1 not specified!\n"); + + if (locvar2) + P_InstaThrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale)); + else + P_Thrust(actor, actor->angle, FixedMul(locvar1*FRACUNIT, actor->scale)); +} + +// Function: A_ZThrust +// +// Description: Pushes the object up or down. +// +// var1 = amount of force +// var2: +// lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept +// upper 16 bits = If 1, z momentum is lost. If 0, z momentum is kept +// +void A_ZThrust(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ZThrust", actor)) + return; +#endif + + if (!locvar1) + CONS_Debug(DBG_GAMELOGIC, "A_ZThrust: Var1 not specified!\n"); + + if (locvar2 & 65535) + actor->momx = actor->momy = 0; + + if (actor->eflags & MFE_VERTICALFLIP) + actor->z--; + else + actor->z++; + + P_SetObjectMomZ(actor, locvar1*FRACUNIT, !(locvar2 >> 16)); +} + +// Function: A_SetTargetsTarget +// +// Description: Sets your target to the object who your target is targeting. Yikes! If it happens to be NULL, you're just out of luck. +// +// var1: (Your target) +// 0 = target +// 1 = tracer +// var2: (Your target's target) +// 0 = target/tracer's target +// 1 = target/tracer's tracer +// +void A_SetTargetsTarget(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *oldtarg = NULL, *newtarg = NULL; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetTargetsTarget", actor)) + return; +#endif + + // actor's target + if (locvar1) // or tracer + oldtarg = actor->tracer; + else + oldtarg = actor->target; + + if (P_MobjWasRemoved(oldtarg)) + return; + + // actor's target's target! + if (locvar2) // or tracer + newtarg = oldtarg->tracer; + else + newtarg = oldtarg->target; + + if (P_MobjWasRemoved(newtarg)) + return; + + // set actor's new target + if (locvar1) // or tracer + P_SetTarget(&actor->tracer, newtarg); + else + P_SetTarget(&actor->target, newtarg); +} + +// Function: A_SetObjectFlags +// +// Description: Sets the flags of an object +// +// var1 = flag value to set +// var2: +// if var2 == 2, add the flag to the current flags +// else if var2 == 1, remove the flag from the current flags +// else if var2 == 0, set the flags to the exact value +// +void A_SetObjectFlags(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + boolean unlinkthings = false; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetObjectFlags", actor)) + return; +#endif + + if (locvar2 == 2) + locvar1 = actor->flags | locvar1; + else if (locvar2 == 1) + locvar1 = actor->flags & ~locvar1; + + if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links + unlinkthings = true; + + if (unlinkthings) { + P_UnsetThingPosition(actor); + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + } + + actor->flags = locvar1; + + if (unlinkthings) + P_SetThingPosition(actor); +} + +// Function: A_SetObjectFlags2 +// +// Description: Sets the flags2 of an object +// +// var1 = flag value to set +// var2: +// if var2 == 2, add the flag to the current flags +// else if var2 == 1, remove the flag from the current flags +// else if var2 == 0, set the flags to the exact value +// +void A_SetObjectFlags2(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetObjectFlags2", actor)) + return; +#endif + + if (locvar2 == 2) + actor->flags2 |= locvar1; + else if (locvar2 == 1) + actor->flags2 &= ~locvar1; + else + actor->flags2 = locvar1; +} + +// Function: A_BossJetFume +// +// Description: Spawns jet fumes/other attachment miscellany for the boss. To only be used when he is spawned. +// +// var1: +// 0 - Triple jet fume pattern +// 1 - Boss 3's propeller +// 2 - Metal Sonic jet fume +// 3 - Boss 4 jet flame +// var2 = unused +// +void A_BossJetFume(mobj_t *actor) +{ + mobj_t *filler; + INT32 locvar1 = var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BossJetFume", actor)) + return; +#endif + + if (locvar1 == 0) // Boss1 jet fumes + { + fixed_t jetx, jety, jetz; + + jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale)); + jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(64*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + jetz = actor->z + actor->height - FixedMul(38*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale); + else + jetz = actor->z + FixedMul(38*FRACUNIT, actor->scale); + + filler = P_SpawnMobj(jetx, jety, jetz, MT_JETFUME1); + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->fuse = 56; + + if (actor->eflags & MFE_VERTICALFLIP) + jetz = actor->z + actor->height - FixedMul(12*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale); + else + jetz = actor->z + FixedMul(12*FRACUNIT, actor->scale); + + filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), + jety + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), + jetz, MT_JETFUME1); + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->fuse = 57; + + filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), + jety + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), + jetz, MT_JETFUME1); + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->fuse = 58; + + P_SetTarget(&actor->tracer, filler); + } + else if (locvar1 == 1) // Boss 3 propeller + { + fixed_t jetx, jety, jetz; + + jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale)); + jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + jetz = actor->z + actor->height - FixedMul(17*FRACUNIT + mobjinfo[MT_PROPELLER].height, actor->scale); + else + jetz = actor->z + FixedMul(17*FRACUNIT, actor->scale); + + filler = P_SpawnMobj(jetx, jety, jetz, MT_PROPELLER); + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->angle = actor->angle - ANGLE_180; + + P_SetTarget(&actor->tracer, filler); + } + else if (locvar1 == 2) // Metal Sonic jet fumes + { + filler = P_SpawnMobj(actor->x, actor->y, actor->z, MT_JETFUME1); + P_SetTarget(&filler->target, actor); + filler->fuse = 59; + P_SetTarget(&actor->tracer, filler); + filler->destscale = actor->scale/2; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + } + else if (locvar1 == 3) // Boss 4 jet flame + { + fixed_t jetz; + if (actor->eflags & MFE_VERTICALFLIP) + jetz = actor->z + actor->height + FixedMul(50*FRACUNIT - mobjinfo[MT_JETFLAME].height, actor->scale); + else + jetz = actor->z - FixedMul(50*FRACUNIT, actor->scale); + filler = P_SpawnMobj(actor->x, actor->y, jetz, MT_JETFLAME); + P_SetTarget(&filler->target, actor); + // Boss 4 already uses its tracer for other things + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + } +} + +// Function: A_RandomState +// +// Description: Chooses one of the two state numbers supplied randomly. +// +// var1 = state number 1 +// var2 = state number 2 +// +void A_RandomState(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RandomState", actor)) + return; +#endif + + P_SetMobjState(actor, P_RandomChance(FRACUNIT/2) ? locvar1 : locvar2); +} + +// Function: A_RandomStateRange +// +// Description: Chooses a random state within the range supplied. +// +// var1 = Minimum state number to choose. +// var2 = Maximum state number to use. +// +void A_RandomStateRange(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RandomStateRange", actor)) + return; +#endif + + P_SetMobjState(actor, P_RandomRange(locvar1, locvar2)); +} + +// Function: A_DualAction +// +// Description: Calls two actions. Be careful, if you reference the same state this action is called from, you can create an infinite loop. +// +// var1 = state # to use 1st action from +// var2 = state # to use 2nd action from +// +void A_DualAction(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_DualAction", actor)) + return; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_DualAction called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); + + var1 = states[locvar1].var1; + var2 = states[locvar1].var2; +#ifdef HAVE_BLUA + astate = &states[locvar1]; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling First Action (state %d)...\n", locvar1); + states[locvar1].action.acp1(actor); + + var1 = states[locvar2].var1; + var2 = states[locvar2].var2; +#ifdef HAVE_BLUA + astate = &states[locvar2]; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_DualAction: Calling Second Action (state %d)...\n", locvar2); + states[locvar2].action.acp1(actor); +} + +// Function: A_RemoteAction +// +// Description: var1 is the remote object. var2 is the state reference for calling the action called on var1. var1 becomes the actor's target, the action (var2) is called on var1. actor's target is restored +// +// var1 = remote object (-2 uses tracer, -1 uses target) +// var2 = state reference for calling an action +// +void A_RemoteAction(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *originaltarget = actor->target; // Hold on to the target for later. +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RemoteAction", actor)) + return; +#endif + + // If >=0, find the closest target. + if (locvar1 >= 0) + { + ///* DO A_FINDTARGET STUFF */// + mobj_t *targetedmobj = NULL; + thinker_t *th; + mobj_t *mo2; + fixed_t dist1 = 0, dist2 = 0; + + // scan the thinkers + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type == (mobjtype_t)locvar1) + { + if (targetedmobj == NULL) + { + targetedmobj = mo2; + dist2 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); + } + else + { + dist1 = R_PointToDist2(actor->x, actor->y, mo2->x, mo2->y); + + if ((locvar2 && dist1 < dist2) || (!locvar2 && dist1 > dist2)) + { + targetedmobj = mo2; + dist2 = dist1; + } + } + } + } + + if (!targetedmobj) + { + CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Unable to find the specified object to target.\n"); + return; // Oops, nothing found.. + } + + CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Found a target.\n"); + + P_SetTarget(&actor->target, targetedmobj); + + ///* END A_FINDTARGET STUFF */// + } + + // If -2, use the tracer as the target + else if (locvar1 == -2) + P_SetTarget(&actor->target, actor->tracer); + // if -1 or anything else, just use the target. + + if (actor->target) + { + // Steal the var1 and var2 from "locvar2" + var1 = states[locvar2].var1; + var2 = states[locvar2].var2; +#ifdef HAVE_BLUA + astate = &states[locvar2]; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_RemoteAction: Calling action on %p\n" + "var1 is %d\nvar2 is %d\n", actor->target, var1, var2); + states[locvar2].action.acp1(actor->target); + } + + P_SetTarget(&actor->target, originaltarget); // Restore the original target. +} + +// Function: A_ToggleFlameJet +// +// Description: Turns a flame jet on and off. +// +// var1 = unused +// var2 = unused +// +void A_ToggleFlameJet(mobj_t* actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ToggleFlameJet", actor)) + return; +#endif + // threshold - off delay + // movecount - on timer + + if (actor->flags2 & MF2_FIRING) + { + actor->flags2 &= ~MF2_FIRING; + + if (actor->threshold) + actor->tics = actor->threshold; + } + else + { + actor->flags2 |= MF2_FIRING; + + if (actor->movecount) + actor->tics = actor->movecount; + } +} + +// Function: A_OrbitNights +// +// Description: Used by Chaos Emeralds to orbit around Nights (aka Super Sonic.) +// +// var1 = Angle adjustment (aka orbit speed) +// var2 = Lower four bits: height offset, Upper 4 bits = set if object is Nightopian Helper +// +void A_OrbitNights(mobj_t* actor) +{ + INT32 ofs = (var2 & 0xFFFF); + boolean ishelper = (var2 & 0xFFFF0000); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_OrbitNights", actor)) + return; +#endif + + if (!actor->target || !actor->target->player || + !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE) || !actor->target->player->nightstime + // Also remove this object if they no longer have a NiGHTS helper + || (ishelper && !actor->target->player->powers[pw_nights_helper])) + { + P_RemoveMobj(actor); + return; + } + else + { + actor->extravalue1 += var1; + P_UnsetThingPosition(actor); + { + const angle_t fa = (angle_t)actor->extravalue1 >> ANGLETOFINESHIFT; + const angle_t ofa = ((angle_t)actor->extravalue1 + (ofs*ANG1)) >> ANGLETOFINESHIFT; + + const fixed_t fc = FixedMul(FINECOSINE(fa),FixedMul(32*FRACUNIT, actor->scale)); + const fixed_t fh = FixedMul(FINECOSINE(ofa),FixedMul(20*FRACUNIT, actor->scale)); + const fixed_t fs = FixedMul(FINESINE(fa),FixedMul(32*FRACUNIT, actor->scale)); + + actor->x = actor->target->x + fc; + actor->y = actor->target->y + fs; + actor->z = actor->target->z + fh + FixedMul(16*FRACUNIT, actor->scale); + + // Semi-lazy hack + actor->angle = (angle_t)actor->extravalue1 + ANGLE_90; + } + P_SetThingPosition(actor); + + if (ishelper) // Flash a helper that's about to be removed. + { + if ((actor->target->player->powers[pw_nights_helper] < TICRATE) + && (actor->target->player->powers[pw_nights_helper] & 1)) + actor->flags2 |= MF2_DONTDRAW; + else + actor->flags2 &= ~MF2_DONTDRAW; + } + } +} + +// Function: A_GhostMe +// +// Description: Spawns a "ghost" mobj of this actor, ala spindash trails and the minus's digging "trails" +// +// var1 = duration in tics +// var2 = unused +// +void A_GhostMe(mobj_t *actor) +{ + INT32 locvar1 = var1; + mobj_t *ghost; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_GhostMe", actor)) + return; +#endif + ghost = P_SpawnGhostMobj(actor); + if (ghost && locvar1 > 0) + ghost->fuse = locvar1; +} + +// Function: A_SetObjectState +// +// Description: Changes the state of an object's target/tracer. +// +// var1 = state number +// var2: +// 0 = target +// 1 = tracer +// +void A_SetObjectState(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *target; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetObjectState", actor)) + return; +#endif + + if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer)) + { + if (cv_debug) + CONS_Printf("A_SetObjectState: No target to change state!\n"); + return; + } + + if (!locvar2) // target + target = actor->target; + else // tracer + target = actor->tracer; + + if (target->health > 0) + { + if (!target->player) + P_SetMobjState(target, locvar1); + else + P_SetPlayerMobjState(target, locvar1); + } +} + +// Function: A_SetObjectTypeState +// +// Description: Changes the state of all active objects of a certain type in a certain range of the actor. +// +// var1 = state number +// var2: +// lower 16 bits = type +// upper 16 bits = range (if == 0, across whole map) +// +void A_SetObjectTypeState(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + const UINT16 loc2lw = (UINT16)(locvar2 & 65535); + const UINT16 loc2up = (UINT16)(locvar2 >> 16); + + thinker_t *th; + mobj_t *mo2; + fixed_t dist = 0; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetObjectTypeState", actor)) + return; +#endif + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type == (mobjtype_t)loc2lw) + { + dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y); + + if (mo2->health > 0) + { + if (loc2up == 0) + P_SetMobjState(mo2, locvar1); + else + { + if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale)) + P_SetMobjState(mo2, locvar1); + } + } + } + } +} + +// Function: A_KnockBack +// +// Description: Knocks back the object's target at its current speed. +// +// var1: +// 0 = target +// 1 = tracer +// var2 = unused +// +void A_KnockBack(mobj_t *actor) +{ + INT32 locvar1 = var1; + mobj_t *target; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_KnockBack", actor)) + return; +#endif + + if (!locvar1) + target = actor->target; + else + target = actor->tracer; + + if (!target) + { + if(cv_debug) + CONS_Printf("A_KnockBack: No target!\n"); + return; + } + + target->momx *= -1; + target->momy *= -1; +} + +// Function: A_PushAway +// +// Description: Pushes an object's target away from the calling object. +// +// var1 = amount of force +// var2: +// lower 16 bits = If 1, xy momentum is lost. If 0, xy momentum is kept +// upper 16 bits = 0 - target, 1 - tracer +// +void A_PushAway(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *target; // target + angle_t an; // actor to target angle +#ifdef HAVE_BLUA + if (LUA_CallAction("A_PushAway", actor)) + return; +#endif + + if ((!(locvar2 >> 16) && !actor->target) || ((locvar2 >> 16) && !actor->tracer)) + return; + + if (!locvar1) + CONS_Printf("A_Thrust: Var1 not specified!\n"); + + if (!(locvar2 >> 16)) // target + target = actor->target; + else // tracer + target = actor->tracer; + + an = R_PointToAngle2(actor->x, actor->y, target->x, target->y); + + if (locvar2 & 65535) + P_InstaThrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale)); + else + P_Thrust(target, an, FixedMul(locvar1*FRACUNIT, actor->scale)); +} + +// Function: A_RingDrain +// +// Description: Drain targeted player's rings. +// +// var1 = ammount of drained rings +// var2 = unused +// +void A_RingDrain(mobj_t *actor) +{ + INT32 locvar1 = var1; + player_t *player; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RingDrain", actor)) + return; +#endif + + if (!actor->target || !actor->target->player) + { + if(cv_debug) + CONS_Printf("A_RingDrain: No player targeted!\n"); + return; + } + + player = actor->target->player; + P_GivePlayerRings(player, -min(locvar1, player->rings)); +} + +// Function: A_SplitShot +// +// Description: Shoots 2 missiles that hit next to the player. +// +// var1 = target x-y-offset +// var2: +// lower 16 bits = missile type +// upper 16 bits = height offset +// +void A_SplitShot(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + const UINT16 loc2lw = (UINT16)(locvar2 & 65535); + const UINT16 loc2up = (UINT16)(locvar2 >> 16); + const fixed_t offs = (fixed_t)(locvar1*FRACUNIT); + const fixed_t hoffs = (fixed_t)(loc2up*FRACUNIT); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SplitShot", actor)) + return; +#endif + + A_FaceTarget(actor); + { + const angle_t an = (actor->angle + ANGLE_90) >> ANGLETOFINESHIFT; + const fixed_t fasin = FINESINE(an); + const fixed_t facos = FINECOSINE(an); + fixed_t xs = FixedMul(facos,FixedMul(offs, actor->scale)); + fixed_t ys = FixedMul(fasin,FixedMul(offs, actor->scale)); + fixed_t z; + + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(hoffs, actor->scale); + else + z = actor->z + FixedMul(hoffs, actor->scale); + + P_SpawnPointMissile(actor, actor->target->x+xs, actor->target->y+ys, actor->target->z, loc2lw, actor->x, actor->y, z); + P_SpawnPointMissile(actor, actor->target->x-xs, actor->target->y-ys, actor->target->z, loc2lw, actor->x, actor->y, z); + } +} + +// Function: A_MissileSplit +// +// Description: If the object is a missile it will create a new missile with an alternate flight path owned by the one who shot the former missile. +// +// var1 = splitting missile type +// var2 = splitting angle +// +void A_MissileSplit(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MissileSplit", actor)) + return; +#endif + if (actor->eflags & MFE_VERTICALFLIP) + P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z+actor->height, locvar2); + else + P_SpawnAlteredDirectionMissile(actor, locvar1, actor->x, actor->y, actor->z, locvar2); +} + +// Function: A_MultiShot +// +// Description: Shoots objects horizontally that spread evenly in all directions. +// +// var1: +// lower 16 bits = number of missiles +// upper 16 bits = missile type # +// var2 = height offset +// +void A_MultiShot(mobj_t *actor) +{ + fixed_t z, xr, yr; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + const UINT16 loc1lw = (UINT16)(locvar1 & 65535); + const UINT16 loc1up = (UINT16)(locvar1 >> 16); + INT32 count = 0; + fixed_t ad; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MultiShot", actor)) + return; +#endif + + if (actor->target) + A_FaceTarget(actor); + + if(loc1lw > 90) + ad = FixedMul(90*FRACUNIT, actor->scale); + else + ad = FixedMul(loc1lw*FRACUNIT, actor->scale); + + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(48*FRACUNIT + locvar2*FRACUNIT, actor->scale); + xr = FixedMul((P_SignedRandom()/3)<scale); // please note p_mobj.c's P_Rand() abuse + yr = FixedMul((P_SignedRandom()/3)<scale); // of rand(), RAND_MAX and signness mess + + while(count <= loc1lw && loc1lw >= 1) + { + const angle_t fa = FixedAngleC(count*FRACUNIT*360, ad)>>ANGLETOFINESHIFT; + const fixed_t rc = FINECOSINE(fa); + const fixed_t rs = FINESINE(fa); + const fixed_t xrc = FixedMul(xr, rc); + const fixed_t yrs = FixedMul(yr, rs); + const fixed_t xrs = FixedMul(xr, rs); + const fixed_t yrc = FixedMul(yr, rc); + + P_SpawnPointMissile(actor, xrc-yrs+actor->x, xrs+yrc+actor->y, z, loc1up, actor->x, actor->y, z); + count++; + } + + if (!(actor->flags & MF_BOSS)) + { + if (ultimatemode) + actor->reactiontime = actor->info->reactiontime*TICRATE; + else + actor->reactiontime = actor->info->reactiontime*TICRATE*2; + } +} + +// Function: A_InstaLoop +// +// Description: Makes the object move along a 2d (view angle, z) polygon. +// +// var1: +// lower 16 bits = current step +// upper 16 bits = maximum step # +// var2 = force +// +void A_InstaLoop(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t force = max(locvar2, 1)*FRACUNIT; // defaults to 1 if var2 < 1 + const UINT16 loc1lw = (UINT16)(locvar1 & 65535); + const UINT16 loc1up = (UINT16)(locvar1 >> 16); + const angle_t fa = FixedAngleC(loc1lw*FRACUNIT*360, loc1up*FRACUNIT)>>ANGLETOFINESHIFT; + const fixed_t ac = FINECOSINE(fa); + const fixed_t as = FINESINE(fa); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_InstaLoop", actor)) + return; +#endif + + P_InstaThrust(actor, actor->angle, FixedMul(ac, FixedMul(force, actor->scale))); + P_SetObjectMomZ(actor, FixedMul(as, force), false); +} + +// Function: A_Custom3DRotate +// +// Description: Rotates the actor around its target in 3 dimensions. +// +// var1: +// lower 16 bits = radius in fracunits +// upper 16 bits = vertical offset +// var2: +// lower 16 bits = vertical rotation speed in 1/10 fracunits per tic +// upper 16 bits = horizontal rotation speed in 1/10 fracunits per tic +// +void A_Custom3DRotate(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + const UINT16 loc1lw = (UINT16)(locvar1 & 65535); + const UINT16 loc1up = (UINT16)(locvar1 >> 16); + const UINT16 loc2lw = (UINT16)(locvar2 & 65535); + const UINT16 loc2up = (UINT16)(locvar2 >> 16); + + const fixed_t radius = FixedMul(loc1lw*FRACUNIT, actor->scale); + const fixed_t hOff = FixedMul(loc1up*FRACUNIT, actor->scale); + const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale); + const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Custom3DRotate", actor)) + return; +#endif + + if (actor->target->health == 0) + { + P_RemoveMobj(actor); + return; + } + + if (!actor->target) // This should NEVER happen. + { + if (cv_debug) + CONS_Printf("Error: Object has no target\n"); + P_RemoveMobj(actor); + return; + } + if (hspeed==0 && vspeed==0) + { + CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n"); + return; + } + + actor->angle += FixedAngle(hspeed); + actor->movedir += FixedAngle(vspeed); + P_UnsetThingPosition(actor); + { + const angle_t fa = actor->angle>>ANGLETOFINESHIFT; + + if (vspeed == 0 && hspeed != 0) + { + actor->x = actor->target->x + FixedMul(FINECOSINE(fa),radius); + actor->y = actor->target->y + FixedMul(FINESINE(fa),radius); + actor->z = actor->target->z + actor->target->height/2 - actor->height/2 + hOff; + } + else + { + const angle_t md = actor->movedir>>ANGLETOFINESHIFT; + actor->x = actor->target->x + FixedMul(FixedMul(FINESINE(md),FINECOSINE(fa)),radius); + actor->y = actor->target->y + FixedMul(FixedMul(FINESINE(md),FINESINE(fa)),radius); + actor->z = actor->target->z + FixedMul(FINECOSINE(md),radius) + actor->target->height/2 - actor->height/2 + hOff; + } + } + P_SetThingPosition(actor); +} + +// Function: A_SearchForPlayers +// +// Description: Checks if the actor has targeted a vulnerable player. If not a new player will be searched all around. If no players are available the object can call a specific state. (Useful for not moving enemies) +// +// var1: +// if var1 == 0, if necessary call state with same state number as var2 +// else, do not call a specific state if no players are available +// var2 = state number +// +void A_SearchForPlayers(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SearchForPlayers", actor)) + return; +#endif + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + if(locvar1==0) + { + P_SetMobjStateNF(actor, locvar2); + return; + } + } +} + +// Function: A_CheckRandom +// +// Description: Calls a state by chance. +// +// var1: +// lower 16 bits = denominator +// upper 16 bits = numerator (defaults to 1 if zero) +// var2 = state number +// +void A_CheckRandom(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t chance = FRACUNIT; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckRandom", actor)) + return; +#endif + if ((locvar1 & 0xFFFF) == 0) + return; + + // The PRNG doesn't suck anymore, OK? + if (locvar1 >> 16) + chance *= (locvar1 >> 16); + chance /= (locvar1 & 0xFFFF); + + if (P_RandomChance(chance)) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckTargetRings +// +// Description: Calls a state depending on the ammount of rings currently owned by targeted players. +// +// var1 = if player rings >= var1 call state +// var2 = state number +// +void A_CheckTargetRings(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckTargetRings", actor)) + return; +#endif + + if (!(actor->target) || !(actor->target->player)) + return; + + if (actor->target->player->rings >= locvar1) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckRings +// +// Description: Calls a state depending on the ammount of rings currently owned by all players. +// +// var1 = if player rings >= var1 call state +// var2 = state number +// +void A_CheckRings(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + INT32 i, cntr = 0; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckRings", actor)) + return; +#endif + + for (i = 0; i < MAXPLAYERS; i++) + cntr += players[i].rings; + + if (cntr >= locvar1) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckTotalRings +// +// Description: Calls a state depending on the maximum ammount of rings owned by all players during this try. +// +// var1 = if total player rings >= var1 call state +// var2 = state number +// +void A_CheckTotalRings(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + INT32 i, cntr = 0; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckTotalRings", actor)) + return; +#endif + + for (i = 0; i < MAXPLAYERS; i++) + cntr += players[i].totalring; + + if (cntr >= locvar1) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckHealth +// +// Description: Calls a state depending on the object's current health. +// +// var1 = if health <= var1 call state +// var2 = state number +// +void A_CheckHealth(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckHealth", actor)) + return; +#endif + + if (actor->health <= locvar1) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckRange +// +// Description: Calls a state if the object's target is in range. +// +// var1: +// lower 16 bits = range +// upper 16 bits = 0 - target, 1 - tracer +// var2 = state number +// +void A_CheckRange(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t dist; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckRange", actor)) + return; +#endif + + if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) + return; + + if (!(locvar1 >> 16)) //target + dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); + else //tracer + dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); + + if (dist <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale)) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckHeight +// +// Description: Calls a state if the object and it's target have a height offset <= var1 compared to each other. +// +// var1: +// lower 16 bits = height offset +// upper 16 bits = 0 - target, 1 - tracer +// var2 = state number +// +void A_CheckHeight(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t height; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckHeight", actor)) + return; +#endif + + if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) + return; + + if (!(locvar1 >> 16)) // target + height = abs(actor->target->z - actor->z); + else // tracer + height = abs(actor->tracer->z - actor->z); + + if (height <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale)) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckTrueRange +// +// Description: Calls a state if the object's target is in true range. (Checks height, too.) +// +// var1: +// lower 16 bits = range +// upper 16 bits = 0 - target, 1 - tracer +// var2 = state number +// +void A_CheckTrueRange(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t height; // vertical range + fixed_t dist; // horizontal range + fixed_t l; // true range +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckTrueRange", actor)) + return; +#endif + + if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) + return; + + if (!(locvar1 >> 16)) // target + { + height = actor->target->z - actor->z; + dist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); + + } + else // tracer + { + height = actor->tracer->z - actor->z; + dist = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); + } + + l = P_AproxDistance(dist, height); + + if (l <= FixedMul((locvar1 & 65535)*FRACUNIT, actor->scale)) + P_SetMobjState(actor, locvar2); + +} + +// Function: A_CheckThingCount +// +// Description: Calls a state depending on the number of active things in range. +// +// var1: +// lower 16 bits = number of things +// upper 16 bits = thing type +// var2: +// lower 16 bits = state to call +// upper 16 bits = range (if == 0, check whole map) +// +void A_CheckThingCount(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + const UINT16 loc1lw = (UINT16)(locvar1 & 65535); + const UINT16 loc1up = (UINT16)(locvar1 >> 16); + const UINT16 loc2lw = (UINT16)(locvar2 & 65535); + const UINT16 loc2up = (UINT16)(locvar2 >> 16); + + INT32 count = 0; + thinker_t *th; + mobj_t *mo2; + fixed_t dist = 0; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckThingCount", actor)) + return; +#endif + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type == (mobjtype_t)loc1up) + { + dist = P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y); + + if (loc2up == 0) + count++; + else + { + if (dist <= FixedMul(loc2up*FRACUNIT, actor->scale)) + count++; + } + } + } + + if(loc1lw <= count) + P_SetMobjState(actor, loc2lw); +} + +// Function: A_CheckAmbush +// +// Description: Calls a state if the actor is behind its targeted player. +// +// var1: +// 0 = target +// 1 = tracer +// var2 = state number +// +void A_CheckAmbush(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + angle_t at; // angle target is currently facing + angle_t atp; // actor to target angle + angle_t an; // angle between at and atp + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckAmbush", actor)) + return; +#endif + + if ((!locvar1 && !actor->target) || (locvar1 && !actor->tracer)) + return; + + if (!locvar1) // target + { + at = actor->target->angle; + atp = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + } + else // tracer + { + at = actor->tracer->angle; + atp = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); + } + + an = atp - at; + + if (an > ANGLE_180) // flip angle if bigger than 180 + an = InvAngle(an); + + if (an < ANGLE_90+ANGLE_22h) // within an angle of 112.5 from each other? + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckCustomValue +// +// Description: Calls a state depending on the object's custom value. +// +// var1 = if custom value >= var1, call state +// var2 = state number +// +void A_CheckCustomValue(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckCustomValue", actor)) + return; +#endif + + if (actor->cusval >= locvar1) + P_SetMobjState(actor, locvar2); +} + +// Function: A_CheckCusValMemo +// +// Description: Calls a state depending on the object's custom memory value. +// +// var1 = if memory value >= var1, call state +// var2 = state number +// +void A_CheckCusValMemo(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckCusValMemo", actor)) + return; +#endif + + if (actor->cvmem >= locvar1) + P_SetMobjState(actor, locvar2); +} + +// Function: A_SetCustomValue +// +// Description: Changes the custom value of an object. +// +// var1 = manipulating value +// var2: +// if var2 == 5, multiply the custom value by var1 +// else if var2 == 4, divide the custom value by var1 +// else if var2 == 3, apply modulo var1 to the custom value +// else if var2 == 2, add var1 to the custom value +// else if var2 == 1, substract var1 from the custom value +// else if var2 == 0, replace the custom value with var1 +// +void A_SetCustomValue(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetCustomValue", actor)) + return; +#endif + + if (cv_debug) + CONS_Printf("Init custom value is %d\n", actor->cusval); + + if (locvar1 == 0 && locvar2 == 4) + return; // DON'T DIVIDE BY ZERO + + // no need for a "temp" value here, just modify the cusval directly + if (locvar2 == 5) // multiply + actor->cusval *= locvar1; + else if (locvar2 == 4) // divide + actor->cusval /= locvar1; + else if (locvar2 == 3) // modulo + actor->cusval %= locvar1; + else if (locvar2 == 2) // add + actor->cusval += locvar1; + else if (locvar2 == 1) // subtract + actor->cusval -= locvar1; + else // replace + actor->cusval = locvar1; + + if(cv_debug) + CONS_Printf("New custom value is %d\n", actor->cusval); +} + +// Function: A_UseCusValMemo +// +// Description: Memorizes or recalls a current custom value. +// +// var1: +// if var1 == 1, manipulate memory value +// else, recall memory value replacing the custom value +// var2: +// if var2 == 5, mem = mem*cv || cv = cv*mem +// else if var2 == 4, mem = mem/cv || cv = cv/mem +// else if var2 == 3, mem = mem%cv || cv = cv%mem +// else if var2 == 2, mem += cv || cv += mem +// else if var2 == 1, mem -= cv || cv -= mem +// else mem = cv || cv = mem +// +void A_UseCusValMemo(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + INT32 temp = actor->cusval; // value being manipulated + INT32 tempM = actor->cvmem; // value used to manipulate temp with +#ifdef HAVE_BLUA + if (LUA_CallAction("A_UseCusValMemo", actor)) + return; +#endif + + if (locvar1 == 1) // cvmem being changed using cusval + { + temp = actor->cvmem; + tempM = actor->cusval; + } + else // cusval being changed with cvmem + { + temp = actor->cusval; + tempM = actor->cvmem; + } + + if (tempM == 0 && locvar2 == 4) + return; // DON'T DIVIDE BY ZERO + + // now get new value for cusval/cvmem using the other + if (locvar2 == 5) // multiply + temp *= tempM; + else if (locvar2 == 4) // divide + temp /= tempM; + else if (locvar2 == 3) // modulo + temp %= tempM; + else if (locvar2 == 2) // add + temp += tempM; + else if (locvar2 == 1) // subtract + temp -= tempM; + else // replace + temp = tempM; + + // finally, give cusval/cvmem the new value! + if (locvar1 == 1) + actor->cvmem = temp; + else + actor->cusval = temp; +} + +// Function: A_RelayCustomValue +// +// Description: Manipulates the custom value of the object's target/tracer. +// +// var1: +// lower 16 bits: +// if var1 == 0, use own custom value +// else, use var1 value +// upper 16 bits = 0 - target, 1 - tracer +// var2: +// if var2 == 5, multiply the target's custom value by var1 +// else if var2 == 4, divide the target's custom value by var1 +// else if var2 == 3, apply modulo var1 to the target's custom value +// else if var2 == 2, add var1 to the target's custom value +// else if var2 == 1, substract var1 from the target's custom value +// else if var2 == 0, replace the target's custom value with var1 +// +void A_RelayCustomValue(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + INT32 temp; // reference value - var1 lower 16 bits changes this + INT32 tempT; // target's value - changed to tracer if var1 upper 16 bits set, then modified to become final value +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RelayCustomValue", actor)) + return; +#endif + + if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) + return; + + // reference custom value + if ((locvar1 & 65535) == 0) + temp = actor->cusval; // your own custom value + else + temp = (locvar1 & 65535); // var1 value + + if (!(locvar1 >> 16)) // target's custom value + tempT = actor->target->cusval; + else // tracer's custom value + tempT = actor->tracer->cusval; + + if (temp == 0 && locvar2 == 4) + return; // DON'T DIVIDE BY ZERO + + // now get new cusval using target's and the reference + if (locvar2 == 5) // multiply + tempT *= temp; + else if (locvar2 == 4) // divide + tempT /= temp; + else if (locvar2 == 3) // modulo + tempT %= temp; + else if (locvar2 == 2) // add + tempT += temp; + else if (locvar2 == 1) // subtract + tempT -= temp; + else // replace + tempT = temp; + + // finally, give target/tracer the new cusval! + if (!(locvar1 >> 16)) // target + actor->target->cusval = tempT; + else // tracer + actor->tracer->cusval = tempT; +} + +// Function: A_CusValAction +// +// Description: Calls an action from a reference state applying custom value parameters. +// +// var1 = state # to use action from +// var2: +// if var2 == 5, only replace new action's var2 with memory value +// else if var2 == 4, only replace new action's var1 with memory value +// else if var2 == 3, replace new action's var2 with custom value and var1 with memory value +// else if var2 == 2, replace new action's var1 with custom value and var2 with memory value +// else if var2 == 1, only replace new action's var2 with custom value +// else if var2 == 0, only replace new action's var1 with custom value +// +void A_CusValAction(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CusValAction", actor)) + return; +#endif + + if (locvar2 == 5) + { + var1 = states[locvar1].var1; + var2 = (INT32)actor->cvmem; + } + else if (locvar2 == 4) + { + var1 = (INT32)actor->cvmem; + var2 = states[locvar1].var2; + } + else if (locvar2 == 3) + { + var1 = (INT32)actor->cvmem; + var2 = (INT32)actor->cusval; + } + else if (locvar2 == 2) + { + var1 = (INT32)actor->cusval; + var2 = (INT32)actor->cvmem; + } + else if (locvar2 == 1) + { + var1 = states[locvar1].var1; + var2 = (INT32)actor->cusval; + } + else + { + var1 = (INT32)actor->cusval; + var2 = states[locvar1].var2; + } + +#ifdef HAVE_BLUA + astate = &states[locvar1]; +#endif + states[locvar1].action.acp1(actor); +} + +// Function: A_ForceStop +// +// Description: Actor immediately stops its current movement. +// +// var1: +// if var1 == 0, stop x-y-z-movement +// else, stop x-y-movement only +// var2 = unused +// +void A_ForceStop(mobj_t *actor) +{ + INT32 locvar1 = var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ForceStop", actor)) + return; +#endif + + actor->momx = actor->momy = 0; + if (locvar1 == 0) + actor->momz = 0; +} + +// Function: A_ForceWin +// +// Description: Makes all players win the level. +// +// var1 = unused +// var2 = unused +// +void A_ForceWin(mobj_t *actor) +{ + INT32 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ForceWin", actor)) + return; +#else + (void)actor; +#endif + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && ((players[i].mo && players[i].mo->health) + || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) + break; + } + + if (i == MAXPLAYERS) + return; + + for (i = 0; i < MAXPLAYERS; i++) + P_DoPlayerExit(&players[i]); +} + +// Function: A_SpikeRetract +// +// Description: Toggles actor solid flag. +// +// var1: +// if var1 == 0, actor no collide +// else, actor solid +// var2 = unused +// +void A_SpikeRetract(mobj_t *actor) +{ + INT32 locvar1 = var1; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpikeRetract", actor)) + return; +#endif + + if (actor->flags & MF_NOBLOCKMAP) + return; + + if (locvar1 == 0) + { + actor->flags &= ~MF_SOLID; + actor->flags |= MF_NOCLIPTHING; + } + else + { + actor->flags |= MF_SOLID; + actor->flags &= ~MF_NOCLIPTHING; + } + if (actor->flags & MF_SOLID) + P_CheckPosition(actor, actor->x, actor->y); +} + +// Function: A_InfoState +// +// Description: Set mobj state to one predefined in mobjinfo. +// +// var1: +// if var1 == 0, set actor to spawnstate +// else if var1 == 1, set actor to seestate +// else if var1 == 2, set actor to meleestate +// else if var1 == 3, set actor to missilestate +// else if var1 == 4, set actor to deathstate +// else if var1 == 5, set actor to xdeathstate +// else if var1 == 6, set actor to raisestate +// var2 = unused +// +void A_InfoState(mobj_t *actor) +{ + INT32 locvar1 = var1; + switch (locvar1) + { + case 0: + if (actor->state != &states[actor->info->spawnstate]) + P_SetMobjState(actor, actor->info->spawnstate); + break; + case 1: + if (actor->state != &states[actor->info->seestate]) + P_SetMobjState(actor, actor->info->seestate); + break; + case 2: + if (actor->state != &states[actor->info->meleestate]) + P_SetMobjState(actor, actor->info->meleestate); + break; + case 3: + if (actor->state != &states[actor->info->missilestate]) + P_SetMobjState(actor, actor->info->missilestate); + break; + case 4: + if (actor->state != &states[actor->info->deathstate]) + P_SetMobjState(actor, actor->info->deathstate); + break; + case 5: + if (actor->state != &states[actor->info->xdeathstate]) + P_SetMobjState(actor, actor->info->xdeathstate); + break; + case 6: + if (actor->state != &states[actor->info->raisestate]) + P_SetMobjState(actor, actor->info->raisestate); + break; + default: + break; + } +} + +// Function: A_Repeat +// +// Description: Returns to state var2 until animation has been used var1 times, then continues to nextstate. +// +// var1 = repeat count +// var2 = state to return to if extravalue2 > 0 +// +void A_Repeat(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Repeat", actor)) + return; +#endif + + if (locvar1 && (!actor->extravalue2 || actor->extravalue2 > locvar1)) + actor->extravalue2 = locvar1; + + if (--actor->extravalue2 > 0) + P_SetMobjState(actor, locvar2); +} + +// Function: A_SetScale +// +// Description: Changes the scale of the actor or its target/tracer +// +// var1 = new scale (1*FRACUNIT = 100%) +// var2: +// upper 16 bits: 0 = actor, 1 = target, 2 = tracer +// lower 16 bits: 0 = instant change, 1 = smooth change +// +void A_SetScale(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *target; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SetScale", actor)) + return; +#endif + + if (locvar1 <= 0) + { + if(cv_debug) + CONS_Printf("A_SetScale: Valid scale not specified!\n"); + return; + } + + if ((locvar2>>16) == 1) + target = actor->target; + else if ((locvar2>>16) == 2) + target = actor->tracer; + else // default to yourself! + target = actor; + + if (!target) + { + if(cv_debug) + CONS_Printf("A_SetScale: No target!\n"); + return; + } + + target->destscale = locvar1; // destination scale + if (!(locvar2 & 65535)) + P_SetScale(target, locvar1); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 anyway +} + +// Function: A_RemoteDamage +// +// Description: Damages, kills or even removes either the actor or its target/tracer. Actor acts as the inflictor/source unless harming itself +// +// var1 = Mobj affected: 0 - actor, 1 - target, 2 - tracer +// var2 = Action: 0 - Damage, 1 - Kill, 2 - Remove +// +void A_RemoteDamage(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *target; // we MUST have a target + mobj_t *source = NULL; // on the other hand we don't necessarily need a source +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RemoteDamage", actor)) + return; +#endif + if (locvar1 == 1) + target = actor->target; + else if (locvar1 == 2) + target = actor->tracer; + else // default to yourself! + target = actor; + + if (locvar1 == 1 || locvar1 == 2) + source = actor; + + if (!target) + { + if(cv_debug) + CONS_Printf("A_RemoteDamage: No target!\n"); + return; + } + + if (locvar2 == 1) // Kill mobj! + { + if (target->player) // players die using P_DamageMobj instead for some reason + P_DamageMobj(target, source, source, 1, DMG_INSTAKILL); + else + P_KillMobj(target, source, source, 0); + } + else if (locvar2 == 2) // Remove mobj! + { + if (target->player) //don't remove players! + return; + + P_RemoveMobj(target); + } + else // default: Damage mobj! + P_DamageMobj(target, source, source, 1, 0); +} + +// Function: A_HomingChase +// +// Description: Actor chases directly towards its destination object +// +// var1 = speed multiple +// var2 = destination: 0 = target, 1 = tracer +// +void A_HomingChase(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *dest; + fixed_t dist; + fixed_t speedmul; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_HomingChase", actor)) + return; +#endif + + if (locvar2 == 1) + dest = actor->tracer; + else //default + dest = actor->target; + + if (!dest || !dest->health) + return; + + actor->angle = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y); + + dist = P_AproxDistance(P_AproxDistance(dest->x - actor->x, dest->y - actor->y), dest->z - actor->z); + + if (dist < 1) + dist = 1; + + speedmul = FixedMul(locvar1, actor->scale); + + actor->momx = FixedMul(FixedDiv(dest->x - actor->x, dist), speedmul); + actor->momy = FixedMul(FixedDiv(dest->y - actor->y, dist), speedmul); + actor->momz = FixedMul(FixedDiv(dest->z - actor->z, dist), speedmul); +} + +// Function: A_TrapShot +// +// Description: Fires a missile in a particular direction and angle rather than AT something, Trapgoyle-style! +// +// var1: +// lower 16 bits = object # to fire +// upper 16 bits = front offset +// var2: +// lower 15 bits = vertical angle variable +// 16th bit: +// - 0: use vertical angle variable as vertical angle in degrees +// - 1: mimic P_SpawnXYZMissile +// use z of actor minus z of missile as vertical distance to cover during momz calculation +// use vertical angle variable as horizontal distance to cover during momz calculation +// upper 16 bits = height offset +// +void A_TrapShot(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + boolean oldstyle = (locvar2 & 32768) ? true : false; + mobjtype_t type = (mobjtype_t)(locvar1 & 65535); + mobj_t *missile; + INT16 frontoff = (INT16)(locvar1 >> 16); + INT16 vertoff = (INT16)(locvar2 >> 16); + fixed_t x, y, z; + fixed_t speed; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_TrapShot", actor)) + return; +#endif + + x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); + + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(vertoff*FRACUNIT, actor->scale) - FixedMul(mobjinfo[type].height, actor->scale); + else + z = actor->z + FixedMul(vertoff*FRACUNIT, actor->scale); + + CONS_Debug(DBG_GAMELOGIC, "A_TrapShot: missile no. = %d, front offset = %d, vertical angle = %d, z offset = %d\n", + type, frontoff, (INT16)(locvar2 & 65535), vertoff); + + missile = P_SpawnMobj(x, y, z, type); + + if (actor->eflags & MFE_VERTICALFLIP) + missile->flags2 |= MF2_OBJECTFLIP; + + missile->destscale = actor->scale; + P_SetScale(missile, actor->scale); + + if (missile->info->seesound) + S_StartSound(missile, missile->info->seesound); + + P_SetTarget(&missile->target, actor); + missile->angle = actor->angle; + + speed = FixedMul(missile->info->speed, missile->scale); + + if (oldstyle) + { + missile->momx = FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed); + missile->momy = FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed); + // The below line basically mimics P_SpawnXYZMissile's momz calculation. + missile->momz = (actor->z + ((actor->eflags & MFE_VERTICALFLIP) ? actor->height : 0) - z) / ((fixed_t)(locvar2 & 32767)*FRACUNIT / speed); + P_CheckMissileSpawn(missile); + } + else + { + angle_t vertang = FixedAngle(((INT16)(locvar2 & 32767))*FRACUNIT); + if (actor->eflags & MFE_VERTICALFLIP) + vertang = InvAngle(vertang); // flip firing angle + missile->momx = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(missile->angle>>ANGLETOFINESHIFT), speed)); + missile->momy = FixedMul(FINECOSINE(vertang>>ANGLETOFINESHIFT), FixedMul(FINESINE(missile->angle>>ANGLETOFINESHIFT), speed)); + missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed); + } +} + +// Function: A_VileTarget +// +// Description: Spawns an object directly on the target, and sets this object as the actor's tracer. +// Originally used by Archviles to summon a pillar of hellfire, hence the name. +// +// var1 = mobj to spawn +// var2 = If 0, target only the actor's target. Else, target every player, period. +// +void A_VileTarget(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *fog; + mobjtype_t fogtype; + INT32 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VileTarget", actor)) + return; +#endif + + if (!actor->target) + return; + + A_FaceTarget(actor); + + // Determine object to spawn + if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES) + fogtype = MT_CYBRAKDEMON_TARGET_RETICULE; + else + fogtype = (mobjtype_t)locvar1; + + if (!locvar2) + { + fog = P_SpawnMobj(actor->target->x, + actor->target->y, + actor->target->z + ((actor->target->eflags & MFE_VERTICALFLIP) ? actor->target->height - mobjinfo[fogtype].height : 0), + fogtype); + if (actor->target->eflags & MFE_VERTICALFLIP) + { + fog->eflags |= MFE_VERTICALFLIP; + fog->flags2 |= MF2_OBJECTFLIP; + } + fog->destscale = actor->target->scale; + P_SetScale(fog, fog->destscale); + + P_SetTarget(&actor->tracer, fog); + P_SetTarget(&fog->target, actor); + P_SetTarget(&fog->tracer, actor->target); + A_VileFire(fog); + } + else + { + // Our "Archvile" here is actually Oprah. "YOU GET A TARGET! YOU GET A TARGET! YOU ALL GET A TARGET!" + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + if (!players[i].mo->health) + continue; + + fog = P_SpawnMobj(players[i].mo->x, + players[i].mo->y, + players[i].mo->z + ((players[i].mo->eflags & MFE_VERTICALFLIP) ? players[i].mo->height - mobjinfo[fogtype].height : 0), + fogtype); + if (players[i].mo->eflags & MFE_VERTICALFLIP) + { + fog->eflags |= MFE_VERTICALFLIP; + fog->flags2 |= MF2_OBJECTFLIP; + } + fog->destscale = players[i].mo->scale; + P_SetScale(fog, fog->destscale); + + if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now + P_SetTarget(&actor->tracer, fog); + P_SetTarget(&fog->target, actor); + P_SetTarget(&fog->tracer, players[i].mo); + A_VileFire(fog); + } + } +} + +// Function: A_VileAttack +// +// Description: Instantly hurts the actor's target, if it's in the actor's line of sight. +// Originally used by Archviles to cause explosions where their hellfire pillars were, hence the name. +// +// var1 = sound to play +// var2: +// Lower 16 bits = optional explosion object +// Upper 16 bits = If 0, attack only the actor's target. Else, attack all the players. All of them. +// +void A_VileAttack(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + sfxenum_t soundtoplay; + mobjtype_t explosionType = MT_NULL; + mobj_t *fire; + INT32 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VileAttack", actor)) + return; +#endif + + if (!actor->target) + return; + + A_FaceTarget(actor); + + if (locvar1 <= 0 || locvar1 >= NUMSFX) + soundtoplay = sfx_brakrx; + else + soundtoplay = (sfxenum_t)locvar1; + + if ((locvar2 & 0xFFFF) > 0 && (locvar2 & 0xFFFF) <= NUMMOBJTYPES) + { + explosionType = (mobjtype_t)(locvar2 & 0xFFFF); + } + + if (!(locvar2 & 0xFFFF0000)) { + if (!P_CheckSight(actor, actor->target)) + return; + + S_StartSound(actor, soundtoplay); + P_DamageMobj(actor->target, actor, actor, 1, 0); + //actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it + actor->target->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(actor->target); // How we're doing it + if (explosionType != MT_NULL) + { + P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, explosionType); + } + + // Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway. + fire = actor->tracer; + + if (!fire) + return; + + // move the fire between the vile and the player + //fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); + //fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); + P_TeleportMove(fire, + actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), + actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), + fire->z); + P_RadiusAttack(fire, actor, 70*FRACUNIT, 0); + } + else + { + // Oprahvile strikes again, but this time, she brings HOT PAIN + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo) + continue; + + if (!players[i].mo->health) + continue; + + if (!P_CheckSight(actor, players[i].mo)) + continue; + + S_StartSound(actor, soundtoplay); + P_DamageMobj(players[i].mo, actor, actor, 1, 0); + //actor->target->momz = 1000*FRACUNIT/actor->target->info->mass; // How id did it + players[i].mo->momz += FixedMul(10*FRACUNIT, actor->scale)*P_MobjFlip(players[i].mo); // How we're doing it + if (explosionType != MT_NULL) + { + P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z, explosionType); + } + + // Extra attack. This was for additional damage in Doom. Doesn't really belong in SRB2, but the heck with it, it's here anyway. + // However, it ONLY applies to the actor's target. Nobody else matters! + if (actor->target != players[i].mo) + continue; + + fire = actor->tracer; + + if (!fire) + continue; + + // move the fire between the vile and the player + //fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); + //fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); + P_TeleportMove(fire, + actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), + actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), + fire->z); + P_RadiusAttack(fire, actor, 70*FRACUNIT, 0); + } + } + +} + +// Function: A_VileFire +// +// Description: Kind of like A_CapeChase; keeps this object in front of its tracer, unless its target can't see it. +// Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific). +// Added some functionality to optionally draw a line directly to the enemy doing the targetting. Y'know, to hammer things in a bit. +// +// var1 = sound to play +// var2: +// Lower 16 bits = mobj to spawn (0 doesn't spawn a line at all) +// Upper 16 bits = # to spawn (default is 8) +// +void A_VileFire(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *dest; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VileFire", actor)) + return; +#endif + + dest = actor->tracer; + if (!dest) + return; + + // don't move it if the vile lost sight + if (!P_CheckSight(actor->target, dest)) + return; + + // keep to same scale and gravity as tracer ALWAYS + actor->destscale = dest->scale; + P_SetScale(actor, actor->destscale); + if (dest->eflags & MFE_VERTICALFLIP) + { + actor->eflags |= MFE_VERTICALFLIP; + actor->flags2 |= MF2_OBJECTFLIP; + } + else + { + actor->eflags &= ~MFE_VERTICALFLIP; + actor->flags2 &= ~MF2_OBJECTFLIP; + } + + P_UnsetThingPosition(actor); + actor->x = dest->x + P_ReturnThrustX(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale)); + actor->y = dest->y + P_ReturnThrustY(actor, dest->angle, FixedMul(24*FRACUNIT, actor->scale)); + actor->z = dest->z + ((actor->eflags & MFE_VERTICALFLIP) ? dest->height-actor->height : 0); + P_SetThingPosition(actor); + + // Play sound, if one's specified + if (locvar1 > 0 && locvar1 < NUMSFX) + S_StartSound(actor, (sfxenum_t)locvar1); + + // Now draw the line to the actor's target + if (locvar2 & 0xFFFF) + { + mobjtype_t lineMobj; + UINT16 numLineMobjs; + fixed_t distX; + fixed_t distY; + fixed_t distZ; + UINT16 i; + + lineMobj = (mobjtype_t)(locvar2 & 0xFFFF); + numLineMobjs = (UINT16)(locvar2 >> 16); + if (numLineMobjs == 0) { + numLineMobjs = 8; + } + + // Get distance for each step + distX = (actor->target->x - actor->x) / numLineMobjs; + distY = (actor->target->y - actor->y) / numLineMobjs; + distZ = ((actor->target->z + FixedMul(actor->target->height/2, actor->target->scale)) - (actor->z + FixedMul(actor->height/2, actor->scale))) / numLineMobjs; + + for (i = 1; i <= numLineMobjs; i++) + { + P_SpawnMobj(actor->x + (distX * i), actor->y + (distY * i), actor->z + (distZ * i) + FixedMul(actor->height/2, actor->scale), lineMobj); + } + } +} + +// Function: A_BrakChase +// +// Description: Chase after your target, but speed and attack are tied to health. +// +// Every time this is called, generate a random number from a 1/4 to 3/4 of mobj's spawn health. +// If health is above that value, use missilestate to attack. +// If health is at or below that value, use meleestate to attack (default to missile state if not available). +// +// Likewise, state will linearly speed up as health goes down. +// Upper bound will be the frame's normal length. +// Lower bound defaults to 1 tic (technically 0, but we round up), unless a lower bound is specified in var1. +// +// var1 = lower-bound of frame length, in tics +// var2 = optional sound to play +// +void A_BrakChase(mobj_t *actor) +{ + INT32 delta; + INT32 lowerbound; + INT32 newtics; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BrakChase", actor)) + return; +#endif + + // Set new tics NOW, in case the state changes while we're doing this and we try applying this to the painstate or something silly + if (actor->tics > 1 && locvar1 < actor->tics) // Not much point, otherwise + { + if (locvar1 < 0) + lowerbound = 0; + else + lowerbound = locvar1; + + newtics = (((actor->tics - lowerbound) * actor->health) / actor->info->spawnhealth) + lowerbound; + if (newtics < 1) + newtics = 1; + + actor->tics = newtics; + } + + if (actor->reactiontime) + { + actor->reactiontime--; + if (actor->reactiontime == 0 && actor->type == MT_CYBRAKDEMON) + S_StartSound(0, sfx_bewar1 + P_RandomKey(4)); + } + + // modify target threshold + if (actor->threshold) + { + if (!actor->target || actor->target->health <= 0) + actor->threshold = 0; + else + actor->threshold--; + } + + // turn towards movement direction if not there yet + if (actor->movedir < NUMDIRS) + { + actor->angle &= (7<<29); + delta = actor->angle - (actor->movedir << 29); + + if (delta > 0) + actor->angle -= ANGLE_45; + else if (delta < 0) + actor->angle += ANGLE_45; + } + + if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) + { + // look for a new target + if (P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + P_SetMobjStateNF(actor, actor->info->spawnstate); + return; + } + + // do not attack twice in a row + if (actor->flags2 & MF2_JUSTATTACKED) + { + actor->flags2 &= ~MF2_JUSTATTACKED; + P_NewChaseDir(actor); + return; + } + + // Check if we can attack + if (P_CheckMissileRange(actor) && !actor->movecount) + { + // Check if we should use "melee" attack first. (Yes, this still runs outside of melee range. Quiet, you.) + if (actor->info->meleestate + && actor->health <= P_RandomRange(actor->info->spawnhealth/4, (actor->info->spawnhealth * 3)/4)) // Guaranteed true if <= 1/4 health, guaranteed false if > 3/4 health + { + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + + P_SetMobjState(actor, actor->info->meleestate); + actor->flags2 |= MF2_JUSTATTACKED; + return; + } + // Else, check for missile attack. + else if (actor->info->missilestate) + { + P_SetMobjState(actor, actor->info->missilestate); + actor->flags2 |= MF2_JUSTATTACKED; + return; + } + } + + // possibly choose another target + if (multiplayer && !actor->threshold && (actor->target->health <= 0 || !P_CheckSight(actor, actor->target)) + && P_LookForPlayers(actor, true, false, 0)) + return; // got a new target + + // chase towards player + if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed)) + P_NewChaseDir(actor); + + // Optionally play a sound effect + if (locvar2 > 0 && locvar2 < NUMSFX) + S_StartSound(actor, (sfxenum_t)locvar2); + + // make active sound + if (actor->type != MT_CYBRAKDEMON && actor->info->activesound && P_RandomChance(3*FRACUNIT/256)) + { + S_StartSound(actor, actor->info->activesound); + } +} + +// Function: A_BrakFireShot +// +// Description: Shoot an object at your target, offset to match where Brak's gun is. +// Also, sets Brak's reaction time; behaves normally otherwise. +// +// var1 = object # to shoot +// var2 = unused +// +void A_BrakFireShot(mobj_t *actor) +{ + fixed_t x, y, z; + INT32 locvar1 = var1; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BrakFireShot", actor)) + return; +#endif + if (!actor->target) + return; + + A_FaceTarget(actor); + + x = actor->x + + P_ReturnThrustX(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale)) + + P_ReturnThrustX(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale)); + y = actor->y + + P_ReturnThrustY(actor, actor->angle, FixedMul(64*FRACUNIT, actor->scale)) + + P_ReturnThrustY(actor, actor->angle+ANGLE_270, FixedMul(32*FRACUNIT, actor->scale)); + if (actor->eflags & MFE_VERTICALFLIP) + z = actor->z + actor->height - FixedMul(144*FRACUNIT, actor->scale); + else + z = actor->z + FixedMul(144*FRACUNIT, actor->scale); + + P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z); + + if (!(actor->flags & MF_BOSS)) + { + if (ultimatemode) + actor->reactiontime = actor->info->reactiontime*TICRATE; + else + actor->reactiontime = actor->info->reactiontime*TICRATE*2; + } +} + +// Function: A_BrakLobShot +// +// Description: Lobs an object at the floor about a third of the way toward your target. +// Implication is it'll bounce the rest of the way. +// (You can also just aim straight at the target, but whatever) +// Formula grabbed from http://en.wikipedia.org/wiki/Trajectory_of_a_projectile#Angle_required_to_hit_coordinate_.28x.2Cy.29 +// +// var1 = object # to lob +// var2: +// Lower 16 bits: height offset to shoot from, from the actor's bottom (none that "airtime" malarky) +// Upper 16 bits: if 0, aim 1/3 of the way. Else, aim directly at target. +// + +void A_BrakLobShot(mobj_t *actor) +{ + fixed_t v; // Velocity to shoot object + fixed_t a1, a2, aToUse; // Velocity squared + fixed_t g; // Gravity + fixed_t x; // Horizontal difference + INT32 x_int; // x! But in integer form! + fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up) + INT32 y_int; // y! But in integer form! + INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper. + fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number. + angle_t theta; // Angle of attack + mobjtype_t typeOfShot; + mobj_t *shot; // Object to shoot + fixed_t newTargetX; // If not aiming directly + fixed_t newTargetY; // If not aiming directly + INT32 locvar1 = var1; + INT32 locvar2 = var2 & 0x0000FFFF; + INT32 aimDirect = var2 & 0xFFFF0000; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_BrakLobShot", actor)) + return; +#endif + + if (!actor->target) + return; // Don't even bother if we've got nothing to aim at. + + // Look up actor's current gravity situation + if (actor->subsector->sector->gravity) + g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); + else + g = gravity; + + // Look up distance between actor and its target + x = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); + if (!aimDirect) + { + // Distance should actually be a third of the way over + x = FixedDiv(x, 3<x + P_ReturnThrustX(actor, actor->angle, x); + newTargetY = actor->y + P_ReturnThrustY(actor, actor->angle, x); + x = P_AproxDistance(newTargetX - actor->x, newTargetY - actor->y); + // Look up height difference between actor and the ground 1/3 of the way to its target + y = P_FloorzAtPos(newTargetX, newTargetY, actor->target->z, actor->target->height) - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale)); + } + else + { + // Look up height difference between actor and its target + y = actor->target->z - (actor->z + FixedMul(locvar2*FRACUNIT, actor->scale)); + } + + // Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise. + x_int = x>>FRACBITS; + y_int = y>>FRACBITS; + intHypotenuse = (x_int*x_int) + (y_int*y_int); + fixedHypotenuse = FixedSqrt(intHypotenuse) *256; + + // a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -. + a1 = FixedMul(g,y+fixedHypotenuse); + a2 = FixedMul(g,y-fixedHypotenuse); + + // Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v. + if (a1 < 0 || a2 < 0) + { + if (a1 < 0 && a2 < 0) + { + //Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort! + return; + } + // Just find which one's NOT negative, and use that + aToUse = max(a1,a2); + } + else + { + // Both are positive; use whichever's smaller so it can decay faster + aToUse = min(a1,a2); + } + v = FixedSqrt(aToUse); + // Okay, so we know the velocity. Let's actually find theta. + // We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So: + //theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS]; + theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))]; + + // Okay, complicated math done. Let's fire our object already, sheesh. + A_FaceTarget(actor); + if (locvar1 <= 0 || locvar1 >= NUMMOBJTYPES) + typeOfShot = MT_CANNONBALL; + else typeOfShot = (mobjtype_t)locvar1; + shot = P_SpawnMobj(actor->x, actor->y, actor->z + FixedMul(locvar2*FRACUNIT, actor->scale), typeOfShot); + if (shot->info->seesound) + S_StartSound(shot, shot->info->seesound); + P_SetTarget(&shot->target, actor); // where it came from + + shot->angle = actor->angle; + + // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. + shot->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(shot->angle >> ANGLETOFINESHIFT)); + shot->momy = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINESINE(shot->angle >> ANGLETOFINESHIFT)); + // Then the vertical axis. No angle-correction needed here. + shot->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT)); + // I hope that's all that's needed, ugh +} + +// Function: A_NapalmScatter +// +// Description: Scatters a specific number of projectiles around in a circle. +// Intended for use with objects that are affected by gravity; would be kind of silly otherwise. +// +// var1: +// Lower 16 bits: object # to lob (TODO: come up with a default) +// Upper 16 bits: Number to lob (default 8) +// var2: +// Lower 16 bits: distance to toss them (No default - 0 does just that - but negatives will revert to 128) +// Upper 16 bits: airtime in tics (default 16) +// +void A_NapalmScatter(mobj_t *actor) +{ + mobjtype_t typeOfShot = var1 & 0x0000FFFF; // Type + INT32 numToShoot = (var1 & 0xFFFF0000) >> 16; // How many + fixed_t distance = (var2 & 0x0000FFFF) << FRACBITS; // How far + fixed_t airtime = var2 & 0xFFFF0000; // How long until impact (assuming no obstacles) + fixed_t vx; // Horizontal momentum + fixed_t vy; // Vertical momentum + fixed_t g; // Gravity + INT32 i; // for-loop cursor + mobj_t *mo; // each and every spawned napalm burst + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_NapalmScatter", actor)) + return; +#endif + + // Some quick sanity-checking + if (typeOfShot >= NUMMOBJTYPES) // I'd add a <0 check, too, but 0x0000FFFF isn't negative in this case + typeOfShot = MT_NULL; + if (numToShoot <= 0) // Presumably you forgot to set var1 up; else, why are you calling this to shoot nothing? + numToShoot = 8; + else if (numToShoot > 8192) // If you seriously need this many objects spawned, stop and ask yourself "Why am I doing this?" + numToShoot = 8192; + if (distance < 0) // Presumably you thought this was an unsigned integer, you naive fool + distance = 32767<subsector->sector->gravity) + g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); + else + g = gravity; + + // vy = (g*(airtime-1))/2 + vy = FixedMul(g,(airtime-(1<>1; + // vx = distance/airtime + vx = FixedDiv(distance, airtime); + + for (i = 0; ix, actor->y, actor->z, typeOfShot); + P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot + + mo->angle = fa << ANGLETOFINESHIFT; + mo->momx = FixedMul(FINECOSINE(fa),vx); + mo->momy = FixedMul(FINESINE(fa),vx); + mo->momz = vy; + } +} + +// Function: A_SpawnFreshCopy +// +// Description: Spawns a copy of the mobj. x, y, z, angle, scale, target and tracer carry over; everything else starts anew. +// Mostly writing this because I want to do multiple actions to pass these along in a single frame instead of several. +// +// var1 = unused +// var2 = unused +// +void A_SpawnFreshCopy(mobj_t *actor) +{ + mobj_t *newObject; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnFreshCopy", actor)) + return; +#endif + + newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); + newObject->flags2 = actor->flags2 & MF2_AMBUSH; + newObject->angle = actor->angle; + newObject->color = actor->color; + P_SetTarget(&newObject->target, actor->target); + P_SetTarget(&newObject->tracer, actor->tracer); + + if (newObject->info->seesound) + S_StartSound(newObject, newObject->info->seesound); +} + +// Internal Flicky spawning function. +mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers) +{ + mobj_t *flicky; + + if (!flickytype) + { + if (!mapheaderinfo[gamemap-1] || !mapheaderinfo[gamemap-1]->numFlickies) // No mapheader, no shoes, no service. + return NULL; + else + { + INT32 prandom = P_RandomKey(mapheaderinfo[gamemap-1]->numFlickies); + flickytype = mapheaderinfo[gamemap-1]->flickies[prandom]; + } + } + + flicky = P_SpawnMobjFromMobj(actor, 0, 0, 0, flickytype); + flicky->angle = actor->angle; + + if (flickytype == MT_SEED) + flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2; + + if (actor->eflags & MFE_UNDERWATER) + momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT)); + + P_SetObjectMomZ(flicky, momz, false); + flicky->movedir = (P_RandomChance(FRACUNIT/2) ? -1 : 1); + flicky->fuse = P_RandomRange(595, 700); // originally 300, 350 + flicky->threshold = 0; + + if (lookforplayers) + P_LookForPlayers(flicky, true, false, 0); + + return flicky; +} + +// Function: A_FlickySpawn +// +// Description: Flicky spawning function. +// +// var1: +// lower 16 bits: if 0, spawns random flicky based on level header. Else, spawns the designated thing type. +// upper 16 bits: if 0, no sound is played. Else, A_Scream is called. +// var2 = upwards thrust for spawned flicky. If zero, default value is provided. +// +void A_FlickySpawn(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickySpawn", actor)) + return; +#endif + + if (locvar1 >> 16) { + A_Scream(actor); // A shortcut for the truly lazy. + locvar1 &= 65535; + } + + P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true); +} + +// Internal Flicky bubbling function. +void P_InternalFlickyBubble(mobj_t *actor) +{ + if (actor->eflags & MFE_UNDERWATER) + { + mobj_t *overlay; + + if (!((actor->z + 3*actor->height/2) < actor->watertop) || !mobjinfo[actor->type].raisestate || actor->tracer) + return; + + overlay = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY); + P_SetMobjStateNF(overlay, mobjinfo[actor->type].raisestate); + P_SetTarget(&actor->tracer, overlay); + P_SetTarget(&overlay->target, actor); + return; + } + + if (!actor->tracer || P_MobjWasRemoved(actor->tracer)) + return; + + P_RemoveMobj(actor->tracer); + P_SetTarget(&actor->tracer, NULL); +} + +// Function: A_FlickyAim +// +// Description: Flicky aiming function. +// +// var1 = how far around the target (in angle constants) the flicky should look +// var2 = distance from target to aim for +// +void A_FlickyAim(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + boolean flickyhitwall = false; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyAim", actor)) + return; +#endif + + if (actor->momx == actor->momy && actor->momy == 0) + flickyhitwall = true; + + P_InternalFlickyBubble(actor); + P_InstaThrust(actor, 0, 0); + + if (!actor->target) + { + P_LookForPlayers(actor, true, false, 0); + actor->angle = P_RandomKey(36)*ANG10; + return; + } + + if (actor->fuse > 2*TICRATE) + { + angle_t posvar; + fixed_t chasevar, chasex, chasey; + + if (flickyhitwall) + actor->movedir *= -1; + + posvar = ((R_PointToAngle2(actor->target->x, actor->target->y, actor->x, actor->y) + actor->movedir*locvar1) >> ANGLETOFINESHIFT) & FINEMASK; + chasevar = FixedSqrt(max(FRACUNIT, P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y) - locvar2)) + locvar2; + + chasex = actor->target->x + FixedMul(FINECOSINE(posvar), chasevar); + chasey = actor->target->y + FixedMul(FINESINE(posvar), chasevar); + + if (P_AproxDistance(chasex - actor->x, chasey - actor->y)) + actor->angle = R_PointToAngle2(actor->x, actor->y, chasex, chasey); + } + else if (flickyhitwall) + { + actor->angle += ANGLE_180; + actor->threshold = 0; + } +} + +//Internal Flicky flying function. Also usuable as an underwater swim thrust. +void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez) +{ + angle_t vertangle; + + flyspeed = FixedMul(flyspeed, actor->scale); + actor->flags |= MF_NOGRAVITY; + + var1 = ANG30; + var2 = 32*FRACUNIT; + A_FlickyAim(actor); + + chasez *= 8; + if (!actor->target || !(actor->fuse > 2*TICRATE)) + chasez += ((actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz - 24*FRACUNIT : actor->floorz + 24*FRACUNIT); + else + { + fixed_t add = actor->target->z + (actor->target->height - actor->height)/2; + if (add > (actor->ceilingz - 24*actor->scale - actor->height)) + add = actor->ceilingz - 24*actor->scale - actor->height; + else if (add < (actor->floorz + 24*actor->scale)) + add = actor->floorz + 24*actor->scale; + chasez += add; + } + + if (!targetdist) + targetdist = 16*FRACUNIT; //Default! + + if (actor->target && abs(chasez - actor->z) > targetdist) + targetdist = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); + + vertangle = (R_PointToAngle2(0, actor->z, targetdist, chasez) >> ANGLETOFINESHIFT) & FINEMASK; + P_InstaThrust(actor, actor->angle, FixedMul(FINECOSINE(vertangle), flyspeed)); + actor->momz = FixedMul(FINESINE(vertangle), flyspeed); +} + +// Function: A_FlickyFly +// +// Description: Flicky flying function. +// +// var1 = how fast to fly +// var2 = how far ahead the target should be considered +// +void A_FlickyFly(mobj_t *actor) +{ + // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead. + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyFly", actor)) + return; +#endif + P_InternalFlickyFly(actor, var1, var2, + FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK) + ); +} + +// Function: A_FlickySoar +// +// Description: Flicky soaring function - specific to puffin. +// +// var1 = how fast to fly +// var2 = how far ahead the target should be considered +// +void A_FlickySoar(mobj_t *actor) +{ + // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead. + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickySoar", actor)) + return; +#endif + P_InternalFlickyFly(actor, var1, var2, + 2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK))) + ); + + if (P_MobjFlip(actor)*actor->momz > 0 && actor->frame == 1 && actor->sprite == SPR_FL10) + actor->frame = 3; +} + +//Function: A_FlickyCoast +// +// Description: Flicky swim-coasting function. +// +// var1 = speed to change state upon reaching +// var2 = state to change to upon slowing down +// the spawnstate of the mobj = state to change to when above water +// +void A_FlickyCoast(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyCoast", actor)) + return; +#endif + if (actor->eflags & MFE_UNDERWATER) + { + actor->momx = (11*actor->momx)/12; + actor->momy = (11*actor->momy)/12; + actor->momz = (11*actor->momz)/12; + + if (P_AproxDistance(P_AproxDistance(actor->momx, actor->momy), actor->momz) < locvar1) + P_SetMobjState(actor, locvar2); + + return; + } + + actor->flags &= ~MF_NOGRAVITY; + P_SetMobjState(actor, mobjinfo[actor->type].spawnstate); +} + +// Internal Flicky hopping function. +void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angle) +{ + if (((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) + || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz))) + { + if (momz) + { + if (actor->eflags & MFE_UNDERWATER) + momz = FixedDiv(momz, FixedSqrt(3*FRACUNIT)); + P_SetObjectMomZ(actor, momz, false); + } + P_InstaThrust(actor, angle, FixedMul(momh, actor->scale)); + } +} + +// Function: A_FlickyHop +// +// Description: Flicky hopping function. +// +// var1 = vertical thrust +// var2 = horizontal thrust +// +void A_FlickyHop(mobj_t *actor) +{ + // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyHop instead. + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyHop", actor)) + return; +#endif + P_InternalFlickyHop(actor, var1, var2, actor->angle); +} + +// Function: A_FlickyFlounder +// +// Description: Flicky floundering function. +// +// var1 = intended vertical thrust +// var2 = intended horizontal thrust +// +void A_FlickyFlounder(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + angle_t hopangle; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyFlounder", actor)) + return; +#endif + locvar1 *= (P_RandomKey(2) + 1); + locvar2 *= (P_RandomKey(2) + 1); + hopangle = (actor->angle + (P_RandomKey(9) - 4)*ANG2); + P_InternalFlickyHop(actor, locvar1, locvar2, hopangle); +} + +// Function: A_FlickyCheck +// +// Description: Flicky airtime check function. +// +// var1 = state to change to upon touching the floor +// var2 = state to change to upon falling +// the meleestate of the mobj = state to change to when underwater +// +void A_FlickyCheck(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyCheck", actor)) + return; +#endif + if (locvar2 && P_MobjFlip(actor)*actor->momz < 1) + P_SetMobjState(actor, locvar2); + else if (locvar1 && ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) + || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz))) + P_SetMobjState(actor, locvar1); + else if (mobjinfo[actor->type].meleestate && (actor->eflags & MFE_UNDERWATER)) + P_SetMobjState(actor, mobjinfo[actor->type].meleestate); + P_InternalFlickyBubble(actor); +} + +// Function: A_FlickyHeightCheck +// +// Description: Flicky height check function. +// +// var1 = state to change to when falling below height relative to target +// var2 = height relative to target to change state at +// +void A_FlickyHeightCheck(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyHeightCheck", actor)) + return; +#endif + if (locvar1 && actor->target && P_MobjFlip(actor)*actor->momz < 1 + && ((P_MobjFlip(actor)*((actor->z + actor->height/2) - (actor->target->z + actor->target->height/2)) < locvar2) + || (actor->z - actor->height < actor->floorz) || (actor->z + 2*actor->height > actor->ceilingz))) + P_SetMobjState(actor, locvar1); + P_InternalFlickyBubble(actor); +} + +// Function: A_FlickyFlutter +// +// Description: Flicky fluttering function - specific to chicken. +// +// var1 = state to change to upon touching the floor +// var2 = state to change to upon falling +// the meleestate of the mobj = state to change to when underwater +// +void A_FlickyFlutter(mobj_t *actor) +{ + // We're not setting up locvars here - it passes var1 and var2 through to A_FlickyCheck instead. + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlickyFlutter", actor)) + return; +#endif + A_FlickyCheck(actor); + + var1 = ANG30; + var2 = 32*FRACUNIT; + A_FlickyAim(actor); + + P_InstaThrust(actor, actor->angle, 2*actor->scale); + if (P_MobjFlip(actor)*actor->momz < -FRACUNIT/2) + actor->momz = -P_MobjFlip(actor)*actor->scale/2; +} + +#undef FLICKYHITWALL + +// Function: A_FlameParticle +// +// Description: Creates the mobj's painchance at a random position around the object's radius. +// +// var1 = unused +// var2 = unused +// +void A_FlameParticle(mobj_t *actor) +{ + mobjtype_t type = (mobjtype_t)(mobjinfo[actor->type].painchance); + fixed_t rad, hei; + mobj_t *particle; + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlameParticle", actor)) + return; +#endif + + if (!type) + return; + + rad = actor->radius>>FRACBITS; + hei = actor->height>>FRACBITS; + particle = P_SpawnMobjFromMobj(actor, + P_RandomRange(rad, -rad)<momx = actor->momy = actor->momz = 0; + + fade = P_SpawnGhostMobj(actor); + fade->frame = actor->frame; + + if (!(locvar1 & 2)) + { + fade->fuse = 15; + fade->flags2 |= MF2_BOSSNOTRAP; + } + else + fade->fuse = 20; + + if (!(locvar1 & 4)) + P_SetTarget(&actor->tracer, fade); +} + +// Function: A_Boss5Jump +// +// Description: Makes an object jump in an arc to land on their tracer precicely. +// Adapted from A_BrakLobShot, see there for explanation. +// +// var1 = unused +// var2 = unused +// +void A_Boss5Jump(mobj_t *actor) +{ + fixed_t v; // Velocity to jump at + fixed_t a1, a2, aToUse; // Velocity squared + fixed_t g; // Gravity + fixed_t x; // Horizontal difference + INT32 x_int; // x! But in integer form! + fixed_t y; // Vertical difference (yes that's normally z in SRB2 shut up) + INT32 y_int; // y! But in integer form! + INT32 intHypotenuse; // x^2 + y^2. Frequently overflows fixed point, hence why we need integers proper. + fixed_t fixedHypotenuse; // However, we can work around that and still get a fixed-point number. + angle_t theta; // Angle of attack + // INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5Jump", actor)) + return; +#endif + + if (!actor->tracer) + return; // Don't even bother if we've got nothing to aim at. + + // Look up actor's current gravity situation + if (actor->subsector->sector->gravity) + g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); + else + g = gravity; + + // Look up distance between actor and its tracer + x = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); + // Look up height difference between actor and its tracer + y = actor->tracer->z - actor->z; + + // Get x^2 + y^2. Have to do it in a roundabout manner, because this overflows fixed_t way too easily otherwise. + x_int = x>>FRACBITS; + y_int = y>>FRACBITS; + intHypotenuse = (x_int*x_int) + (y_int*y_int); + fixedHypotenuse = FixedSqrt(intHypotenuse) *256; + + // a = g(y+/-sqrt(x^2+y^2)). a1 can be +, a2 can be -. + a1 = FixedMul(g,y+fixedHypotenuse); + a2 = FixedMul(g,y-fixedHypotenuse); + + // Determine which one isn't actually an imaginary number (or the smaller of the two, if both are real), and use that for v. + if (a1 < 0 || a2 < 0) + { + if (a1 < 0 && a2 < 0) + { + //Somehow, v^2 is negative in both cases. v is therefore imaginary and something is horribly wrong. Abort! + return; + } + // Just find which one's NOT negative, and use that + aToUse = max(a1,a2); + } + else + { + // Both are positive; use whichever's smaller so it can decay faster + aToUse = min(a1,a2); + } + v = FixedSqrt(aToUse); + // Okay, so we know the velocity. Let's actually find theta. + // We can cut the "+/- sqrt" part out entirely, since v was calculated specifically for it to equal zero. So: + //theta = tantoangle[FixedDiv(aToUse,FixedMul(g,x)) >> DBITS]; + theta = tantoangle[SlopeDiv(aToUse,FixedMul(g,x))]; + + // Okay, complicated math done. Let's make this object jump already. + A_FaceTracer(actor); + + if (actor->eflags & MFE_VERTICALFLIP) + actor->z--; + else + actor->z++; + + // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. + fixedHypotenuse = FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)); // variable reuse + actor->momx = FixedMul(fixedHypotenuse, FINECOSINE(actor->angle >> ANGLETOFINESHIFT)); + actor->momy = FixedMul(fixedHypotenuse, FINESINE(actor->angle >> ANGLETOFINESHIFT)); + // Then the vertical axis. No angle-correction needed here. + actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT)); + // I hope that's all that's needed, ugh +} + +// Function: A_LightBeamReset +// Description: Resets momentum and position for DSZ's projecting light beams +// +// var1 = unused +// var2 = unused +// +void A_LightBeamReset(mobj_t *actor) +{ + // INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_LightBeamReset", actor)) + return; +#endif + + P_SetScale(actor, FRACUNIT + P_SignedRandom()*FRACUNIT/256); + actor->destscale = actor->scale; + + if (!actor->spawnpoint) + return; // this can't work properly welp + + actor->momx = P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; + actor->momy = P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; + actor->momz = P_SignedRandom()*FRACUNIT/128; + + P_UnsetThingPosition(actor); + actor->x = actor->spawnpoint->x*FRACUNIT + P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; + actor->y = actor->spawnpoint->y*FRACUNIT + P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; + actor->z = actor->spawnpoint->z*FRACUNIT + P_SignedRandom()*FRACUNIT/2; + P_SetThingPosition(actor); +} + +// Function: A_MineExplode +// Description: Handles the explosion of a DSZ mine. +// +// var1 = unused +// var2 = unused +// +void A_MineExplode(mobj_t *actor) +{ + // INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MineExplode", actor)) + return; +#endif + + A_Scream(actor); + actor->flags = MF_NOGRAVITY|MF_NOCLIP; + + quake.epicenter = NULL; + quake.radius = 512*FRACUNIT; + quake.intensity = 8*FRACUNIT; + quake.time = TICRATE/3; + + P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT, DMG_CANHURTSELF); + P_MobjCheckWater(actor); + + { +#define dist 64 + UINT8 i; + mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE); + S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e)); + P_SpawnMobj(actor->x, actor->y, actor->z, type); + for (i = 0; i < 16; i++) + { + mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT, + actor->y+P_RandomRange(-dist, dist)*FRACUNIT, + actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT, + type); + fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z; + fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx)); + b->momx = FixedDiv(dx, dm)*3; + b->momy = FixedDiv(dy, dm)*3; + b->momz = FixedDiv(dz, dm)*3; + if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop)) + b->flags &= ~MF_NOGRAVITY; + } +#undef dist + + if (actor->watertop != INT32_MAX) + P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH); + } +} + +// Function: A_MineRange +// Description: If the target gets too close, change the state to meleestate. +// +// var1 = Distance to alert at +// var2 = unused +// +void A_MineRange(mobj_t *actor) +{ + fixed_t dm; + INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MineRange", actor)) + return; +#endif + + if (!actor->target) + return; + + dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x)); + if ((dm>>FRACBITS) < locvar1) + P_SetMobjState(actor, actor->info->meleestate); +} + +// Function: A_ConnectToGround +// Description: Create a palm tree trunk/mine chain. +// +// var1 = Object type to connect to ground +// var2 = Object type to place on ground +// +void A_ConnectToGround(mobj_t *actor) +{ + mobj_t *work; + fixed_t workz; + fixed_t workh; + INT8 dir; + angle_t ang; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ConnectToGround", actor)) + return; +#endif + + P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); + + if (actor->flags2 & MF2_OBJECTFLIP) + { + workz = actor->ceilingz - (actor->z + actor->height); + dir = -1; + } + else + { + workz = actor->floorz - actor->z; + dir = 1; + } + + if (locvar2) + { + if (actor->flags2 & MF2_OBJECTFLIP) + workz -= FixedMul(mobjinfo[locvar2].height, actor->scale); + work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2); + } + + if (!locvar1) + return; + + workh = FixedMul(mobjinfo[locvar1].height, actor->scale); + + if (actor->flags2 & MF2_OBJECTFLIP) + workz -= workh; + + ang = actor->angle + ANGLE_45; + while (dir*workz < 0) + { + work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1); + if (work) + work->angle = ang; + ang += ANGLE_90; + workz += dir*workh; + } + + if (workz != 0) + actor->z += workz; +} + +// Function: A_SpawnParticleRelative +// +// Description: Spawns a particle effect relative to the location of the actor +// +// var1: +// var1 >> 16 = x +// var1 & 65535 = y +// var2: +// var2 >> 16 = z +// var2 & 65535 = state +// +void A_SpawnParticleRelative(mobj_t *actor) +{ + INT16 x, y, z; // Want to be sure we can use negative values + statenum_t state; + mobj_t *mo; + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SpawnParticleRelative", actor)) + return; +#endif + + CONS_Debug(DBG_GAMELOGIC, "A_SpawnParticleRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); + + x = (INT16)(locvar1>>16); + y = (INT16)(locvar1&65535); + z = (INT16)(locvar2>>16); + state = (statenum_t)(locvar2&65535); + + // Spawn objects correctly in reverse gravity. + // NOTE: Doing actor->z + actor->height is the bottom of the object while the object has reverse gravity. - Flame + mo = P_SpawnMobj(actor->x + FixedMul(x<scale), + actor->y + FixedMul(y<scale), + (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), MT_PARTICLE); + + // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn + mo->angle = actor->angle; + + if (actor->eflags & MFE_VERTICALFLIP) + mo->flags2 |= MF2_OBJECTFLIP; + + P_SetMobjState(mo, state); +} + +// Function: A_MultiShotDist +// +// Description: Spawns multiple shots based on player proximity +// +// var1 = same as A_MultiShot +// var2 = same as A_MultiShot +// +void A_MultiShotDist(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MultiShotDist", actor)) + return; +#endif + + { + UINT8 i; + // Quick! Look through players! + // Don't spawn dust unless a player is relatively close by (var1). + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].mo + && P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (1600<> 16 = mobjtype of child +// var2 & 65535 = vertical momentum +// var2: +// var2 >> 16 = forward offset +// var2 & 65535 = vertical offset +// +void A_WhoCaresIfYourSonIsABee(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t foffsetx; + fixed_t foffsety; + mobj_t *son; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_WhoCaresIfYourSonIsABee", actor)) + return; +#endif + + A_FaceTarget(actor); + + if (actor->extravalue1) + actor->extravalue1--; + + if (actor->info->attacksound) + S_StartSound(actor, actor->info->attacksound); + + foffsetx = P_ReturnThrustX(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + foffsety = P_ReturnThrustY(actor, actor->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + + if (!(son = P_SpawnMobjFromMobj(actor, foffsetx, foffsety, (locvar2&65535)*FRACUNIT, (mobjtype_t)(locvar1 >> 16)))) + return; + + P_SetObjectMomZ(son, (locvar1 & 65535)<tracer, actor); + P_SetTarget(&son->target, actor->target); +} + +// Function: A_ParentTriesToSleep +// +// Description: If extravalue1 is less than or equal to var1, go to var2. +// +// var1 = state to go to when extravalue1 +// var2 = unused +// +void A_ParentTriesToSleep(mobj_t *actor) +{ + INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ParentTriesToSleep", actor)) + return; +#endif + + if (actor->extravalue1) + { + if (actor->info->seesound) + S_StartSound(actor, actor->info->seesound); + actor->reactiontime = 0; + P_SetMobjState(actor, locvar1); + } + else if (!actor->reactiontime) + { + actor->reactiontime = 1; + if (actor->info->activesound) // more like INactivesound doy hoy hoy + S_StartSound(actor, actor->info->activesound); + } +} + + +// Function: A_CryingToMomma +// +// Description: If you're a child, let your parent know something's happened to you through extravalue1. Also, prepare to die. +// +// var1 = unused +// var2 = unused +// +void A_CryingToMomma(mobj_t *actor) +{ + //INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CryingToMomma", actor)) + return; +#endif + + if (actor->tracer) + actor->tracer->extravalue1++; + + actor->momx = actor->momy = actor->momz = 0; + + P_UnsetThingPosition(actor); + if (sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + actor->flags = MF_NOBLOCKMAP|MF_NOCLIPTHING; + P_SetThingPosition(actor); +} + +// Function: A_CheckFlags2 +// +// Description: If actor->flags2 & var1, goto var2. +// +// var1 = mask +// var2 = state to go +// +void A_CheckFlags2(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CheckFlags2", actor)) + return; +#endif + + if (actor->flags2 & locvar1) + P_SetMobjState(actor, (statenum_t)locvar2); +} \ No newline at end of file diff --git a/src/p_inter.c b/src/p_inter.c index cb55fa04e..5161f4cc3 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1461,10 +1461,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetMobjState(special, special->info->seestate); } return; - case MT_SMALLMACECHAIN: - case MT_BIGMACECHAIN: - // Is this the last link in the chain? - if (toucher->momz > 0 || !(special->flags2 & MF2_AMBUSH) + case MT_SMALLGRABCHAIN: + case MT_BIGGRABCHAIN: + if (P_MobjFlip(toucher)*toucher->momz > 0 || (player->powers[pw_carry])) return; diff --git a/src/p_mobj.c b/src/p_mobj.c index af61a8896..72e87cd33 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6324,7 +6324,7 @@ void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot) mobj->y += pos_sideways[1]; // Cut the height to align the link with the axis. - if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN) + if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN || mobj->type == MT_SMALLGRABCHAIN || mobj->type == MT_BIGGRABCHAIN) zstore -= P_MobjFlip(mobj)*mobj->height/4; else zstore -= P_MobjFlip(mobj)*mobj->height/2; @@ -9953,7 +9953,7 @@ void P_SpawnMapThing(mapthing_t *mthing) fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor; angle_t mspokeangle; mobjtype_t chainlink, macetype, firsttype, linktype; - boolean mdosound, mdocenter; + boolean mdosound, mdocenter, mchainlike; mobj_t *spawnee = NULL, *hprev = mobj; mobjflag_t mflagsapply; mobjflag2_t mflags2apply; @@ -10059,6 +10059,19 @@ ML_EFFECT4 : Don't clip inside the ground else chainlink = MT_NULL; break; + case MT_CHAINPOINT: + if (mthing->options & MTF_AMBUSH) + { + macetype = MT_BIGGRABCHAIN; + chainlink = MT_BIGMACECHAIN; + } + else + { + macetype = MT_SMALLGRABCHAIN; + chainlink = MT_SMALLMACECHAIN; + } + mchainlike = true; + break; default: if (mthing->options & MTF_AMBUSH) { @@ -10076,17 +10089,15 @@ ML_EFFECT4 : Don't clip inside the ground if (!macetype && !chainlink) break; - if (mobj->type != MT_CHAINPOINT) - { - firsttype = macetype; - mlength++; - } - else + if (mobj->type == MT_CHAINPOINT) { if (!mlength) break; - firsttype = chainlink; } + else + mlength++; + + firsttype = macetype; // Adjustable direction if (lines[line].flags & ML_NOCLIMB) @@ -10110,13 +10121,15 @@ ML_EFFECT4 : Don't clip inside the ground else radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); - widthfactor = ((firsttype == chainlink) ? 1 : 2); + if (!mchainlike) + mchainlike = (firsttype == chainlink); + widthfactor = (mchainlike ? 1 : 2); mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP|MF_NOCLIPHEIGHT)); mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0); meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0); - msound = ((firsttype == chainlink) ? 0 : (mwidth & 1)); + msound = (mchainlike ? 0 : (mwidth & 1)); // Quick and easy preparatory variable setting mphase = (FixedAngle(mphase*FRACUNIT)>>ANGLETOFINESHIFT); @@ -10155,7 +10168,8 @@ ML_EFFECT4 : Don't clip inside the ground if (mobj->type != MT_CHAINMACEPOINT) continue; - firsttype = linktype = chainlink; + linktype = chainlink; + firsttype = ((mthing->options & MTF_AMBUSH) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN); mmaxlength = 1 + (mlength - 1)*radiusfactor; radiusfactor = widthfactor = 1; } @@ -10170,10 +10184,7 @@ ML_EFFECT4 : Don't clip inside the ground radiusfactor = 2; } else - { - linktype = chainlink; radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); - } firsttype = macetype; widthfactor = 2; @@ -10185,8 +10196,8 @@ ML_EFFECT4 : Don't clip inside the ground mwidthset = mwidth; mlengthset = mminlength; - if (mdocenter) // Innermost mace/link - makemace(macetype, 0, 0); + if (mdocenter) // Innermost link + makemace(linktype, 0, 0); // Out from the center... if (linktype) @@ -10240,8 +10251,8 @@ ML_EFFECT4 : Don't clip inside the ground while (mlengthset > mminlength) makemace(linktype, radiusfactor*(mlengthset--), 0); - if (mdocenter) // Innermost mace/link - makemace(macetype, 0, 0); + if (mdocenter) // Innermost link + makemace(linktype, 0, 0); } } diff --git a/src/sounds.c b/src/sounds.c index 8f2b805a9..d3a0ac373 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -439,8 +439,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kc3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Levitation"}, // ditto {"s3kc4s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"}, {"s3kc4l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"}, // ditto - {"s3kc5s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s3kc5l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto + {"s3kc5s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Revving up"}, + {"s3kc5l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Revving up"}, // ditto {"s3kc6s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, {"s3kc6l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, // ditto {"s3kc7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, From 364984ac129e973d8f15b53760ddfd09a3b36412 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 24 May 2018 13:19:42 +0100 Subject: [PATCH 140/212] Fix bugs (uninitialised memory the compiler didn't pick up, and not setting scale) I sleepily caused last night. --- src/p_enemy.c | 12 +++++++----- src/p_mobj.c | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index b2f3ffadf..d2ef9ab9f 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1266,30 +1266,32 @@ void A_FaceStabHurl(mobj_t *actor) #define NUMSTEPS 3 #define NUMGRADS 5 #define MAXVAL (NUMSTEPS*NUMGRADS) - SINT8 step = ++actor->extravalue1; + SINT8 step = (++actor->extravalue1); fixed_t basesize = FRACUNIT/MAXVAL; mobj_t *hwork = actor; INT32 dist = 113; fixed_t xo = P_ReturnThrustX(actor, actor->angle, dist*basesize); fixed_t yo = P_ReturnThrustY(actor, actor->angle, dist*basesize); + while (step > 0) { if (!hwork->hnext) P_SetTarget(&hwork->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_FACESTABBERSPEAR)); hwork = hwork->hnext; hwork->angle = actor->angle + ANGLE_90; - hwork->destscale = FixedSqrt(basesize*step); + hwork->destscale = FixedSqrt(step*basesize); + P_SetScale(hwork, hwork->destscale); hwork->fuse = 2; P_TeleportMove(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<angle); - if (actor->extravalue1 >= MAXVAL) actor->extravalue1 -= NUMGRADS; + if ((step % 5) == 0) + P_SharpDust(actor, MT_SPINDUST, actor->angle); + P_FaceStabFlume(actor); return; #undef MAXVAL diff --git a/src/p_mobj.c b/src/p_mobj.c index 72e87cd33..6c46fe841 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9953,7 +9953,7 @@ void P_SpawnMapThing(mapthing_t *mthing) fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor; angle_t mspokeangle; mobjtype_t chainlink, macetype, firsttype, linktype; - boolean mdosound, mdocenter, mchainlike; + boolean mdosound, mdocenter, mchainlike = false; mobj_t *spawnee = NULL, *hprev = mobj; mobjflag_t mflagsapply; mobjflag2_t mflags2apply; From 0b6d6c3363d4b1aeece18a415caec54e7b0aca86 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Thu, 24 May 2018 16:24:09 -0400 Subject: [PATCH 141/212] GME low volume fix --- src/sdl/mixer_sound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 718324591..8938cb749 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -458,7 +458,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len) // apply volume to stream for (i = 0, p = (short *)stream; i < len/2; i++, p++) - *p = ((INT32)*p) * music_volume / 31; + *p = ((INT32)*p) * music_volume*2/31; } #endif From f4181f7eb6203af8d8363cd03a351d8b780061da Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 26 May 2018 13:13:37 +0100 Subject: [PATCH 142/212] Very large map rendering issue fixed Move old fix for too large maps having rendering issues from R_CheckBBox to OpenGL's HWR_CheckBBox From what I know, this effects at least Aerial Garden and Seraphic Skylands --- src/hardware/hw_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 81021ef7f..059a09b15 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2901,8 +2901,8 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord) py2 = bspcoord[checkcoord[boxpos][3]]; // check clip list for an open space - angle1 = R_PointToAngle(px1, py1) - dup_viewangle; - angle2 = R_PointToAngle(px2, py2) - dup_viewangle; + angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle; + angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle; span = angle1 - angle2; From 41e9c20c04bde872c794e2a8287baba627bedc25 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 28 May 2018 21:29:46 +0100 Subject: [PATCH 143/212] Ignore mouse button events if the mouse's focus is not actually on the window at the moment. This should hopefully kill the F12 getting stuck issue once and for all. --- src/sdl/i_video.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 87ce84158..4eab0ae3c 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -658,6 +658,14 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type) SDL_memset(&event, 0, sizeof(event_t)); + // Ignore the event if the mouse is not actually focused on the window. + // This can happen if you used the mouse to restore keyboard focus; + // this apparently makes a mouse button down event but not a mouse button up event, + // resulting in whatever key was pressed down getting "stuck" if we don't ignore it. + // -- Monster Iestyn (28/05/18) + if (SDL_GetMouseFocus() != window) + return; + /// \todo inputEvent.button.which if (USE_MOUSEINPUT) { From cea4562c74655b24508bcd04bf21df65baaefd2f Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 29 May 2018 18:48:57 +0100 Subject: [PATCH 144/212] Realised I forgot to commit these, didn't want to move to a new laptop-tablet and just have them disappear on me. * Facestabber statues now have fun breaking effects. * Fake coronas for candles and prickets. * hnext and hprev are properly dealt with in MobjThinker if P_MobjIsRemoved. --- src/info.c | 14 +++++++------- src/p_enemy.c | 36 +++++++++++++++++++++++++++++++----- src/p_mobj.c | 18 ++++++++++++++++++ 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/info.c b/src/info.c index 57c3c0a04..4f4dc1aa7 100644 --- a/src/info.c +++ b/src/info.c @@ -2137,9 +2137,9 @@ state_t states[NUMSTATES] = {SPR_CBBS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSTATUE - {SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT}, // S_SUSPICIOUSFACESTABBERSTATUE_WAIT - {SPR_CBBS, 0, 23, {NULL}, 0, 0, S_SUSPICIOUSFACESTABBERSTATUE_BURST2}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1 - {SPR_NULL, 0, 40, {A_StatueBurst}, 0, S_FACESTABBER_CHARGE2, S_NULL}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2 + {SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT}, // S_SUSPICIOUSFACESTABBERSTATUE_WAIT + {SPR_CBBS, 0, 23, {NULL}, 0, 0, S_SUSPICIOUSFACESTABBERSTATUE_BURST2}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1 + {SPR_NULL, 0, 40, {A_StatueBurst}, MT_FACESTABBER, S_FACESTABBER_CHARGE2, S_NULL}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2 // Big Tumbleweed {SPR_BTBL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BIGTUMBLEWEED @@ -10048,7 +10048,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_YELLOWSPRINGBALL2, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -10075,7 +10075,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_REDSPRINGBALL2, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -10552,7 +10552,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // damage sfx_None, // activesound MF_SLIDEME|MF_SOLID|MF_PUSHABLE, // flags - MT_FACESTABBER // raisestate + MT_ROCKCRUMBLE3 // raisestate }, { // MT_BIGTUMBLEWEED @@ -14304,7 +14304,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // speed 4*FRACUNIT, // radius 4*FRACUNIT, // height - 0, // display offset + 1, // display offset 4, // mass 0, // damage sfx_None, // activesound diff --git a/src/p_enemy.c b/src/p_enemy.c index d2ef9ab9f..20b32f220 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1188,8 +1188,6 @@ void A_FaceStabRev(mobj_t *actor) return; } - if (actor->hnext) - P_SetTarget(&actor->hnext, NULL); actor->extravalue1 = 0; if (!actor->reactiontime) @@ -1344,13 +1342,14 @@ void A_FaceStabMiss(mobj_t *actor) // // Description: For suspicious statues only... // -// var1 = unused +// var1 = object to create // var2 = effective nextstate for created object // void A_StatueBurst(mobj_t *actor) { - //INT32 locvar1 = var1; + INT32 locvar1 = var1; INT32 locvar2 = var2; + mobjtype_t chunktype = (mobjtype_t)actor->info->raisestate; mobj_t *new; #ifdef HAVE_BLUA @@ -1358,15 +1357,42 @@ void A_StatueBurst(mobj_t *actor) return; #endif - if (!(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, (mobjtype_t)actor->info->raisestate))) + if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1))) return; new->angle = actor->angle; new->target = actor->target; if (locvar2) P_SetMobjState(new, (statenum_t)locvar2); + S_StartSound(new, new->info->attacksound); S_StopSound(actor); S_StartSound(actor, sfx_s3k96); + + { + fixed_t a, b; + fixed_t c = (actor->height>>2) - FixedMul(actor->scale, mobjinfo[chunktype].height>>1); + fixed_t v = 4<radius>>1); + mobj_t *spawned; + UINT8 i; + for (i = 0; i < 8; i++) + { + a = ((i & 1) ? r : (-r)); + b = ((i & 2) ? r : (-r)); + if (i == 4) + { + c += (actor->height>>1); + v = 8<fuse = 3*TICRATE; + } + } } // Function: A_JetJawRoam diff --git a/src/p_mobj.c b/src/p_mobj.c index 6c46fe841..8232586b2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6670,6 +6670,10 @@ void P_MobjThinker(mobj_t *mobj) P_SetTarget(&mobj->target, NULL); if (mobj->tracer && P_MobjWasRemoved(mobj->tracer)) P_SetTarget(&mobj->tracer, NULL); + if (mobj->hnext && P_MobjWasRemoved(mobj->hnext)) + P_SetTarget(&mobj->hnext, NULL); + if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) + P_SetTarget(&mobj->hprev, NULL); mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG); @@ -8612,6 +8616,20 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } } break; + case MT_CANDLE: + case MT_CANDLEPRICKET: + { + // Fake corona!! + mobj_t *corona = P_SpawnMobjFromMobj(mobj, 0, 0, ((mobj->type == MT_CANDLE) ? 40 : 176)<tracer, mobj); + //corona->flags2 |= MF2_LINKDRAW; -- crash??????? can't debug right now... + corona->sprite = SPR_FLAM; + corona->frame = (FF_FULLBRIGHT|FF_TRANS90|12); + corona->tics = -1; + if (mobj->type == MT_CANDLE) + P_SetScale(corona, (corona->destscale = mobj->scale*3)); + } + break; case MT_JACKO1: case MT_JACKO2: case MT_JACKO3: From 0248fcecd40c67fa6adffe0b6d0ff2a93ea46ceb Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 29 May 2018 20:31:28 -0400 Subject: [PATCH 145/212] Some small change Really this is just to prevent the music end up being disorted at max volume --- src/sdl/mixer_sound.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 8938cb749..fd8e64de5 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -458,7 +458,8 @@ static void mix_gme(void *udata, Uint8 *stream, int len) // apply volume to stream for (i = 0, p = (short *)stream; i < len/2; i++, p++) - *p = ((INT32)*p) * music_volume*2/31; + *p = ((INT32)*p) * music_volume*2 / 42; + CONS_Printf("%hs", p); } #endif From e394f7992deb81a195709126bec7e9cc68d14114 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 29 May 2018 22:12:36 -0400 Subject: [PATCH 146/212] Removed CONS_Printf line. That wasn't meant to be commited. --- src/sdl/mixer_sound.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index fd8e64de5..497422724 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -459,7 +459,6 @@ static void mix_gme(void *udata, Uint8 *stream, int len) // apply volume to stream for (i = 0, p = (short *)stream; i < len/2; i++, p++) *p = ((INT32)*p) * music_volume*2 / 42; - CONS_Printf("%hs", p); } #endif From 2ec1c3cd9d6110dc3bb13576762671530934986e Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 30 May 2018 23:16:57 +0100 Subject: [PATCH 147/212] First commit on new tablet-laptop! * Robo Hood. * Hi MI, I know you're looking at this just because it features Robo hood. :V --- src/dehacked.c | 11 ++-- src/info.c | 41 ++++++------- src/info.h | 11 ++-- src/p_enemy.c | 156 +++++++++++++++++++++++++++++++++++++++---------- src/p_mobj.c | 14 +++++ 5 files changed, 173 insertions(+), 60 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b52c79461..78a9912a4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1703,7 +1703,9 @@ static actionpointer_t actionpointers[] = {{A_JetJawChomp}, "A_JETJAWCHOMP"}, {{A_PointyThink}, "A_POINTYTHINK"}, {{A_CheckBuddy}, "A_CHECKBUDDY"}, + {{A_HoodFire}, "A_HOODFIRE"}, {{A_HoodThink}, "A_HOODTHINK"}, + {{A_HoodFall}, "A_HOODFALL"}, {{A_ArrowCheck}, "A_ARROWCHECK"}, {{A_SnailerThink}, "A_SNAILERTHINK"}, {{A_SharpChase}, "A_SHARPCHASE"}, @@ -3757,11 +3759,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Robo-Hood "S_ROBOHOOD_LOOK", - "S_ROBOHOOD_STND", - "S_ROBOHOOD_SHOOT", - "S_ROBOHOOD_JUMP", + "S_ROBOHOOD_STAND", + "S_ROBOHOOD_FIRE1", + "S_ROBOHOOD_FIRE2", + "S_ROBOHOOD_JUMP1", "S_ROBOHOOD_JUMP2", - "S_ROBOHOOD_FALL", + "S_ROBOHOOD_JUMP3", // CastleBot FaceStabber "S_FACESTABBER_STND1", diff --git a/src/info.c b/src/info.c index 4f4dc1aa7..01edc0eb2 100644 --- a/src/info.c +++ b/src/info.c @@ -981,12 +981,13 @@ state_t states[NUMSTATES] = {SPR_PNTY, 1, 1, {A_CheckBuddy}, 0, 0, S_POINTYBALL1}, // S_POINTYBALL1 // Robo-Hood - {SPR_ARCH, 0, 14, {A_Look}, (512<<16), 0, S_ROBOHOOD_LOOK}, // S_ROBOHOOD_LOOK - {SPR_ARCH, 2, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_STND}, // S_ROBOHOOD_STND - {SPR_ARCH, 0, 35, {A_FireShot}, MT_ARROW, -24, S_ROBOHOOD_STND}, // S_ROBOHOOD_SHOOT - {SPR_ARCH, 1, 1, {A_BunnyHop}, 8, 5, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP - {SPR_ARCH, 1, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP2 - {SPR_ARCH, 0, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_FALL}, // S_ROBOHOOD_FALL + {SPR_ARCH, 0, 4, {A_Look}, 2048<x; + y -= actor->y; + z -= actor->z; + + dh = P_AproxDistance(x, y); + + actor->momx = FixedMul(FixedDiv(x, dh), speed); + actor->momy = FixedMul(FixedDiv(y, dh), speed); + + if (!gravity) + return; + + dh = FixedDiv(FixedMul(dh, gravity), speed); + actor->momz = (dh>>1) + FixedDiv(z, dh<<1); +} + +// Function: A_HoodFire +// +// Description: Firing Robo-Hood +// +// var1 = object type to fire +// var2 = unused +// +void A_HoodFire(mobj_t *actor) +{ + mobj_t *arrow; + INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_HoodFire", actor)) + return; +#endif + + // Check target first. + if (!actor->target) + { + actor->reactiontime = actor->info->reactiontime; + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + A_FaceTarget(actor); + + if (!(arrow = P_SpawnMissile(actor, actor->target, (mobjtype_t)locvar1))) + return; + + // Set a parabolic trajectory for the arrow. + P_ParabolicMove(arrow, actor->target->x, actor->target->y, actor->target->z, arrow->info->speed); +} + // Function: A_HoodThink // // Description: Thinker for Robo-Hood @@ -1600,53 +1658,87 @@ void A_CheckBuddy(mobj_t *actor) // void A_HoodThink(mobj_t *actor) { + fixed_t dx, dy, dz, dm; + boolean checksight; #ifdef HAVE_BLUA if (LUA_CallAction("A_HoodThink", actor)) return; #endif - // Currently in the air... - if (!(actor->eflags & MFE_VERTICALFLIP) && actor->z > actor->floorz) - { - if (actor->momz > 0) - P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising - else - P_SetMobjStateNF(actor, actor->info->raisestate); // Falling - - return; - } - else if ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height < actor->ceilingz) - { - if (actor->momz < 0) - P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising - else - P_SetMobjStateNF(actor, actor->info->raisestate); // Falling - - return; - } - - if (actor->state == &states[actor->info->xdeathstate] - || actor->state == &states[actor->info->raisestate]) - P_SetMobjStateNF(actor, actor->info->seestate); + // Check target first. if (!actor->target) { + actor->reactiontime = actor->info->reactiontime; P_SetMobjState(actor, actor->info->spawnstate); return; } - A_FaceTarget(actor); // Aiming... aiming... + dx = (actor->target->x - actor->x), dy = (actor->target->y - actor->y), dz = (actor->target->z - actor->z); + dm = P_AproxDistance(dx, dy); + // Target dangerously close to robohood, retreat then. + if ((dm < 256<info->raisestate); + return; + } - if (--actor->reactiontime > 0) + // If target on sight, look at it. + if ((checksight = P_CheckSight(actor, actor->target))) + { + angle_t dang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + if (actor->angle >= ANGLE_180) + { + actor->angle = InvAngle(actor->angle)>>1; + actor->angle = InvAngle(actor->angle); + } + else + actor->angle >>= 1; + + if (dang >= ANGLE_180) + { + dang = InvAngle(dang)>>1; + dang = InvAngle(dang); + } + else + dang >>= 1; + + actor->angle += dang; + } + + // Check whether to do anything. + if ((--actor->reactiontime) <= 0) + { + actor->reactiontime = actor->info->reactiontime; + + // If way too far, don't shoot. + if ((dm < (3072<info->missilestate); + return; + } + } +} + +// Function: A_HoodFall +// +// Description: Falling Robo-Hood +// +// var1 = unused +// var2 = unused +// +void A_HoodFall(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_HoodFall", actor)) + return; +#endif + + if (!P_IsObjectOnGround(actor)) return; - // Shoot, if not too close (cheap shots are lame) - if ((P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) > FixedMul(192*FRACUNIT, actor->scale)) - || (actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH))) // If you can't jump, might as well shoot regardless of distance! - P_SetMobjState(actor, actor->info->missilestate); - else if (!(actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH)))// But we WILL jump! - P_SetMobjState(actor, actor->info->painstate); - + actor->momx = actor->momy = 0; actor->reactiontime = actor->info->reactiontime; + P_SetMobjState(actor, actor->info->seestate); } // Function: A_ArrowCheck diff --git a/src/p_mobj.c b/src/p_mobj.c index 8232586b2..3b6ea394c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7354,6 +7354,20 @@ void P_MobjThinker(mobj_t *mobj) } P_MobjCheckWater(mobj); break; + case MT_ARROW: + if (!(mobj->extravalue1) && (mobj->momz < 0)) + { + mobj->extravalue1 = 1; + S_StartSound(mobj, mobj->info->activesound); + } + if (leveltime & 1) + { + mobj_t *dust = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_PARTICLE); + dust->tics = 18; + dust->scalespeed = 4096; + dust->destscale = FRACUNIT/32; + } + break; case MT_EMERALDSPAWN: if (mobj->threshold) { From 8d00192fee38fe940322aa58e7c98062af3df091 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 31 May 2018 21:00:12 +0100 Subject: [PATCH 148/212] New CEZ hardcoding done!! * Better Robo Hood arrows. * Shield break animation for Egg Guard. (Temporary state slot so I don't have to compile from scratch until I do something more complicated later.) * Suspicious Facestabber Statue animates a little before bursting open. * Fix Facestabber radius. * Fix some stuff in Flicky functions that could be overwritten in Lua call actions by mistake. --- src/dehacked.c | 6 ++--- src/info.c | 28 ++++++++++---------- src/info.h | 6 ++--- src/p_enemy.c | 71 ++++++++++++++++++-------------------------------- src/p_inter.c | 13 ++++----- src/p_mobj.c | 47 ++++++++++++++++++++++++++------- 6 files changed, 89 insertions(+), 82 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 78a9912a4..c25e9e1fa 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1706,7 +1706,7 @@ static actionpointer_t actionpointers[] = {{A_HoodFire}, "A_HOODFIRE"}, {{A_HoodThink}, "A_HOODTHINK"}, {{A_HoodFall}, "A_HOODFALL"}, - {{A_ArrowCheck}, "A_ARROWCHECK"}, + {{A_ArrowBonks}, "A_ARROWBONKS"}, {{A_SnailerThink}, "A_SNAILERTHINK"}, {{A_SharpChase}, "A_SHARPCHASE"}, {{A_SharpSpin}, "A_SHARPSPIN"}, @@ -4709,8 +4709,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Arrow "S_ARROW", - "S_ARROWUP", - "S_ARROWDOWN", + "S_TEMPSHI", + "S_ARROWBONK", // Trapgoyle Demon fire "S_DEMONFIRE1", diff --git a/src/info.c b/src/info.c index 01edc0eb2..e791c7728 100644 --- a/src/info.c +++ b/src/info.c @@ -1933,9 +1933,9 @@ state_t states[NUMSTATES] = {SPR_CBLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANNONBALL1 - {SPR_AROW, 0, 1, {A_ArrowCheck}, 0, 0, S_ARROW}, // S_ARROW - {SPR_AROW, 1, 1, {A_ArrowCheck}, 0, 0, S_ARROWUP}, // S_ARROWUP - {SPR_AROW, 2, 1, {A_ArrowCheck}, 0, 0, S_ARROWDOWN}, // S_ARROWDOWN + {SPR_AROW, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ARROW + {SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_TEMPSHI + {SPR_AROW, FF_ANIMATE, TICRATE, {A_ArrowBonks}, 7, 2, S_NULL}, // S_ARROWBONK {SPR_CFIR, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DEMONFIRE2}, // S_DEMONFIRE1 {SPR_CFIR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEMONFIRE3}, // S_DEMONFIRE2 @@ -2138,8 +2138,8 @@ state_t states[NUMSTATES] = {SPR_CBBS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSTATUE - {SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT}, // S_SUSPICIOUSFACESTABBERSTATUE_WAIT - {SPR_CBBS, 0, 23, {NULL}, 0, 0, S_SUSPICIOUSFACESTABBERSTATUE_BURST2}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1 + {SPR_CBBS, 0, 5, {A_Look}, 768*FRACUNIT, 0, S_SUSPICIOUSFACESTABBERSTATUE_WAIT}, // S_SUSPICIOUSFACESTABBERSTATUE_WAIT + {SPR_CBBS, FF_ANIMATE, 23, {NULL}, 6, 1, S_SUSPICIOUSFACESTABBERSTATUE_BURST2}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST1 {SPR_NULL, 0, 40, {A_StatueBurst}, MT_FACESTABBER, S_FACESTABBER_CHARGE2, S_NULL}, // S_SUSPICIOUSFACESTABBERSTATUE_BURST2 // Big Tumbleweed @@ -4260,7 +4260,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_cybdth, // deathsound 3, // speed - 36*FRACUNIT, // radius + 32*FRACUNIT, // radius 72*FRACUNIT, // height 0, // display offset 100, // mass @@ -4287,7 +4287,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 36*FRACUNIT, // radius + 32*FRACUNIT, // radius 72*FRACUNIT, // height 0, // display offset DMG_SPIKE, // mass @@ -4337,7 +4337,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_s3k7b, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_XPLD1, // deathstate + S_TEMPSHI, // deathstate S_NULL, // xdeathstate sfx_wbreak, // deathsound 3, // speed @@ -8625,18 +8625,18 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_NULL, // deathstate - S_ARROWDOWN, // xdeathstate + S_ARROWBONK, // deathstate + S_NULL, // xdeathstate sfx_s3k52, // deathsound 16*FRACUNIT, // speed 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 0, // mass + DMG_SPIKE, // mass 1, // damage sfx_s3k51, // activesound MF_NOBLOCKMAP|MF_MISSILE, // flags - S_ARROWUP // raisestate + S_NULL // raisestate }, { // MT_DEMONFIRE @@ -10519,7 +10519,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 36*FRACUNIT, // radius + 32*FRACUNIT, // radius 72*FRACUNIT, // height 0, // display offset 100, // mass @@ -10546,7 +10546,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 36*FRACUNIT, // radius + 32*FRACUNIT, // radius 72*FRACUNIT, // height 0, // display offset 100, // mass diff --git a/src/info.h b/src/info.h index 8134a1a49..5f84b22d4 100644 --- a/src/info.h +++ b/src/info.h @@ -105,7 +105,7 @@ void A_CheckBuddy(); void A_HoodFire(); void A_HoodThink(); void A_HoodFall(); -void A_ArrowCheck(); +void A_ArrowBonks(); void A_SnailerThink(); void A_SharpChase(); void A_SharpSpin(); @@ -2061,8 +2061,8 @@ typedef enum state // Arrow S_ARROW, - S_ARROWUP, - S_ARROWDOWN, + S_TEMPSHI, + S_ARROWBONK, // Trapgoyle Demon fire S_DEMONFIRE1, diff --git a/src/p_enemy.c b/src/p_enemy.c index 8a09df286..2c55210b7 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -66,7 +66,7 @@ void A_CheckBuddy(mobj_t *actor); void A_HoodFire(mobj_t *actor); void A_HoodThink(mobj_t *actor); void A_HoodFall(mobj_t *actor); -void A_ArrowCheck(mobj_t *actor); +void A_ArrowBonks(mobj_t *actor); void A_SnailerThink(mobj_t *actor); void A_SharpChase(mobj_t *actor); void A_SharpSpin(mobj_t *actor); @@ -1741,48 +1741,29 @@ void A_HoodFall(mobj_t *actor) P_SetMobjState(actor, actor->info->seestate); } -// Function: A_ArrowCheck +// Function: A_ArrowBonks // -// Description: Checks arrow direction and adjusts sprite accordingly +// Description: Arrow momentum setting on collision // // var1 = unused // var2 = unused // -void A_ArrowCheck(mobj_t *actor) +void A_ArrowBonks(mobj_t *actor) { - fixed_t x,y,z; - angle_t angle; - fixed_t dist; - #ifdef HAVE_BLUA - if (LUA_CallAction("A_ArrowCheck", actor)) + if (LUA_CallAction("A_ArrowBonks", actor)) return; #endif - // Movement vector - x = actor->momx; - y = actor->momy; - z = actor->momz; + if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) + || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) + actor->angle += ANGLE_180; - // Calculate the angle of movement. - /* - Z - / | - / | - / | - 0------dist(X,Y) - */ + P_SetObjectMomZ(actor, 8*actor->scale, false); + P_InstaThrust(actor, actor->angle, -6*actor->scale); - dist = P_AproxDistance(x, y); - - angle = R_PointToAngle2(0, 0, dist, z); - - if (angle > ANG20 && angle <= ANGLE_180) - P_SetMobjStateNF(actor, actor->info->raisestate); - else if (angle < ANG340 && angle > ANGLE_180) - P_SetMobjStateNF(actor, actor->info->xdeathstate); - else - P_SetMobjStateNF(actor, actor->info->spawnstate); + actor->flags = (actor->flags|MF_NOCLIPHEIGHT) & ~MF_NOGRAVITY; + actor->z += P_MobjFlip(actor); } // Function: A_SnailerThink @@ -10966,14 +10947,13 @@ void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fi // void A_FlickyFly(mobj_t *actor) { - // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; + INT32 locvar1 = var1; + INT32 locvar2 = var2; #ifdef HAVE_BLUA if (LUA_CallAction("A_FlickyFly", actor)) return; #endif - P_InternalFlickyFly(actor, var1, var2, + P_InternalFlickyFly(actor, locvar1, locvar2, FINECOSINE((((actor->fuse % 36) * ANG10) >> ANGLETOFINESHIFT) & FINEMASK) ); } @@ -10987,14 +10967,13 @@ void A_FlickyFly(mobj_t *actor) // void A_FlickySoar(mobj_t *actor) { - // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyFly instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; + INT32 locvar1 = var1; + INT32 locvar2 = var2; #ifdef HAVE_BLUA if (LUA_CallAction("A_FlickySoar", actor)) return; #endif - P_InternalFlickyFly(actor, var1, var2, + P_InternalFlickyFly(actor, locvar1, locvar2, 2*(FRACUNIT/2 - abs(FINECOSINE((((actor->fuse % 144) * 5*ANG1/2) >> ANGLETOFINESHIFT) & FINEMASK))) ); @@ -11059,14 +11038,13 @@ void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angl // void A_FlickyHop(mobj_t *actor) { - // We're not setting up locvars here - it passes var1 and var2 through to P_InternalFlickyHop instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; + INT32 locvar1 = var1; + INT32 locvar2 = var2; #ifdef HAVE_BLUA if (LUA_CallAction("A_FlickyHop", actor)) return; #endif - P_InternalFlickyHop(actor, var1, var2, actor->angle); + P_InternalFlickyHop(actor, locvar1, locvar2, actor->angle); } // Function: A_FlickyFlounder @@ -11149,13 +11127,14 @@ void A_FlickyHeightCheck(mobj_t *actor) // void A_FlickyFlutter(mobj_t *actor) { - // We're not setting up locvars here - it passes var1 and var2 through to A_FlickyCheck instead. - //INT32 locvar1 = var1; - //INT32 locvar2 = var2; + INT32 locvar1 = var1; + INT32 locvar2 = var2; #ifdef HAVE_BLUA if (LUA_CallAction("A_FlickyFlutter", actor)) return; #endif + var1 = locvar1; + var2 = locvar2; A_FlickyCheck(actor); var1 = ANG30; diff --git a/src/p_inter.c b/src/p_inter.c index 5161f4cc3..fed459d6a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1430,13 +1430,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // experimental bounce if (special->target) special->target->extravalue1 = -special->target->info->speed; - return; } - else if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) - || ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) - || ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0)) - || (player->pflags & (PF_SPINNING|PF_GLIDING)) - || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? + else { // Shatter the shield! toucher->momx = -toucher->momx/2; @@ -2358,6 +2353,12 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } break; + case MT_EGGSHIELD: + P_SetObjectMomZ(target, 4*target->scale, false); + P_InstaThrust(target, target->angle, 3*target->scale); + target->flags = (target->flags|MF_NOCLIPHEIGHT) & ~MF_NOGRAVITY; + break; + case MT_EGGMOBILE3: { thinker_t *th; diff --git a/src/p_mobj.c b/src/p_mobj.c index 3b6ea394c..dbf5f5880 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7238,6 +7238,9 @@ void P_MobjThinker(mobj_t *mobj) return; } break; + case MT_EGGSHIELD: + mobj->flags2 ^= MF2_DONTDRAW; + break; case MT_EGGTRAP: // Egg Capsule animal release if (mobj->fuse > 0 && mobj->fuse < 2*TICRATE-(TICRATE/7) && (mobj->fuse & 3)) @@ -7355,18 +7358,42 @@ void P_MobjThinker(mobj_t *mobj) P_MobjCheckWater(mobj); break; case MT_ARROW: - if (!(mobj->extravalue1) && (mobj->momz < 0)) + if (mobj->flags & MF_MISSILE) { - mobj->extravalue1 = 1; - S_StartSound(mobj, mobj->info->activesound); - } - if (leveltime & 1) - { - mobj_t *dust = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_PARTICLE); - dust->tics = 18; - dust->scalespeed = 4096; - dust->destscale = FRACUNIT/32; + // Calculate the angle of movement. + /* + momz + / | + / | + / | + 0------dist(momx,momy) + */ + + fixed_t dist = P_AproxDistance(mobj->momx, mobj->momy); + angle_t angle = R_PointToAngle2(0, 0, dist, mobj->momz); + + if (angle > ANG20 && angle <= ANGLE_180) + mobj->frame = 2; + else if (angle < ANG340 && angle > ANGLE_180) + mobj->frame = 0; + else + mobj->frame = 1; + + if (!(mobj->extravalue1) && (mobj->momz < 0)) + { + mobj->extravalue1 = 1; + S_StartSound(mobj, mobj->info->activesound); + } + if (leveltime & 1) + { + mobj_t *dust = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_PARTICLE); + dust->tics = 18; + dust->scalespeed = 4096; + dust->destscale = FRACUNIT/32; + } } + else + mobj->flags2 ^= MF2_DONTDRAW; break; case MT_EMERALDSPAWN: if (mobj->threshold) From 6e07631cc9851ca8a4d9ac0e6aa143fe6fdd75b0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 3 Jun 2018 22:41:54 +0100 Subject: [PATCH 149/212] MONSTER COMMIT. OLD SPECIAL STAGES: * Spheres in old special stages instead of rings! * Individual timers in old special stages instead of a global one! * Old special stages use a variant of the NiGHTS HUD now! * Special stage damage in old special stages loses 5 seconds of time instead of 10 rings/spheres! * All damage gained through old special stages is converted to special stage damage! As a consequence, the special spikeball has no need to be special anymore. * Made emerald gaining function be based on special stage number rather than gained emeralds! * Consistency with... NiGHTS SPECIAL STAGES: * Spheres now flash in bonus time. https://cdn.discordapp.com/attachments/400761370800422922/452590553100713984/srb20032.gif * Sphere and ring mapthingnums are now less fucked up in 'em. (Rings are 300, same as usual, while Spheres are now 1706 replacing NiGHTS Wings.) SPECIAL STAGES IN GENERAL: * useNightsSS is now dead. Each individual special stage is now assessed for NiGHTS-mode behaviour based on maptol & TOL_NIGHTS. * CRAWLA HONCHO\n CAN NOW BE\n SUPER CRAWLA HONCHO end tally modification now also includes a mini-tutorial on turning super. https://cdn.discordapp.com/attachments/400761370800422922/452844894113759233/srb20036.gif * SONIC GOT A CHAOS EMERALD? https://cdn.discordapp.com/attachments/400761370800422922/452623869497573386/srb20034.gif NiGHTS NON-SPECIAL STAGES: * Colour Chips and Star Chips! Replaces Spheres and Rings of NiGHTS Special Stages. * Colour Chips turn yellow in bonus time. * Ideya! * Its own "drowning" music! * All of the object types for Dream Hill. * GIF: https://cdn.discordapp.com/attachments/400761370800422922/452844894113759233/srb20036.gif RANDOM BS: * Turn super with the spin button instead of the jump button! * Followmobj now correctly set with P_SetTarget instead of pointer assignment. * Emerald hunt uses new sprites! * Made unlock noise different from emblem gain noise! (It's the CRAWLA HONCHO CAN NOW TURN yadda yadda sound from S3K now.) --- src/d_clisrv.c | 22 ++-- src/d_clisrv.h | 3 +- src/d_netcmd.c | 7 +- src/d_player.h | 5 +- src/dehacked.c | 70 +++++++---- src/doomstat.h | 3 +- src/f_finale.c | 2 +- src/g_game.c | 6 +- src/hardware/hw_light.c | 13 +- src/hu_stuff.c | 5 +- src/hu_stuff.h | 2 +- src/info.c | 256 ++++++++++++++++++++++++++++++---------- src/info.h | 83 ++++++++----- src/lua_hud.h | 2 +- src/lua_playerlib.c | 14 ++- src/m_cheat.c | 22 ++-- src/p_enemy.c | 19 ++- src/p_inter.c | 228 ++++++++++++++++++++--------------- src/p_local.h | 1 + src/p_mobj.c | 216 ++++++++++++++++----------------- src/p_mobj.h | 4 +- src/p_saveg.c | 16 +-- src/p_setup.c | 71 +++++++---- src/p_setup.h | 1 + src/p_spec.c | 14 +-- src/p_tick.c | 89 +++++++------- src/p_user.c | 161 ++++++++++++++----------- src/r_things.c | 2 +- src/screen.c | 7 +- src/sounds.c | 14 ++- src/sounds.h | 4 +- src/st_stuff.c | 211 ++++++++++++++++++++------------- src/y_inter.c | 104 ++++++++++------ 33 files changed, 1006 insertions(+), 671 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 5832b2c27..14677b8a1 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -513,7 +513,8 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); // Score is resynched in the rspfirm resync packet - rsp->rings = LONG(players[i].rings); + rsp->rings = SHORT(players[i].rings); + rsp->spheres = SHORT(players[i].spheres); rsp->lives = players[i].lives; rsp->continues = players[i].continues; rsp->scoreadd = players[i].scoreadd; @@ -643,7 +644,8 @@ static void resynch_read_player(resynch_pak *rsp) players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); // Score is resynched in the rspfirm resync packet - players[i].rings = LONG(rsp->rings); + players[i].rings = SHORT(rsp->rings); + players[i].spheres = SHORT(rsp->spheres); players[i].lives = rsp->lives; players[i].continues = rsp->continues; players[i].scoreadd = rsp->scoreadd; @@ -2377,11 +2379,11 @@ static void CL_RemovePlayer(INT32 playernum) if (gametype == GT_CTF) P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! - // If in a special stage, redistribute the player's rings across + // If in a special stage, redistribute the player's spheres across // the remaining players. if (G_IsSpecialStage(gamemap)) { - INT32 i, count, increment, rings; + INT32 i, count, increment, spheres; for (i = 0, count = 0; i < MAXPLAYERS; i++) { @@ -2390,19 +2392,19 @@ static void CL_RemovePlayer(INT32 playernum) } count--; - rings = players[playernum].rings; - increment = rings/count; + spheres = players[playernum].spheres; + increment = spheres/count; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && i != playernum) { - if (rings < increment) - P_GivePlayerRings(&players[i], rings); + if (spheres < increment) + P_GivePlayerSpheres(&players[i], spheres); else - P_GivePlayerRings(&players[i], increment); + P_GivePlayerSpheres(&players[i], increment); - rings -= increment; + spheres -= increment; } } } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index bdf332665..bdb85a76c 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -164,7 +164,8 @@ typedef struct UINT16 powers[NUMPOWERS]; // Score is resynched in the confirm resync packet - INT32 rings; + INT16 rings; + INT16 spheres; SINT8 lives; SINT8 continues; UINT8 scoreadd; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e01178155..bd1f93512 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -309,8 +309,8 @@ consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Centiseconds"}, {2, "Mania"}, {3, "Tics"}, {0, NULL}}; -consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display +static CV_PossibleValue_t timetic_cons_t[] = {{0, "Classic"}, {1, "Centiseconds"}, {2, "Mania"}, {3, "Tics"}, {0, NULL}}; +consvar_t cv_timetic = {"timerres", "Classic", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-person only"}, {2, "Always"}, {0, NULL}}; consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -2682,8 +2682,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) // Clear player score and rings if a spectator. if (players[playernum].spectator) { - players[playernum].score = 0; - players[playernum].rings = 0; + players[playernum].score = players[playernum].rings = 0; if (players[playernum].mo) players[playernum].mo->health = 1; } diff --git a/src/d_player.h b/src/d_player.h index e1350fe67..24c4f9252 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -324,7 +324,8 @@ typedef struct player_s angle_t drawangle; // player's ring count - INT32 rings; + INT16 rings; + INT16 spheres; SINT8 pity; // i pity the fool. INT32 currentweapon; // current weapon selected. @@ -460,7 +461,7 @@ typedef struct player_s tic_t marebegunat; // Leveltime when mare begun tic_t startedtime; // Time which you started this mare with. tic_t finishedtime; // Time it took you to finish the mare (used for display) - INT16 finishedrings; // The rings you had left upon finishing the mare + INT16 finishedspheres; // The spheres you had left upon finishing the mare UINT32 marescore; // score for this nights stage UINT32 lastmarescore; // score for the last mare UINT8 lastmare; // previous mare diff --git a/src/dehacked.c b/src/dehacked.c index c25e9e1fa..ca17614ed 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2673,10 +2673,6 @@ static void readmaincfg(MYFILE *f) sstage_start = (INT16)value; sstage_end = (INT16)(sstage_start+6); // 7 special stages total } - else if (fastcmp(word, "USENIGHTSSS")) - { - useNightsSS = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); - } else if (fastcmp(word, "REDTEAM")) { skincolor_redteam = (UINT8)get_number(word2); @@ -3799,6 +3795,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Egg Shield for Egg Guard "S_EGGSHIELD", + "S_EGGSHIELDBREAK", // Green Snapper "S_GSNAPPER_STND", @@ -4367,8 +4364,17 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_RING", // Blue Sphere for special stages - "S_BLUEBALL", - "S_BLUEBALLSPARK", + "S_BLUESPHERE", + "S_BLUESPHEREBONUS", + "S_BLUESPHERESPARK", + + // NiGHTS Chip + "S_NIGHTSCHIP", + "S_NIGHTSCHIPBONUS", + + // NiGHTS Star + "S_NIGHTSSTAR", + "S_NIGHTSSTARXMAS", // Gravity Wells for special stages "S_GRAVWELLGREEN", @@ -4426,8 +4432,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CEMG6", "S_CEMG7", - // Emeralds (for hunt) - "S_EMER1", + // Emerald hunt shards + "S_SHRD1", + "S_SHRD2", + "S_SHRD3", // Bubble Source "S_BUBBLES1", @@ -4709,7 +4717,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Arrow "S_ARROW", - "S_TEMPSHI", "S_ARROWBONK", // Trapgoyle Demon fire @@ -4739,6 +4746,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_POLYGONTREE", "S_BUSHTREE", "S_BUSHREDTREE", + "S_SPRINGTREE", // THZ flowers "S_THZFLOWERA", // THZ1 Steam flower @@ -6007,9 +6015,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_NIGHTSCORE90_2", "S_NIGHTSCORE100_2", - "S_NIGHTSWING", - "S_NIGHTSWING_XMAS", - // NiGHTS Paraloop Powerups "S_NIGHTSSUPERLOOP", "S_NIGHTSDRILLREFILL", @@ -6027,14 +6032,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ORBITEM6", "S_ORBITEM7", "S_ORBITEM8", - "S_ORBITEM9", - "S_ORBITEM10", - "S_ORBITEM11", - "S_ORBITEM12", - "S_ORBITEM13", - "S_ORBITEM14", - "S_ORBITEM15", - "S_ORBITEM16", + "S_ORBIDYA1", + "S_ORBIDYA2", + "S_ORBIDYA3", + "S_ORBIDYA4", + "S_ORBIDYA5", // "Flicky" helper "S_NIGHTOPIANHELPER1", @@ -6047,6 +6049,26 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_NIGHTOPIANHELPER8", "S_NIGHTOPIANHELPER9", + // Nightopian + "S_PIAN0", + "S_PIAN1", + "S_PIAN2", + "S_PIAN3", + "S_PIAN4", + "S_PIAN5", + "S_PIAN6", + "S_PIANSING", + + // Shleep + "S_SHLEEP1", + "S_SHLEEP2", + "S_SHLEEP3", + "S_SHLEEP4", + "S_SHLEEPBOUNCE1", + "S_SHLEEPBOUNCE2", + "S_SHLEEPBOUNCE3", + + // Secret badniks and hazards, shhhh "S_HIVEELEMENTAL_LOOK", "S_HIVEELEMENTAL_PREPARE1", @@ -6322,7 +6344,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Collectible Items "MT_RING", "MT_FLINGRING", // Lost ring - "MT_BLUEBALL", // Blue sphere replacement for special stages + "MT_BLUESPHERE", // Blue sphere replacement for special stages "MT_REDTEAMRING", //Rings collectable by red team. "MT_BLUETEAMRING", //Rings collectable by blue team. "MT_TOKEN", // Special Stage Token @@ -6466,6 +6488,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_POLYGONTREE", "MT_BUSHTREE", "MT_BUSHREDTREE", + "MT_SPRINGTREE", // Techno Hill Scenery "MT_THZFLOWER1", @@ -6778,7 +6801,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_HOOPCOLLIDE", // Collision detection for NiGHTS hoops "MT_HOOPCENTER", // Center of a hoop "MT_NIGHTSCORE", - "MT_NIGHTSWING", + "MT_NIGHTSCHIP", // NiGHTS Chip + "MT_NIGHTSSTAR", // NiGHTS Star "MT_NIGHTSSUPERLOOP", "MT_NIGHTSDRILLREFILL", "MT_NIGHTSHELPER", @@ -6786,6 +6810,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_NIGHTSLINKFREEZE", "MT_EGGCAPSULE", "MT_NIGHTOPIANHELPER", // the actual helper object that orbits you + "MT_PIAN", // decorative singing friend + "MT_SHLEEP", // almost-decorative sleeping enemy // Secret badniks and hazards, shhhh "MT_HIVEELEMENTAL", diff --git a/src/doomstat.h b/src/doomstat.h index d4735f6b2..3a2084e29 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -134,7 +134,6 @@ extern boolean hidetitlepics; extern INT16 bootmap; //bootmap for loading a map on startup extern boolean looptitle; -extern boolean useNightsSS; // CTF colors. extern UINT8 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering; @@ -175,7 +174,7 @@ extern cutscene_t *cutscenes[128]; extern INT16 nextmapoverride; extern boolean skipstats; -extern UINT32 totalrings; // Total # of rings in a level +extern UINT32 ssspheres; // Total # of spheres in a level // Fun extra stuff extern INT16 lastmap; // Last level you were at (returning from special stages). diff --git a/src/f_finale.c b/src/f_finale.c index db62ddf09..2191e8673 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1345,7 +1345,7 @@ void F_GameEvaluationDrawer(void) ++timesBeatenUltimate; if (M_UpdateUnlockablesAndExtraEmblems()) - S_StartSound(NULL, sfx_ncitem); + S_StartSound(NULL, sfx_s3k68); G_SaveGameData(); } diff --git a/src/g_game.c b/src/g_game.c index 509ccf0ab..79f62bcd1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -116,7 +116,7 @@ INT32 secondarydisplayplayer; // for splitscreen tic_t gametic; tic_t levelstarttic; // gametic at level start -UINT32 totalrings; // for intermission +UINT32 ssspheres; // old special stage INT16 lastmap; // last level you were at (returning from special stages) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) @@ -129,7 +129,6 @@ boolean hidetitlepics = false; INT16 bootmap; //bootmap for loading a map on startup boolean looptitle = false; -boolean useNightsSS = false; UINT8 skincolor_redteam = SKINCOLOR_RED; UINT8 skincolor_blueteam = SKINCOLOR_BLUE; @@ -2201,7 +2200,7 @@ void G_PlayerReborn(INT32 player) p->pflags |= PF_JUMPDOWN; p->playerstate = PST_LIVE; - p->rings = 0; // 0 rings + p->rings = p->spheres = 0; // 0 rings p->panim = PA_IDLE; // standing animation //if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there @@ -3209,7 +3208,6 @@ void G_LoadGameSettings(void) spstage_start = 1; sstage_start = 50; sstage_end = 57; // 8 special stages in vanilla SRB2 - useNightsSS = false; //true; // initialize free sfx slots for skin sounds S_InitRuntimeSounds(); diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index fbec957f7..aee6f9396 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -229,10 +229,12 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_TOKE &lspr[REDBALL_L], // SPR_RFLG &lspr[BLUEBALL_L], // SPR_BFLG - &lspr[NOLIGHT], // SPR_NWNG + &lspr[NOLIGHT], // SPR_SPHR + &lspr[NOLIGHT], // SPR_NCHP + &lspr[NOLIGHT], // SPR_NSTR &lspr[NOLIGHT], // SPR_EMBM &lspr[NOLIGHT], // SPR_CEMG - &lspr[NOLIGHT], // SPR_EMER + &lspr[NOLIGHT], // SPR_SHRD // Interactive Objects &lspr[NOLIGHT], // SPR_BBLS @@ -298,6 +300,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_TRE3 &lspr[NOLIGHT], // SPR_TRE4 &lspr[NOLIGHT], // SPR_TRE5 + &lspr[NOLIGHT], // SPR_TRE6 // Techno Hill Scenery &lspr[NOLIGHT], // SPR_THZP @@ -498,6 +501,9 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_HSCR &lspr[NOLIGHT], // SPR_NPRU &lspr[NOLIGHT], // SPR_CAPS + &lspr[INVINCIBLE_L], // SPR_IDYA + &lspr[NOLIGHT], // SPR_NTPN + &lspr[NOLIGHT], // SPR_SHLP // Secret badniks and hazards, shhhh &lspr[NOLIGHT], // SPR_HIVE @@ -538,9 +544,6 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_ROIO &lspr[NOLIGHT], // SPR_ROIP - // Blue Spheres - &lspr[NOLIGHT], // SPR_BBAL - // Gravity Well Objects &lspr[NOLIGHT], // SPR_GWLG &lspr[NOLIGHT], // SPR_GWLR diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a13801388..456f97bac 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -89,7 +89,7 @@ patch_t *tallinfin; // coop hud //------------------------------------------- -patch_t *emeraldpics[3][7]; // 0 = normal, 1 = tiny, 2 = coinbox +patch_t *emeraldpics[3][8]; // 0 = normal, 1 = tiny, 2 = coinbox static patch_t *emblemicon; patch_t *tokenicon; static patch_t *exiticon; @@ -256,6 +256,7 @@ void HU_LoadGraphics(void) emeraldpics[0][4] = W_CachePatchName("CHAOS5", PU_HUDGFX); emeraldpics[0][5] = W_CachePatchName("CHAOS6", PU_HUDGFX); emeraldpics[0][6] = W_CachePatchName("CHAOS7", PU_HUDGFX); + emeraldpics[0][7] = W_CachePatchName("CHAOS8", PU_HUDGFX); emeraldpics[1][0] = W_CachePatchName("TEMER1", PU_HUDGFX); emeraldpics[1][1] = W_CachePatchName("TEMER2", PU_HUDGFX); @@ -264,6 +265,7 @@ void HU_LoadGraphics(void) emeraldpics[1][4] = W_CachePatchName("TEMER5", PU_HUDGFX); emeraldpics[1][5] = W_CachePatchName("TEMER6", PU_HUDGFX); emeraldpics[1][6] = W_CachePatchName("TEMER7", PU_HUDGFX); + //emeraldpics[1][7] = W_CachePatchName("TEMER8", PU_HUDGFX); -- unused emeraldpics[2][0] = W_CachePatchName("EMBOX1", PU_HUDGFX); emeraldpics[2][1] = W_CachePatchName("EMBOX2", PU_HUDGFX); @@ -272,6 +274,7 @@ void HU_LoadGraphics(void) emeraldpics[2][4] = W_CachePatchName("EMBOX5", PU_HUDGFX); emeraldpics[2][5] = W_CachePatchName("EMBOX6", PU_HUDGFX); emeraldpics[2][6] = W_CachePatchName("EMBOX7", PU_HUDGFX); + //emeraldpics[2][7] = W_CachePatchName("EMBOX8", PU_HUDGFX); -- unused } // Initialise Heads up diff --git a/src/hu_stuff.h b/src/hu_stuff.h index fb1fa1817..46c47b59e 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -63,7 +63,7 @@ extern patch_t *tallnum[10]; extern patch_t *nightsnum[10]; extern patch_t *lt_font[LT_FONTSIZE]; extern patch_t *cred_font[CRED_FONTSIZE]; -extern patch_t *emeraldpics[3][7]; +extern patch_t *emeraldpics[3][8]; extern patch_t *rflagico; extern patch_t *bflagico; extern patch_t *rmatcico; diff --git a/src/info.c b/src/info.c index e791c7728..f02fba8d2 100644 --- a/src/info.c +++ b/src/info.c @@ -118,10 +118,12 @@ char sprnames[NUMSPRITES + 1][5] = "TOKE", // Special Stage Token "RFLG", // Red CTF Flag "BFLG", // Blue CTF Flag - "NWNG", // NiGHTS Wing collectable item. + "SPHR", // Sphere + "NCHP", // NiGHTS chip + "NSTR", // NiGHTS star "EMBM", // Emblem "CEMG", // Chaos Emeralds - "EMER", // Emerald Hunt + "SHRD", // Emerald hunt shards // Interactive Objects "BBLS", // water bubble source @@ -187,6 +189,7 @@ char sprnames[NUMSPRITES + 1][5] = "TRE3", // Frozen Hillside "TRE4", // Polygon "TRE5", // Bush tree + "TRE6", // Spring tree // Techno Hill Scenery "THZP", // THZ1 Steam Flower @@ -392,6 +395,9 @@ char sprnames[NUMSPRITES + 1][5] = "NSCR", // NiGHTS score sprite "NPRU", // Nights Powerups "CAPS", // Capsule thingy for NiGHTS + "IDYA", // Ideya + "NTPN", // Nightopian + "SHLP", // Shleep // Secret badniks and hazards, shhhh "HIVE", @@ -432,9 +438,6 @@ char sprnames[NUMSPRITES + 1][5] = "ROIO", "ROIP", - // Blue Spheres - "BBAL", - // Gravity Well Objects "GWLG", "GWLR", @@ -715,7 +718,7 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_SUPER_TRANS4}, // S_PLAY_SUPER_TRANS3 {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_SUPER_TRANS5}, // S_PLAY_SUPER_TRANS4 {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_SUPER_TRANS6}, // S_PLAY_SUPER_TRANS5 - {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 20, {A_FadeOverlay}, 0, 0, S_PLAY_FALL}, // S_PLAY_SUPER_TRANS6 + {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 20, {A_FadeOverlay}, 0, 0, S_PLAY_FLOAT}, // S_PLAY_SUPER_TRANS6 {SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY @@ -1021,7 +1024,8 @@ state_t states[NUMSTATES] = {SPR_SPSH, 10, 1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN4}, // S_EGGGUARD_RUN3 {SPR_SPSH, 11, 1, {A_GuardChase}, 0, 0, S_EGGGUARD_RUN1}, // S_EGGGUARD_RUN4 - {SPR_ESHI, 0, 8, {A_EggShield}, 0, 0, S_EGGSHIELD}, // S_EGGSHIELD + {SPR_ESHI, 0, 8, {A_EggShield}, 0, 0, S_EGGSHIELD}, // S_EGGSHIELD + {SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_EGGSHIELDBREAK // Green Snapper {SPR_GSNP, 0, 1, {A_Look}, 0, 0, S_GSNAPPER_STND}, // S_GSNAPPER_STND @@ -1591,18 +1595,22 @@ state_t states[NUMSTATES] = // Ring {SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING}, // S_RING - // Blue Sphere Replacement for special stages - {SPR_BBAL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEBALL - {SPR_BBAL, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUEBALLSPARK + // Blue Sphere for special stages + {SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE + {SPR_SPHR, FF_FULLBRIGHT|FF_RANDOMANIM|FF_ANIMATE, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS + {SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK + + // NiGHTS Chip + {SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIP + {SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIPBONUS + + // NiGHTS Star + {SPR_NSTR, FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_NIGHTSSTAR + {SPR_NSTR, 15, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSSTARXMAS // Gravity Well sprites for Egg Rock's Special Stage - {SPR_GWLG, 0, 1, {NULL}, 0, 0, S_GRAVWELLGREEN2}, // S_GRAVWELLGREEN - {SPR_GWLG, 1, 1, {NULL}, 0, 0, S_GRAVWELLGREEN3}, // S_GRAVWELLGREEN2 - {SPR_GWLG, 2, 1, {NULL}, 0, 0, S_GRAVWELLGREEN}, // S_GRAVWELLGREEN3 - - {SPR_GWLR, 0, 1, {NULL}, 0, 0, S_GRAVWELLRED2}, // S_GRAVWELLRED - {SPR_GWLR, 1, 1, {NULL}, 0, 0, S_GRAVWELLRED3}, // S_GRAVWELLRED2 - {SPR_GWLR, 2, 1, {NULL}, 0, 0, S_GRAVWELLRED}, // S_GRAVWELLRED3 + {SPR_GWLG, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_GRAVWELLGREEN + {SPR_GWLR, FF_ANIMATE, -1, {NULL}, 2, 1, S_NULL}, // S_GRAVWELLRED // Individual Team Rings (now with shield attracting action! =P) {SPR_TRNG, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_TEAMRING}, // S_TEAMRING @@ -1651,8 +1659,10 @@ state_t states[NUMSTATES] = {SPR_CEMG, FF_FULLBRIGHT|5, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG6 {SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG7 - // Emeralds (for hunt) - {SPR_EMER, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EMER1 + // Emerald hunt shards + {SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1 + {SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD2 + {SPR_SHRD, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD3 // Bubble Source {SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2}, // S_BUBBLES1 @@ -1934,7 +1944,6 @@ state_t states[NUMSTATES] = {SPR_CBLL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANNONBALL1 {SPR_AROW, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ARROW - {SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_TEMPSHI {SPR_AROW, FF_ANIMATE, TICRATE, {A_ArrowBonks}, 7, 2, S_NULL}, // S_ARROWBONK {SPR_CFIR, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DEMONFIRE2}, // S_DEMONFIRE1 @@ -1963,6 +1972,7 @@ state_t states[NUMSTATES] = {SPR_TRE4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_POLYGONTREE {SPR_TRE5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHTREE {SPR_TRE5, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BUSHREDTREE + {SPR_TRE6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPRINGTREE // THZ flowers {SPR_THZP, FF_ANIMATE, -1, {NULL}, 7, 4, S_NULL}, // S_THZFLOWERA @@ -3301,9 +3311,6 @@ state_t states[NUMSTATES] = {SPR_NSCR, FF_FULLBRIGHT|18, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE90_2 {SPR_NSCR, FF_FULLBRIGHT|19, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSCORE100_2 - {SPR_NWNG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSWING - {SPR_NWNG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSWING_XMAS - // NiGHTS Paraloop Powerups {SPR_NPRU, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSSUPERLOOP {SPR_NPRU, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSDRILLREFILL @@ -3313,7 +3320,7 @@ state_t states[NUMSTATES] = {SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGCAPSULE - // Orbiting Chaos Emeralds for NiGHTS + // Orbiting Chaos Emeralds/Ideya for NiGHTS {SPR_CEMG, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1}, // S_ORBITEM1 {SPR_CEMG, FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2 {SPR_CEMG, FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3 @@ -3322,14 +3329,11 @@ state_t states[NUMSTATES] = {SPR_CEMG, FF_FULLBRIGHT|5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6 {SPR_CEMG, FF_FULLBRIGHT|6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7 {SPR_CEMG, FF_FULLBRIGHT|7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8 - {SPR_CEMG, FF_FULLBRIGHT|8, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM9 - {SPR_CEMG, FF_FULLBRIGHT|9, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM10 - {SPR_CEMG, FF_FULLBRIGHT|10, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM11 - {SPR_CEMG, FF_FULLBRIGHT|11, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM12 - {SPR_CEMG, FF_FULLBRIGHT|12, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM13 - {SPR_CEMG, FF_FULLBRIGHT|13, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM14 - {SPR_CEMG, FF_FULLBRIGHT|14, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM15 - {SPR_CEMG, FF_FULLBRIGHT|15, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM16 + {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA1}, // S_ORBIDYA1 + {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA2}, // S_ORBIDYA2 + {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA3}, // S_ORBIDYA3 + {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA4}, // S_ORBIDYA4 + {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA5}, // S_ORBIDYA5 // Flicky helper for NiGHTS {SPR_FL01, 1, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER2}, // S_NIGHTOPIANHELPER1 @@ -3342,6 +3346,25 @@ state_t states[NUMSTATES] = {SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER9}, // S_NIGHTOPIANHELPER8 {SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1}, // S_NIGHTOPIANHELPER9 + // Nightopian + {SPR_NTPN, 0, 4, {A_Look}, 0, 0, S_PIAN0}, // S_PIAN0 + {SPR_NTPN, 0, 4, {A_JetgThink}, 0, 0, S_PIAN2}, // S_PIAN1 + {SPR_NTPN, 1, 4, {NULL}, 0, 0, S_PIAN3}, // S_PIAN2 + {SPR_NTPN, 2, 4, {NULL}, 0, 0, S_PIAN4}, // S_PIAN3 + {SPR_NTPN, 3, 4, {NULL}, 0, 0, S_PIAN5}, // S_PIAN4 + {SPR_NTPN, 2, 4, {NULL}, 0, 0, S_PIAN6}, // S_PIAN5 + {SPR_NTPN, 1, 4, {NULL}, 0, 0, S_PIAN1}, // S_PIAN6 + {SPR_NTPN, 5|FF_ANIMATE, 4, {NULL}, 1, 4, S_PIAN1}, // S_PIANSING + + // Shleep + {SPR_SHLP, 0, 15, {NULL}, 0, 0, S_SHLEEP2}, // S_SHLEEP1 + {SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP3}, // S_SHLEEP2 + {SPR_SHLP, 2, 15, {NULL}, 0, 0, S_SHLEEP4}, // S_SHLEEP3 + {SPR_SHLP, 1, 15, {NULL}, 0, 0, S_SHLEEP1}, // S_SHLEEP4 + {SPR_SHLP, 3, 1, {A_Scream}, 0, 0, S_SHLEEPBOUNCE2}, // S_SHLEEPBOUNCE1 + {SPR_SHLP, 3, 1, {A_ZThrust}, 9, 0, S_SHLEEPBOUNCE3}, // S_SHLEEPBOUNCE2 + {SPR_SHLP, 3, 400, {A_SetObjectFlags}, MF_SLIDEME|MF_ENEMY|MF_BOUNCE|MF_NOCLIP|MF_NOCLIPHEIGHT, 0, S_NULL}, // S_SHLEEPBOUNCE3 + // Secret badniks and hazards, shhhh {SPR_HIVE, 0, 5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK {SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1 @@ -4337,7 +4360,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_s3k7b, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_TEMPSHI, // deathstate + S_EGGSHIELDBREAK,// deathstate S_NULL, // xdeathstate sfx_wbreak, // deathsound 3, // speed @@ -5729,9 +5752,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_BLUEBALL - -1, // doomednum - S_BLUEBALL, // spawnstate + { // MT_BLUESPHERE + 1706, // doomednum + S_BLUESPHERE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -5742,7 +5765,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_BLUEBALLSPARK, // deathstate + S_BLUESPHERESPARK, // deathstate S_NULL, // xdeathstate sfx_s3k65, // deathsound 38*FRACUNIT, // speed @@ -5753,7 +5776,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // damage sfx_None, // activesound MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags - S_NULL // raisestate + S_BLUESPHEREBONUS // raisestate }, { // MT_REDTEAMRING @@ -5825,7 +5848,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // missilestate S_SPRK1, // deathstate S_NULL, // xdeathstate - sfx_token, // deathsound + sfx_None, // deathsound 0, // speed 8*FRACUNIT, // radius 16*FRACUNIT, // height @@ -6103,7 +6126,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_EMERHUNT 320, // doomednum - S_EMER1, // spawnstate + S_SHRD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -6118,8 +6141,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_cgot, // deathsound 8, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 12*FRACUNIT, // radius + 42*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage @@ -6588,7 +6611,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SPIKEBALL - -1, // doomednum + 521, // doomednum S_SPIKEBALL1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -6604,7 +6627,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 10*FRACUNIT, // speed - 4*FRACUNIT, // radius + 12*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset DMG_SPIKE, // mass @@ -8803,7 +8826,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_GFZTREE 806, // doomednum - S_GFZTREE, // spawnstate + S_GFZTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8830,7 +8853,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_GFZBERRYTREE 807, // doomednum - S_GFZBERRYTREE, // spawnstate + S_GFZBERRYTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8857,7 +8880,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_GFZCHERRYTREE 808, // doomednum - S_GFZCHERRYTREE, // spawnstate + S_GFZCHERRYTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8884,7 +8907,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_CHECKERTREE 810, // doomednum - S_CHECKERTREE, // spawnstate + S_CHECKERTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8911,7 +8934,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_CHECKERSUNSETTREE 811, // doomednum - S_CHECKERSUNSETTREE, // spawnstate + S_CHECKERSUNSETTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8938,7 +8961,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FHZTREE 812, // doomednum - S_FHZTREE, // spawnstate + S_FHZTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8965,7 +8988,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FHZPINKTREE 813, // doomednum - S_FHZPINKTREE, // spawnstate + S_FHZPINKTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8992,7 +9015,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_POLYGONTREE 814, // doomednum - S_POLYGONTREE, // spawnstate + S_POLYGONTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -9019,7 +9042,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_BUSHTREE 815, // doomednum - S_BUSHTREE, // spawnstate + S_BUSHTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -9046,7 +9069,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_BUSHREDTREE 816, // doomednum - S_BUSHREDTREE, // spawnstate + S_BUSHREDTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -9071,6 +9094,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SPRINGTREE + 1600, // doomednum + S_SPRINGTREE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_THZFLOWER1 900, // doomednum S_THZFLOWERA, // spawnstate @@ -14406,7 +14456,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // painchance sfx_None, // painsound S_ORBITEM1, // meleestate - S_NULL, // missilestate + S_ORBIDYA1, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound @@ -16131,11 +16181,11 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_NIGHTSWING - 1706, // doomednum - S_NIGHTSWING, // spawnstate + { // MT_NIGHTSCHIP + -1, // doomednum + S_NIGHTSCHIP, // spawnstate 1000, // spawnhealth - S_NIGHTSWING_XMAS, // seestate + S_NULL, // seestate sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound @@ -16146,14 +16196,41 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // missilestate S_SPRK1, // deathstate S_NULL, // xdeathstate - sfx_None, // deathsound + sfx_ncchip, // deathsound 1, // speed - 12*FRACUNIT, // radius + 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage - sfx_ncitem, // activesound + sfx_None, // activesound + MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NIGHTSCHIPBONUS // raisestate + }, + + { // MT_NIGHTSSTAR + -1, // doomednum + S_NIGHTSSTAR, // spawnstate + 1000, // spawnhealth + S_NIGHTSSTARXMAS, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_s3k33, // painsound + S_RING, // meleestate + S_NULL, // missilestate + S_SPRK1, // deathstate + S_NULL, // xdeathstate + sfx_ncitem, // deathsound + 1, // speed + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -16320,7 +16397,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - // the flicky that orbits the player when they have a Nightopian helper { // MT_NIGHTOPIANHELPER -1, // doomednum S_NIGHTOPIANHELPER1, // spawnstate @@ -16348,6 +16424,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_PIAN + 1602, // doomednum + S_PIAN0, // spawnstate + 1000, // spawnhealth + S_PIAN1, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_PIANSING, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + FRACUNIT, // speed + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SHLEEP + 1601, // doomednum + S_SHLEEP1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_SHLEEPBOUNCE1, // deathstate + S_NULL, // xdeathstate + sfx_peww, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_HIVEELEMENTAL 3190, // doomednum S_HIVEELEMENTAL_LOOK, // spawnstate diff --git a/src/info.h b/src/info.h index 5f84b22d4..4e316efdb 100644 --- a/src/info.h +++ b/src/info.h @@ -337,10 +337,12 @@ typedef enum sprite SPR_TOKE, // Special Stage Token SPR_RFLG, // Red CTF Flag SPR_BFLG, // Blue CTF Flag - SPR_NWNG, // NiGHTS Wing collectable item. + SPR_SPHR, // Sphere + SPR_NCHP, // NiGHTS chip + SPR_NSTR, // NiGHTS star SPR_EMBM, // Emblem SPR_CEMG, // Chaos Emeralds - SPR_EMER, // Emerald Hunt + SPR_SHRD, // Emerald Hunt // Interactive Objects SPR_BBLS, // water bubble source @@ -406,6 +408,7 @@ typedef enum sprite SPR_TRE3, // Frozen Hillside SPR_TRE4, // Polygon SPR_TRE5, // Bush tree + SPR_TRE6, // Spring tree // Techno Hill Scenery SPR_THZP, // THZ1 Steam Flower @@ -611,6 +614,9 @@ typedef enum sprite SPR_NSCR, // NiGHTS score sprite SPR_NPRU, // Nights Powerups SPR_CAPS, // Capsule thingy for NiGHTS + SPR_IDYA, // Ideya + SPR_NTPN, // Nightopian + SPR_SHLP, // Shleep // Secret badniks and hazards, shhhh SPR_HIVE, @@ -651,9 +657,6 @@ typedef enum sprite SPR_ROIO, SPR_ROIP, - // Blue Spheres - SPR_BBAL, - // Gravity Well Objects SPR_GWLG, SPR_GWLR, @@ -1149,6 +1152,7 @@ typedef enum state // Egg Shield for Egg Guard S_EGGSHIELD, + S_EGGSHIELDBREAK, // Green Snapper S_GSNAPPER_STND, @@ -1717,17 +1721,21 @@ typedef enum state S_RING, // Blue Sphere for special stages - S_BLUEBALL, - S_BLUEBALLSPARK, + S_BLUESPHERE, + S_BLUESPHEREBONUS, + S_BLUESPHERESPARK, + + // NiGHTS Chip + S_NIGHTSCHIP, + S_NIGHTSCHIPBONUS, + + // NiGHTS Star + S_NIGHTSSTAR, + S_NIGHTSSTARXMAS, // Gravity Wells for special stages S_GRAVWELLGREEN, - S_GRAVWELLGREEN2, - S_GRAVWELLGREEN3, - S_GRAVWELLRED, - S_GRAVWELLRED2, - S_GRAVWELLRED3, // Individual Team Rings S_TEAMRING, @@ -1776,8 +1784,10 @@ typedef enum state S_CEMG6, S_CEMG7, - // Emeralds (for hunt) - S_EMER1, + // Emerald hunt shards + S_SHRD1, + S_SHRD2, + S_SHRD3, // Bubble Source S_BUBBLES1, @@ -2061,7 +2071,6 @@ typedef enum state // Arrow S_ARROW, - S_TEMPSHI, S_ARROWBONK, // Trapgoyle Demon fire @@ -2091,6 +2100,7 @@ typedef enum state S_POLYGONTREE, S_BUSHTREE, S_BUSHREDTREE, + S_SPRINGTREE, // THZ flowers S_THZFLOWERA, // THZ1 Steam flower @@ -3359,9 +3369,6 @@ typedef enum state S_NIGHTSCORE90_2, S_NIGHTSCORE100_2, - S_NIGHTSWING, - S_NIGHTSWING_XMAS, - // NiGHTS Paraloop Powerups S_NIGHTSSUPERLOOP, S_NIGHTSDRILLREFILL, @@ -3379,14 +3386,11 @@ typedef enum state S_ORBITEM6, S_ORBITEM7, S_ORBITEM8, - S_ORBITEM9, - S_ORBITEM10, - S_ORBITEM11, - S_ORBITEM12, - S_ORBITEM13, - S_ORBITEM14, - S_ORBITEM15, - S_ORBITEM16, + S_ORBIDYA1, + S_ORBIDYA2, + S_ORBIDYA3, + S_ORBIDYA4, + S_ORBIDYA5, // "Flicky" helper S_NIGHTOPIANHELPER1, @@ -3399,6 +3403,25 @@ typedef enum state S_NIGHTOPIANHELPER8, S_NIGHTOPIANHELPER9, + // Nightopian + S_PIAN0, + S_PIAN1, + S_PIAN2, + S_PIAN3, + S_PIAN4, + S_PIAN5, + S_PIAN6, + S_PIANSING, + + // Shleep + S_SHLEEP1, + S_SHLEEP2, + S_SHLEEP3, + S_SHLEEP4, + S_SHLEEPBOUNCE1, + S_SHLEEPBOUNCE2, + S_SHLEEPBOUNCE3, + // Secret badniks and hazards, shhhh S_HIVEELEMENTAL_LOOK, S_HIVEELEMENTAL_PREPARE1, @@ -3694,7 +3717,7 @@ typedef enum mobj_type // Collectible Items MT_RING, MT_FLINGRING, // Lost ring - MT_BLUEBALL, // Blue sphere replacement for special stages + MT_BLUESPHERE, // Blue sphere replacement for special stages MT_REDTEAMRING, //Rings collectable by red team. MT_BLUETEAMRING, //Rings collectable by blue team. MT_TOKEN, // Special Stage token for special stage @@ -3838,6 +3861,7 @@ typedef enum mobj_type MT_POLYGONTREE, MT_BUSHTREE, MT_BUSHREDTREE, + MT_SPRINGTREE, // Techno Hill Scenery MT_THZFLOWER1, @@ -4150,7 +4174,8 @@ typedef enum mobj_type MT_HOOPCOLLIDE, // Collision detection for NiGHTS hoops MT_HOOPCENTER, // Center of a hoop MT_NIGHTSCORE, - MT_NIGHTSWING, + MT_NIGHTSCHIP, // NiGHTS Chip + MT_NIGHTSSTAR, // NiGHTS Star MT_NIGHTSSUPERLOOP, MT_NIGHTSDRILLREFILL, MT_NIGHTSHELPER, @@ -4158,6 +4183,8 @@ typedef enum mobj_type MT_NIGHTSLINKFREEZE, MT_EGGCAPSULE, MT_NIGHTOPIANHELPER, // the actual helper object that orbits you + MT_PIAN, // decorative singing friend + MT_SHLEEP, // almost-decorative sleeping enemy // Secret badniks and hazards, shhhh MT_HIVEELEMENTAL, diff --git a/src/lua_hud.h b/src/lua_hud.h index beaca7883..c1479d5ef 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -24,7 +24,7 @@ enum hud { // NiGHTS mode hud_nightslink, hud_nightsdrill, - hud_nightsrings, + hud_nightsspheres, hud_nightsscore, hud_nightstime, hud_nightsrecords, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 12b2646d0..8a1079c36 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -130,6 +130,8 @@ static int player_get(lua_State *L) lua_pushangle(L, plr->drawangle); else if (fastcmp(field,"rings")) lua_pushinteger(L, plr->rings); + else if (fastcmp(field,"spheres")) + lua_pushinteger(L, plr->spheres); else if (fastcmp(field,"pity")) lua_pushinteger(L, plr->pity); else if (fastcmp(field,"currentweapon")) @@ -294,8 +296,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->startedtime); else if (fastcmp(field,"finishedtime")) lua_pushinteger(L, plr->finishedtime); - else if (fastcmp(field,"finishedrings")) - lua_pushinteger(L, plr->finishedrings); + else if (fastcmp(field,"finishedspheres")) + lua_pushinteger(L, plr->finishedspheres); else if (fastcmp(field,"marescore")) lua_pushinteger(L, plr->marescore); else if (fastcmp(field,"lastmarescore")) @@ -396,6 +398,8 @@ static int player_set(lua_State *L) plr->drawangle = luaL_checkangle(L, 3); else if (fastcmp(field,"rings")) plr->rings = (INT32)luaL_checkinteger(L, 3); + else if (fastcmp(field,"spheres")) + plr->spheres = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"pity")) plr->pity = (SINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"currentweapon")) @@ -448,7 +452,7 @@ static int player_set(lua_State *L) else if (fastcmp(field,"followitem")) plr->followitem = luaL_checkinteger(L, 3); else if (fastcmp(field,"followmobj")) - plr->followmobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); + P_SetTarget(&plr->followmobj, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ))); else if (fastcmp(field,"actionspd")) plr->actionspd = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"mindash")) @@ -570,8 +574,8 @@ static int player_set(lua_State *L) plr->startedtime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"finishedtime")) plr->finishedtime = (tic_t)luaL_checkinteger(L, 3); - else if (fastcmp(field,"finishedrings")) - plr->finishedrings = (INT16)luaL_checkinteger(L, 3); + else if (fastcmp(field,"finishedspheres")) + plr->finishedspheres = (INT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"marescore")) plr->marescore = (UINT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"lastmarescore")) diff --git a/src/m_cheat.c b/src/m_cheat.c index 174e2780d..81a8702fd 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -728,7 +728,7 @@ void Command_Setrings_f(void) // P_GivePlayerRings does value clamping players[consoleplayer].rings = 0; P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1))); - if (!G_IsSpecialStage(gamemap) || !useNightsSS) + if (!G_IsSpecialStage(gamemap) || !(maptol & TOL_NIGHTS)) players[consoleplayer].totalring -= atoi(COM_Argv(1)); //undo totalring addition done in P_GivePlayerRings G_SetGameModified(multiplayer); @@ -1010,7 +1010,7 @@ void OP_NightsObjectplace(player_t *player) mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS); mt->angle = (INT16)(mt->angle+(INT16)((FixedInt(FixedDiv(temp*FRACUNIT, 360*(FRACUNIT/256))))<<8)); - P_SpawnHoopsAndRings(mt); + P_SpawnHoopsAndRings(mt, false); } // This places a bumper! @@ -1024,26 +1024,26 @@ void OP_NightsObjectplace(player_t *player) P_SpawnMapThing(mt); } - // This places a ring! + // This places a sphere! if (cmd->buttons & BT_WEAPONNEXT) { player->pflags |= PF_ATTACKDOWN; if (!OP_HeightOkay(player, false)) return; - mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_RING].doomednum, false); - P_SpawnHoopsAndRings(mt); + mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_BLUESPHERE].doomednum, false); + P_SpawnHoopsAndRings(mt, false); } - // This places a wing item! + // This places a ring! if (cmd->buttons & BT_WEAPONPREV) { player->pflags |= PF_ATTACKDOWN; if (!OP_HeightOkay(player, false)) return; - mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_NIGHTSWING].doomednum, false); - P_SpawnHoopsAndRings(mt); + mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_RING].doomednum, false); + P_SpawnHoopsAndRings(mt, false); } // This places a custom object as defined in the console cv_mapthingnum. @@ -1077,12 +1077,12 @@ void OP_NightsObjectplace(player_t *player) if (mt->type == 300 // Ring || mt->type == 308 || mt->type == 309 // Team Rings - || mt->type == 1706 // Nights Wing + || mt->type == 1706 // Sphere || (mt->type >= 600 && mt->type <= 609) // Placement patterns || mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops || mt->type == 1800) // Mario Coin { - P_SpawnHoopsAndRings(mt); + P_SpawnHoopsAndRings(mt, false); } else P_SpawnMapThing(mt); @@ -1227,7 +1227,7 @@ void OP_ObjectplaceMovement(player_t *player) || mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops || mt->type == 1800) // Mario Coin { - P_SpawnHoopsAndRings(mt); + P_SpawnHoopsAndRings(mt, false); } else P_SpawnMapThing(mt); diff --git a/src/p_enemy.c b/src/p_enemy.c index 2c55210b7..2f1fa842e 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -8604,10 +8604,12 @@ void A_OrbitNights(mobj_t* actor) return; #endif - if (!actor->target || !actor->target->player || - !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE) || !actor->target->player->nightstime + if (!actor->target + || (actor->target->player && + // if NiGHTS special stage and not NiGHTSmode. + (((maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && !(actor->target->player->powers[pw_carry] == CR_NIGHTSMODE)) // Also remove this object if they no longer have a NiGHTS helper - || (ishelper && !actor->target->player->powers[pw_nights_helper])) + || (ishelper && !actor->target->player->powers[pw_nights_helper])))) { P_RemoveMobj(actor); return; @@ -8633,7 +8635,7 @@ void A_OrbitNights(mobj_t* actor) } P_SetThingPosition(actor); - if (ishelper) // Flash a helper that's about to be removed. + if (ishelper && actor->target->player) // Flash a helper that's about to be removed. { if ((actor->target->player->powers[pw_nights_helper] < TICRATE) && (actor->target->player->powers[pw_nights_helper] & 1)) @@ -11185,7 +11187,7 @@ void A_FlameParticle(mobj_t *actor) // // Description: Makes a pretty overlay (primarily for super/NiGHTS transformation). // -// var1 = bit 1 = don't halt momentum, bit 2 = don't make fast, bit 3 = don't set tracer +// var1 = bit 1 = bit 1 = don't make fast, bit 2 = don't set tracer // var2 = unused // void A_FadeOverlay(mobj_t *actor) @@ -11199,13 +11201,10 @@ void A_FadeOverlay(mobj_t *actor) return; #endif - if (!(locvar1 & 1)) - actor->momx = actor->momy = actor->momz = 0; - fade = P_SpawnGhostMobj(actor); fade->frame = actor->frame; - if (!(locvar1 & 2)) + if (!(locvar1 & 1)) { fade->fuse = 15; fade->flags2 |= MF2_BOSSNOTRAP; @@ -11213,7 +11212,7 @@ void A_FadeOverlay(mobj_t *actor) else fade->fuse = 20; - if (!(locvar1 & 4)) + if (!(locvar1 & 2)) P_SetTarget(&actor->tracer, fade); } diff --git a/src/p_inter.c b/src/p_inter.c index fed459d6a..33a5abcd2 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -23,6 +23,7 @@ #include "hu_stuff.h" #include "lua_hook.h" #include "m_cond.h" // unlockables, emblems, etc +#include "p_setup.h" #include "m_cheat.h" // objectplace #include "m_misc.h" #include "v_video.h" // video flags for CEchos @@ -471,40 +472,49 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) /* FALLTHRU */ case MT_RING: case MT_FLINGRING: - if (!(P_CanPickupItem(player, false))) - return; - - special->momx = special->momy = special->momz = 0; - P_GivePlayerRings(player, 1); - - if ((maptol & TOL_NIGHTS) && special->type != MT_FLINGRING) - P_DoNightsScore(player); - break; - case MT_COIN: case MT_FLINGCOIN: if (!(P_CanPickupItem(player, false))) return; - special->momx = special->momy = 0; + special->momx = special->momy = special->momz = 0; P_GivePlayerRings(player, 1); - if ((maptol & TOL_NIGHTS) && special->type != MT_FLINGCOIN) + if ((maptol & TOL_NIGHTS) && special->type != MT_FLINGRING && special->type != MT_FLINGCOIN) P_DoNightsScore(player); break; - case MT_BLUEBALL: + case MT_BLUESPHERE: if (!(P_CanPickupItem(player, false))) return; - P_GivePlayerRings(player, 1); - special->momx = special->momy = special->momz = 0; - special->destscale = FixedMul(8*FRACUNIT, special->scale); + P_GivePlayerSpheres(player, 1); + + special->destscale = ((player->powers[pw_carry] == CR_NIGHTSMODE) ? 4 : 2)*special->scale; if (states[special->info->deathstate].tics > 0) special->scalespeed = FixedDiv(FixedDiv(special->destscale, special->scale), states[special->info->deathstate].tics<scalespeed = 4*FRACUNIT/5; + if (maptol & TOL_NIGHTS) + P_DoNightsScore(player); + break; + case MT_NIGHTSCHIP: + if (!(P_CanPickupItem(player, false))) + return; + + special->momx = special->momy = special->momz = 0; + P_GivePlayerSpheres(player, 1); + + if (maptol & TOL_NIGHTS) + P_DoNightsScore(player); + break; + case MT_NIGHTSSTAR: + if (!(P_CanPickupItem(player, false))) + return; + + special->momx = special->momy = special->momz = 0; + if (maptol & TOL_NIGHTS) P_DoNightsScore(player); break; @@ -562,7 +572,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_AddPlayerScore(player, 1000); if (gametype != GT_COOP || modeattacking) // score only? + { + S_StartSound(toucher, sfx_chchng); break; + } tokenlist += special->health; @@ -574,10 +587,17 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) players->gotcontinue = true; if (P_IsLocalPlayer(player)) S_StartSound(NULL, sfx_s3kac); + else + S_StartSound(toucher, sfx_chchng); } + else + S_StartSound(toucher, sfx_chchng); } else + { token++; + S_StartSound(toucher, sfx_token); + } break; @@ -602,7 +622,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) players[i].exiting = (14*TICRATE)/5 + 1; } - S_StartSound(NULL, sfx_lvpass); + //S_StartSound(NULL, sfx_lvpass); } break; @@ -733,45 +753,71 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // NiGHTS gameplay items and powerups // // ********************************** // case MT_NIGHTSDRONE: - if (player->bot) - return; - if (player->exiting) - return; - if (player->bonustime) { - if (G_IsSpecialStage(gamemap)) //After-mare bonus time/emerald reward in special stages. - { - // only allow the player with the emerald in-hand to leave. - if (toucher->tracer - && toucher->tracer->type == MT_GOTEMERALD) - { - } - else // Make sure that SOMEONE has the emerald, at least! - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].playerstate == PST_LIVE - && players[i].mo->tracer - && players[i].mo->tracer->type == MT_GOTEMERALD) - return; - // Well no one has an emerald, so exit anyway! - } - P_GiveEmerald(false); - // Don't play Ideya sound in special stage mode - } - else - S_StartSound(toucher, special->info->activesound); - } - else //Initial transformation. Don't allow second chances in special stages! - { - if (player->powers[pw_carry] == CR_NIGHTSMODE) + boolean spec = G_IsSpecialStage(gamemap); + if (player->bot) return; + if (player->exiting) + return; + if (player->bonustime) + { + if (spec) //After-mare bonus time/emerald reward in special stages. + { + // only allow the player with the emerald in-hand to leave. + if (toucher->tracer + && toucher->tracer->type == MT_GOTEMERALD) + {} + else // Make sure that SOMEONE has the emerald, at least! + { + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].playerstate == PST_LIVE + && players[i].mo->tracer + && players[i].mo->tracer->type == MT_GOTEMERALD) + return; + // Well no one has an emerald, so exit anyway! + } + P_GiveEmerald(false); + // Don't play Ideya sound in special stage mode + } + else + S_StartSound(toucher, special->info->activesound); + } + else //Initial transformation. Don't allow second chances in special stages! + { + if (player->powers[pw_carry] == CR_NIGHTSMODE) + return; - S_StartSound(toucher, sfx_supert); + S_StartSound(toucher, sfx_supert); + } + P_SwitchSpheresBonusMode(false); + if (!(netgame || multiplayer) && !(player->powers[pw_carry] == CR_NIGHTSMODE)) + P_SetTarget(&special->tracer, toucher); + P_NightserizePlayer(player, special->health); // Transform! + if (!spec) + { + if (toucher->tracer) // Move the ideya over to the drone! + { + mobj_t *hnext = special->hnext; + P_SetTarget(&special->hnext, toucher->tracer); + P_SetTarget(&special->hnext->hnext, hnext); // Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo. + P_SetTarget(&special->hnext->target, special); + P_SetTarget(&toucher->tracer, NULL); + if (hnext) + { + special->hnext->extravalue1 = (angle_t)(hnext->extravalue1 - 72*ANG1); + if (special->hnext->extravalue1 > hnext->extravalue1) + special->hnext->extravalue1 -= (72*ANG1)/special->hnext->extravalue1; + } + } + if (player->exiting) // ...then move it back? + { + mobj_t *hnext = special; + while ((hnext = hnext->hnext)) + P_SetTarget(&hnext->target, toucher); + } + } + return; } - if (!(netgame || multiplayer) && !(player->powers[pw_carry] == CR_NIGHTSMODE)) - P_SetTarget(&special->tracer, toucher); - P_NightserizePlayer(player, special->health); // Transform! - return; case MT_NIGHTSLOOPHELPER: // One second delay if (special->fuse < toucher->fuse - TICRATE) @@ -876,8 +922,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } } - if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN - || mo2->type == MT_BLUEBALL + if (!(mo2->type == MT_RING || mo2->type == MT_COIN || mo2->type == MT_BLUESPHERE + || mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR || ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL)))) continue; @@ -903,16 +949,16 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; if (G_IsSpecialStage(gamemap) && !player->exiting) - { // In special stages, share rings. Everyone gives up theirs to the player who touched the capsule + { // In special stages, share spheres. Everyone gives up theirs to the player who touched the capsule for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (&players[i] != player) && players[i].rings > 0) + if (playeringame[i] && (&players[i] != player) && players[i].spheres > 0) { - player->rings += players[i].rings; - players[i].rings = 0; + player->spheres += players[i].spheres; + players[i].spheres = 0; } } - if (player->rings <= 0 || player->exiting) + if (player->spheres <= 0 || player->exiting) return; // Mark the player as 'pull into the capsule' @@ -1120,17 +1166,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) HU_DoCEcho(M_GetText("\\\\\\\\\\\\\\\\Link Freeze")); } break; - case MT_NIGHTSWING: - if (G_IsSpecialStage(gamemap) && useNightsSS) - { // Pseudo-ring. - S_StartSound(toucher, special->info->painsound); - player->totalring++; - } - else - S_StartSound(toucher, special->info->activesound); - - P_DoNightsScore(player); - break; case MT_HOOPCOLLIDE: // This produces a kind of 'domino effect' with the hoop's pieces. for (; special->hprev != NULL; special = special->hprev); // Move to the first sprite in the hoop @@ -1496,12 +1531,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->pflags |= PF_JUMPSTASIS; return; - case MT_SPECIALSPIKEBALL: - if (!useNightsSS && G_IsSpecialStage(gamemap)) // Only for old special stages - P_SpecialStageDamage(player, special, NULL); - else - P_DamageMobj(toucher, special, special, 1, 0); - return; case MT_EGGMOBILE2_POGO: // sanity checks if (!special->target || !special->target->health) @@ -2070,8 +2099,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL)) P_SetTarget(&target->tracer, inflictor); - if (!useNightsSS && G_IsSpecialStage(gamemap) && target->player && sstimer > 6) - sstimer = 6; // Just let P_Ticker take care of the rest. + if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && target->player && target->player->nightstime > 6) + target->player->nightstime = 6; // Just let P_Ticker take care of the rest. if (target->flags & (MF_ENEMY|MF_BOSS)) target->momx = target->momy = target->momz = 0; @@ -2633,20 +2662,10 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source) player->drillmeter -= 5*20; else { - if (source && source->player) - { - if (player->nightstime > 20*TICRATE) - player->nightstime -= 20*TICRATE; - else - player->nightstime = 1; - } + if (player->nightstime > 5*TICRATE) + player->nightstime -= 5*TICRATE; else - { - if (player->nightstime > 5*TICRATE) - player->nightstime -= 5*TICRATE; - else - player->nightstime = 1; - } + player->nightstime = 1; } if (player->pflags & PF_TRANSFERTOCLOSEST) @@ -2670,7 +2689,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source) && player->nightstime < 10*TICRATE) { //S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH - S_ChangeMusicInternal("_drown",false); + S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false); } } } @@ -3000,11 +3019,13 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN // P_SpecialStageDamage // // Do old special stage-style damaging -// Removes 10 rings from the player, or knocks off their shield if they have one. +// Removes 5 seconds from the player, or knocks off their shield if they have one. // If they don't have anything, just knock the player back anyway (this doesn't kill them). // void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) { + tic_t oldnightstime = player->nightstime; + if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super]) return; @@ -3015,17 +3036,24 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) } else { - P_PlayRinglossSound(player->mo); - if (player->rings >= 10) - player->rings -= 10; + S_StartSound(player->mo, sfx_nghurt); + if (player->nightstime > 5*TICRATE) + player->nightstime -= 5*TICRATE; else - player->rings = 0; + player->nightstime = 0; } P_DoPlayerPain(player, inflictor, source); if (gametype == GT_CTF && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)) P_PlayerFlagBurst(player, false); + + if (oldnightstime > 10*TICRATE + && player->nightstime < 10*TICRATE) + { + //S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH + S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false); + } } /** Damages an object, which may or may not be a player. @@ -3175,6 +3203,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return true; } + if (G_IsSpecialStage(gamemap)) + { + P_SpecialStageDamage(player, inflictor, source); + return true; + } + if (!force && inflictor && inflictor->flags & MF_FIRE) { if (player->powers[pw_shield] & SH_PROTECTFIRE) diff --git a/src/p_local.h b/src/p_local.h index da4c70b0f..682fb7b55 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -146,6 +146,7 @@ void P_SpawnShieldOrb(player_t *player); void P_SwitchShield(player_t *player, UINT16 shieldtype); mobj_t *P_SpawnGhostMobj(mobj_t *mobj); void P_GivePlayerRings(player_t *player, INT32 num_rings); +void P_GivePlayerSpheres(player_t *player, INT32 num_spheres); void P_GivePlayerLives(player_t *player, INT32 numlives); void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound); UINT8 P_GetNextEmerald(void); diff --git a/src/p_mobj.c b/src/p_mobj.c index dbf5f5880..587615448 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2513,7 +2513,9 @@ static boolean P_ZMovement(mobj_t *mo) case MT_RING: // Ignore still rings case MT_COIN: - case MT_BLUEBALL: + case MT_BLUESPHERE: + case MT_NIGHTSCHIP: + case MT_NIGHTSSTAR: case MT_REDTEAMRING: case MT_BLUETEAMRING: case MT_FLINGRING: @@ -2550,10 +2552,6 @@ static boolean P_ZMovement(mobj_t *mo) if (!(mo->momx || mo->momy || mo->momz)) return true; break; - case MT_NIGHTSWING: - if (!(mo->momx || mo->momy || mo->momz)) - return true; - break; case MT_FLAMEJET: case MT_VERTICALFLAMEJET: if (!(mo->flags & MF_BOUNCE)) @@ -7225,7 +7223,7 @@ void P_MobjThinker(mobj_t *mobj) else if (mobj->health <= 0) // Dead things think differently than the living. switch (mobj->type) { - case MT_BLUEBALL: + case MT_BLUESPHERE: if ((mobj->tics>>2)+1 > 0 && (mobj->tics>>2)+1 <= tr_trans60) // tr_trans50 through tr_trans90, shifting once every second frame mobj->frame = (NUMTRANSMAPS-((mobj->tics>>2)+1))<target, NULL); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo - && players[i].mare == mobj->threshold && players[i].rings > 0) + && players[i].mare == mobj->threshold && players[i].spheres > 0) { fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); if (dist < shortest) @@ -7775,8 +7773,8 @@ void P_MobjThinker(mobj_t *mobj) } if (!bonustime) { - mobj->flags &= ~MF_NOGRAVITY; - P_SetMobjState(mobj, S_NIGHTSDRONE1); + /*mobj->flags &= ~MF_NOGRAVITY; + P_SetMobjState(mobj, S_NIGHTSDRONE1);*/ mobj->flags2 |= MF2_DONTDRAW; } } @@ -7848,7 +7846,9 @@ void P_MobjThinker(mobj_t *mobj) mobj->flags2 &= ~MF2_DONTDRAW; } mobj->angle += ANG10; - if (mobj->z <= mobj->floorz) + if (mobj->flags2 & MF2_DONTDRAW) + mobj->momz = 0; + else if (mobj->z <= mobj->floorz) mobj->momz = 5*FRACUNIT; } break; @@ -7881,7 +7881,9 @@ void P_MobjThinker(mobj_t *mobj) break; case MT_RING: case MT_COIN: - case MT_BLUEBALL: + case MT_BLUESPHERE: + case MT_NIGHTSCHIP: + case MT_NIGHTSSTAR: case MT_REDTEAMRING: case MT_BLUETEAMRING: // No need to check water. Who cares? @@ -7899,10 +7901,6 @@ void P_MobjThinker(mobj_t *mobj) else A_AttractChase(mobj); break; - case MT_NIGHTSWING: - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - break; case MT_EMBLEM: if (mobj->flags2 & MF2_NIGHTSPULL) P_NightsItemChase(mobj); @@ -8025,7 +8023,7 @@ void P_MobjThinker(mobj_t *mobj) { mobj_t *missile; - if (mobj->target->player && mobj->target->player->nightstime) + if (mobj->target->player && mobj->target->player->powers[pw_carry] == CR_NIGHTSMODE) { fixed_t oldval = mobjinfo[mobj->extravalue1].speed; @@ -8726,7 +8724,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_RING: case MT_COIN: - case MT_BLUEBALL: nummaprings++; default: break; @@ -8861,7 +8858,6 @@ void P_RemoveMobj(mobj_t *mobj) if (mobj->spawnpoint && (mobj->type == MT_RING || mobj->type == MT_COIN - || mobj->type == MT_BLUEBALL || mobj->type == MT_REDTEAMRING || mobj->type == MT_BLUETEAMRING || P_WeaponOrPanel(mobj->type)) @@ -8881,7 +8877,7 @@ void P_RemoveMobj(mobj_t *mobj) if (mobj->player && mobj->player->followmobj) { P_RemoveMobj(mobj->player->followmobj); - mobj->player->followmobj = NULL; + P_SetTarget(&mobj->player->followmobj, NULL); } mobj->health = 0; // Just because @@ -9314,7 +9310,7 @@ void P_SpawnPlayer(INT32 playernum) p->spectator = p->outofcoop = (((multiplayer || netgame) && gametype == GT_COOP) // only question status in coop && ((leveltime > 0 - && ((G_IsSpecialStage(gamemap) && useNightsSS) // late join special stage + && ((G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) // late join special stage || (cv_coopstarposts.value == 2 && (p->jointime < 1 || p->outofcoop)))) // late join or die in new coop || (((cv_cooplives.value == 1) || !P_GetLives(p)) && p->lives <= 0))); // game over and can't redistribute lives } @@ -9383,7 +9379,7 @@ void P_SpawnPlayer(INT32 playernum) P_SetupStateAnimation(mobj, mobj->state); mobj->health = 1; - p->rings = 0; + p->rings = p->spheres = 0; p->playerstate = PST_LIVE; p->bonustime = false; @@ -9402,6 +9398,22 @@ void P_SpawnPlayer(INT32 playernum) mobj->radius = FixedMul(skins[p->skin].radius, mobj->scale); mobj->height = P_GetPlayerHeight(p); + if (!leveltime && ((maptol & TOL_NIGHTS) == TOL_NIGHTS) != (G_IsSpecialStage(gamemap))) // non-special NiGHTS stage or special non-NiGHTS stage + { + if (maptol & TOL_NIGHTS) + { + if (p == players) // this is totally the wrong place to do this aaargh. + { + mobj_t *idya = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_GOTEMERALD); + P_SetTarget(&idya->target, mobj); + P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate); + P_SetTarget(&mobj->tracer, idya); + } + } + else if (sstimer) + p->nightstime = sstimer; + } + // Spawn with a pity shield if necessary. P_DoPityCheck(p); } @@ -9715,10 +9727,6 @@ void P_SpawnMapThing(mapthing_t *mthing) return; } - if (!G_RingSlingerGametype() || !cv_specialrings.value) - if (P_WeaponOrPanel(i)) - return; // Don't place weapons/panels in non-ringslinger modes - if (i == MT_EMERHUNT) { // Emerald Hunt is Coop only. @@ -9752,6 +9760,10 @@ void P_SpawnMapThing(mapthing_t *mthing) if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS)) return; + if (!G_RingSlingerGametype() || !cv_specialrings.value) + if (P_WeaponOrPanel(i)) + return; // Don't place weapons/panels in non-ringslinger modes + // Altering monitor spawns via cvars // If MF_GRENADEBOUNCE is set in the monitor's info, // skip this step. (Used for gold monitors) @@ -10754,8 +10766,9 @@ ML_EFFECT4 : Don't clip inside the ground mthing->mobj = mobj; } -void P_SpawnHoopsAndRings(mapthing_t *mthing) +void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) { + mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; INT32 r, i; fixed_t x, y, z, finalx, finaly, finalz; @@ -11034,59 +11047,26 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) return; } - // Wing logo item. - else if (mthing->type == mobjinfo[MT_NIGHTSWING].doomednum) - { - z = -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); - - mthing->z = (INT16)(z>>FRACBITS); - - mobj = P_SpawnMobj(x, y, z, MT_NIGHTSWING); - mobj->spawnpoint = mthing; - - if (G_IsSpecialStage(gamemap) && useNightsSS) - P_SetMobjState(mobj, mobj->info->meleestate); - else if (maptol & TOL_XMAS) - P_SetMobjState(mobj, mobj->info->seestate); - - mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mobj->flags2 |= MF2_AMBUSH; - mthing->mobj = mobj; - } // All manners of rings and coins else if (mthing->type == mobjinfo[MT_RING].doomednum || mthing->type == mobjinfo[MT_COIN].doomednum || - mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) + mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum || + mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) { - mobjtype_t ringthing = MT_RING; - - // No rings in Ultimate! - if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS)) - return; // Which ringthing to use - switch (mthing->type) - { - case 1800: - ringthing = MT_COIN; - break; - case 308: // No team rings in non-CTF - ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; - break; - case 309: // No team rings in non-CTF - ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; - break; - default: - // Spawn rings as blue spheres in special stages, ala S3+K. - if (G_IsSpecialStage(gamemap) && useNightsSS) - ringthing = MT_BLUEBALL; - break; - } + if (mthing->type == mobjinfo[MT_COIN].doomednum) + ringthing = MT_COIN; + else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF + ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; + else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto + ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; + else if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) + ringthing = MT_BLUESPHERE; + + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + ringthing = ((ringthing == MT_BLUESPHERE) ? MT_NIGHTSCHIP : MT_NIGHTSSTAR); + else if (ringthing != MT_BLUESPHERE && ultimatemode) + return; // No rings in Ultimate! // Set proper height if (mthing->options & MTF_OBJECTFLIP) @@ -11130,8 +11110,14 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) } mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mobj->flags2 |= MF2_AMBUSH; mthing->mobj = mobj; + if (mthing->options & MTF_AMBUSH) + mobj->flags2 |= MF2_AMBUSH; + + if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) + P_SetMobjState(mobj, mobj->info->raisestate); + else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); } // *** // Special placement patterns @@ -11141,17 +11127,13 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) else if (mthing->type == 600 || mthing->type == 601) { INT32 dist = 64*FRACUNIT; - mobjtype_t ringthing = MT_RING; if (mthing->type == 601) dist = 128*FRACUNIT; - // No rings in Ultimate! - if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS)) - return; - - // Spawn rings as blue spheres in special stages, ala S3+K. - if (G_IsSpecialStage(gamemap) && useNightsSS) - ringthing = MT_BLUEBALL; + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + ringthing = MT_NIGHTSSTAR; + else if (ultimatemode) + return; // No rings in Ultimate! for (r = 1; r <= 5; r++) { @@ -11187,31 +11169,30 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if (mthing->options & MTF_AMBUSH) mobj->flags2 |= MF2_AMBUSH; + + if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); } } // Diagonal rings (handles both types) else if (mthing->type == 602 || mthing->type == 603) // Diagonal rings (5) { - angle_t angle = FixedAngle(mthing->angle*FRACUNIT); - mobjtype_t ringthing = MT_RING; INT32 iterations = 5; if (mthing->type == 603) iterations = 10; - // No rings in Ultimate! - if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS)) - return; + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + ringthing = MT_NIGHTSSTAR; + else if (ultimatemode) + return; // No rings in Ultimate! - // Spawn rings as blue spheres in special stages, ala S3+K. - if (G_IsSpecialStage(gamemap) && useNightsSS) - ringthing = MT_BLUEBALL; - - angle >>= ANGLETOFINESHIFT; + closestangle = FixedAngle(mthing->angle*FRACUNIT); + fa = (closestangle >> ANGLETOFINESHIFT); for (r = 1; r <= iterations; r++) { - x += FixedMul(64*FRACUNIT, FINECOSINE(angle)); - y += FixedMul(64*FRACUNIT, FINESINE(angle)); + x += FixedMul(64*FRACUNIT, FINECOSINE(fa)); + y += FixedMul(64*FRACUNIT, FINESINE(fa)); if (mthing->options & MTF_OBJECTFLIP) { @@ -11242,9 +11223,12 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->flags2 |= MF2_OBJECTFLIP; } - mobj->angle = FixedAngle(mthing->angle*FRACUNIT); + mobj->angle = closestangle; if (mthing->options & MTF_AMBUSH) mobj->flags2 |= MF2_AMBUSH; + + if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); } } // Rings of items (all six of them) @@ -11252,7 +11236,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) { INT32 numitems = 8; INT32 size = 96*FRACUNIT; - mobjtype_t itemToSpawn = MT_NIGHTSWING; if (mthing->type & 1) { @@ -11277,30 +11260,24 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) { case 604: case 605: - itemToSpawn = MT_RING; + ringthing = MT_BLUESPHERE; break; case 608: case 609: - itemToSpawn = (i & 1) ? MT_NIGHTSWING : MT_RING; + ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; break; case 606: case 607: - itemToSpawn = MT_NIGHTSWING; + ringthing = MT_RING; break; default: break; } - // No rings in Ultimate! - if (itemToSpawn == MT_RING) - { - if (ultimatemode && !(G_IsSpecialStage(gamemap) || (maptol & TOL_NIGHTS))) - continue; - - // Spawn rings as blue spheres in special stages, ala S3+K. - if (G_IsSpecialStage(gamemap) && useNightsSS) - itemToSpawn = MT_BLUEBALL; - } + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + ringthing = ((ringthing == MT_BLUESPHERE) ? MT_NIGHTSCHIP : MT_NIGHTSSTAR); + else if (ringthing == MT_RING && ultimatemode) + continue; // No rings in Ultimate! fa = i*FINEANGLES/numitems; v[0] = FixedMul(FINECOSINE(fa),size); @@ -11315,16 +11292,23 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) finaly = y + v[1]; finalz = z + v[2]; - mobj = P_SpawnMobj(finalx, finaly, finalz, itemToSpawn); + mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing); mobj->z -= mobj->height/2; - if (itemToSpawn == MT_NIGHTSWING) + if (mthing->options & MTF_OBJECTFLIP) { - if (G_IsSpecialStage(gamemap) && useNightsSS) - P_SetMobjState(mobj, mobj->info->meleestate); - else if ((maptol & TOL_XMAS)) - P_SetMobjState(mobj, mobj->info->seestate); + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; } + + mobj->angle = closestangle; + if (mthing->options & MTF_AMBUSH) + mobj->flags2 |= MF2_AMBUSH; + + if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) + P_SetMobjState(mobj, mobj->info->raisestate); + else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); } return; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 405dca77e..f7b2d8f36 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -314,7 +314,7 @@ typedef struct mobj_s mobjtype_t type; const mobjinfo_t *info; // &mobjinfo[mobj->type] - INT32 health; // for player this is rings + 1 + INT32 health; // for player this is rings + 1 -- no it isn't, not any more!! // Movement direction, movement generation (zig-zagging). angle_t movedir; // dirtype_t 0-7; also used by Deton for up/down angle @@ -435,7 +435,7 @@ void P_MovePlayerToStarpost(INT32 playernum); void P_AfterPlayerSpawn(INT32 playernum); void P_SpawnMapThing(mapthing_t *mthing); -void P_SpawnHoopsAndRings(mapthing_t *mthing); +void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime); void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle); void P_SpawnPrecipitation(void); void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, statenum_t nstate, angle_t rotangle, boolean spawncenter); diff --git a/src/p_saveg.c b/src/p_saveg.c index 029df08f4..2e47f2077 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -116,7 +116,8 @@ static void P_NetArchivePlayers(void) WRITEANGLE(save_p, players[i].drawangle); WRITEANGLE(save_p, players[i].awayviewaiming); WRITEINT32(save_p, players[i].awayviewtics); - WRITEINT32(save_p, players[i].rings); + WRITEINT16(save_p, players[i].rings); + WRITEINT16(save_p, players[i].spheres); WRITESINT8(save_p, players[i].pity); WRITEINT32(save_p, players[i].currentweapon); @@ -201,7 +202,7 @@ static void P_NetArchivePlayers(void) WRITEUINT32(save_p, players[i].marebegunat); WRITEUINT32(save_p, players[i].startedtime); WRITEUINT32(save_p, players[i].finishedtime); - WRITEINT16(save_p, players[i].finishedrings); + WRITEINT16(save_p, players[i].finishedspheres); WRITEUINT32(save_p, players[i].marescore); WRITEUINT32(save_p, players[i].lastmarescore); WRITEUINT8(save_p, players[i].lastmare); @@ -303,7 +304,8 @@ static void P_NetUnArchivePlayers(void) players[i].drawangle = READANGLE(save_p); players[i].awayviewaiming = READANGLE(save_p); players[i].awayviewtics = READINT32(save_p); - players[i].rings = READINT32(save_p); + players[i].rings = READINT16(save_p); + players[i].spheres = READINT16(save_p); players[i].pity = READSINT8(save_p); players[i].currentweapon = READINT32(save_p); @@ -388,7 +390,7 @@ static void P_NetUnArchivePlayers(void) players[i].marebegunat = READUINT32(save_p); players[i].startedtime = READUINT32(save_p); players[i].finishedtime = READUINT32(save_p); - players[i].finishedrings = READINT16(save_p); + players[i].finishedspheres = READINT16(save_p); players[i].marescore = READUINT32(save_p); players[i].lastmarescore = READUINT32(save_p); players[i].lastmare = READUINT8(save_p); @@ -1986,7 +1988,7 @@ static void LoadMobjThinker(actionf_p1 thinker) if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case { - P_SpawnHoopsAndRings(&mapthings[spawnpointnum]); + P_SpawnHoopsAndRings(&mapthings[spawnpointnum], false); return; } @@ -3261,7 +3263,7 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, tokenlist); WRITEUINT32(save_p, leveltime); - WRITEUINT32(save_p, totalrings); + WRITEUINT32(save_p, ssspheres); WRITEINT16(save_p, lastmap); WRITEUINT16(save_p, emeralds); @@ -3338,7 +3340,7 @@ static inline boolean P_NetUnArchiveMisc(void) // get the time leveltime = READUINT32(save_p); - totalrings = READUINT32(save_p); + ssspheres = READUINT32(save_p); lastmap = READINT16(save_p); emeralds = READUINT16(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index a9fc57652..076c8dba7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -808,7 +808,7 @@ void P_ReloadRings(void) mapthing_t *hoopsToRespawn[4096]; mapthing_t *mt = mapthings; - // scan the thinkers to find rings/wings/hoops to unset + // scan the thinkers to find rings/spheres/hoops to unset for (th = thinkercap.next; th != &thinkercap; th = th->next) { if (th->function.acp1 != (actionf_p1)P_MobjThinker) @@ -826,7 +826,8 @@ void P_ReloadRings(void) } continue; } - if (!(mo->type == MT_RING || mo->type == MT_NIGHTSWING || mo->type == MT_COIN || mo->type == MT_BLUEBALL)) + if (!(mo->type == MT_RING || mo->type == MT_COIN || mo->type == MT_BLUESPHERE + || mo->type == MT_NIGHTSCHIP || mo->type == MT_NIGHTSSTAR)) continue; // Don't auto-disintegrate things being pulled to us @@ -840,9 +841,9 @@ void P_ReloadRings(void) for (i = 0; i < nummapthings; i++, mt++) { // Notice an omission? We handle hoops differently. - if (mt->type == 300 || mt->type == 308 || mt->type == 309 - || mt->type == 1706 || (mt->type >= 600 && mt->type <= 609) - || mt->type == 1800) + if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum + || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_COIN].doomednum + || (mt->type >= 600 && mt->type <= 609)) // circles { mt->mobj = NULL; @@ -850,12 +851,35 @@ void P_ReloadRings(void) mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) ->sector->floorheight>>FRACBITS); - P_SpawnHoopsAndRings (mt); + P_SpawnHoopsAndRings(mt, true); } } for (i = 0; i < numHoops; i++) { - P_SpawnHoopsAndRings(hoopsToRespawn[i]); + P_SpawnHoopsAndRings(hoopsToRespawn[i], false); + } +} + +void P_SwitchSpheresBonusMode(boolean bonustime) +{ + mobj_t *mo; + thinker_t *th; + + // scan the thinkers to find spheres to switch + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo = (mobj_t *)th; + + if (mo->type != MT_BLUESPHERE && mo->type != MT_NIGHTSCHIP) + continue; + + if (!mo->health) + continue; + + P_SetMobjState(mo, ((bonustime) ? mo->info->raisestate : mo->info->spawnstate)); } } @@ -1025,20 +1049,22 @@ static void P_LoadThings(void) } //decrement spawn values to the actual number because zero is valid. - if (emer1) - P_SpawnMobj(huntemeralds[emer1 - 1]->x<y<z<x<y<z<x<y<z<x<y<z<x<y<z<x<y<z<z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) ->sector->floorheight>>FRACBITS); - P_SpawnHoopsAndRings (mt); + P_SpawnHoopsAndRings(mt, false); } } } @@ -2298,7 +2324,7 @@ static void P_LevelInitStuff(void) // circuit, race and competition stuff circuitmap = false; numstarposts = 0; - totalrings = timeinmap = 0; + ssspheres = timeinmap = 0; // special stage stagefailed = false; @@ -2334,6 +2360,7 @@ static void P_LevelInitStuff(void) players[i].xtralife = players[i].deadtimer = players[i].numboxes = players[i].totalring = players[i].laps = 0; players[i].rings = 0; + players[i].spheres = 0; players[i].aiming = 0; players[i].pflags &= ~PF_GAMETYPEOVER; @@ -2341,7 +2368,7 @@ static void P_LevelInitStuff(void) players[i].timeshit = 0; players[i].marescore = players[i].lastmarescore = players[i].maxlink = 0; - players[i].startedtime = players[i].finishedtime = players[i].finishedrings = 0; + players[i].startedtime = players[i].finishedtime = players[i].finishedspheres = 0; players[i].lastmare = players[i].marebegunat = 0; // Don't show anything diff --git a/src/p_setup.h b/src/p_setup.h index a42ac5b76..569501531 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -72,6 +72,7 @@ void P_DeleteFlickies(INT16 i); // Needed for NiGHTS void P_ReloadRings(void); +void P_SwitchSpheresBonusMode(boolean bonustime); void P_DeleteGrades(INT16 i); void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext); UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare); diff --git a/src/p_spec.c b/src/p_spec.c index e77a783e9..2999d94ac 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2868,7 +2868,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Unlocked something? if (M_UpdateUnlockablesAndExtraEmblems()) { - S_StartSound(NULL, sfx_ncitem); + S_StartSound(NULL, sfx_s3k68); G_SaveGameData(); // only save if unlocked something } } @@ -3527,7 +3527,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers if (player->exiting || player->bot) // Don't do anything for bots or players who have just finished break; - if (!(player->powers[pw_shield] || player->rings > 0)) // Don't do anything if no shield or rings anyway + if (!(player->powers[pw_shield] || player->spheres > 0)) // Don't do anything if no shield or spheres anyway break; P_SpecialStageDamage(player, NULL, NULL); @@ -3775,8 +3775,8 @@ DoneSection2: case 2: // Special stage GOAL sector / Exit Sector / CTF Flag Return if (player->bot) break; - if (!useNightsSS && G_IsSpecialStage(gamemap) && sstimer > 6) - sstimer = 6; // Just let P_Ticker take care of the rest. + if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6) + player->nightstime = 6; // Just let P_Ticker take care of the rest. // Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c) { @@ -4643,7 +4643,7 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) switch(GETSECSPECIAL(sector->special, 4)) { case 2: // Level Exit / GOAL Sector / Flag Return - if (!useNightsSS && G_IsSpecialStage(gamemap)) + if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap)) { // Special stage GOAL sector // requires touching floor. @@ -5502,7 +5502,7 @@ void P_InitSpecials(void) // Defaults in case levels don't have them set. sstimer = 90*TICRATE + 6; - totalrings = 1; + ssspheres = 1; CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; @@ -5596,7 +5596,7 @@ void P_SpawnSpecials(INT32 fromnetsave) { case 10: // Time for special stage sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish - totalrings = sector->ceilingheight>>FRACBITS; // Ring count for special stage + ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage break; case 11: // Custom global gravity! diff --git a/src/p_tick.c b/src/p_tick.c index 658b1e4ea..483b161a4 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -424,7 +424,7 @@ void P_DoTeamscrambling(void) static inline void P_DoSpecialStageStuff(void) { - boolean inwater = false; + boolean stillalive = false; INT32 i; // Can't drown in a special stage @@ -436,68 +436,59 @@ static inline void P_DoSpecialStageStuff(void) players[i].powers[pw_underwater] = players[i].powers[pw_spacetime] = 0; } - if (sstimer < 15*TICRATE+6 && sstimer > 7 && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)) - S_SpeedMusic(1.4f); + //if (sstimer < 15*TICRATE+6 && sstimer > 7 && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)) + //S_SpeedMusic(1.4f); - if (sstimer < 7 && sstimer > 0) // The special stage time is up! + if (sstimer && !objectplacing) { - sstimer = 0; - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - { - players[i].exiting = (14*TICRATE)/5 + 1; - players[i].pflags &= ~PF_GLIDING; - } - - if (i == consoleplayer) - S_StartSound(NULL, sfx_lose); - } - - if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC) - S_SpeedMusic(1.0f); - - stagefailed = true; - } - - if (sstimer > 1) // As long as time isn't up... - { - UINT32 ssrings = 0; + UINT16 countspheres = 0; // Count up the rings of all the players and see if // they've collected the required amount. for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { - ssrings += players[i].rings; + tic_t oldnightstime = players[i].nightstime; + countspheres += players[i].spheres; // If in water, deplete timer 6x as fast. - if ((players[i].mo->eflags & MFE_TOUCHWATER) - || (players[i].mo->eflags & MFE_UNDERWATER)) - inwater = true; + if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) + players[i].nightstime -= 5; + if (--players[i].nightstime > 6) + { + if (P_IsLocalPlayer(&players[i]) && oldnightstime > 10*TICRATE && players[i].nightstime <= 10*TICRATE) + S_ChangeMusicInternal("_drown", false); + stillalive = true; + } + else if (!players[i].exiting) + { + players[i].exiting = (14*TICRATE)/5 + 1; + players[i].pflags &= ~(PF_GLIDING|PF_BOUNCING); + players[i].nightstime = 0; + if (P_IsLocalPlayer(&players[i])) + S_StartSound(NULL, sfx_s3k66); + } } - if (ssrings >= totalrings && totalrings > 0) + if (stillalive) { - // Halt all the players - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - players[i].mo->momx = players[i].mo->momy = 0; - players[i].exiting = (14*TICRATE)/5 + 1; - } + if (countspheres >= ssspheres) + { + // Halt all the players + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + { + players[i].mo->momx = players[i].mo->momy = 0; + players[i].exiting = (14*TICRATE)/5 + 1; + } - sstimer = 0; - - P_GiveEmerald(true); + sstimer = 0; + P_GiveEmerald(true); + } } - - // Decrement the timer - if (!objectplacing) + else { - if (inwater) - sstimer -= 6; - else - sstimer--; + sstimer = 0; + stagefailed = true; } } } @@ -608,7 +599,7 @@ void P_Ticker(boolean run) // Keep track of how long they've been playing! totalplaytime++; - if (!useNightsSS && G_IsSpecialStage(gamemap)) + if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap)) P_DoSpecialStageStuff(); if (runemeraldmanager) diff --git a/src/p_user.c b/src/p_user.c index a28c8f445..8d05d2b01 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -283,22 +283,9 @@ boolean P_PlayerMoving(INT32 pnum) // UINT8 P_GetNextEmerald(void) { - if (!useNightsSS) // In order - { - if (!(emeralds & EMERALD1)) return 0; - if (!(emeralds & EMERALD2)) return 1; - if (!(emeralds & EMERALD3)) return 2; - if (!(emeralds & EMERALD4)) return 3; - if (!(emeralds & EMERALD5)) return 4; - if (!(emeralds & EMERALD6)) return 5; - return 6; - } - else // Depends on stage - { - if (gamemap < sstage_start || gamemap > sstage_end) - return 0; - return (UINT8)(gamemap - sstage_start); - } + if (gamemap < sstage_start || gamemap > sstage_end) + return 0; + return (UINT8)(gamemap - sstage_start); } // @@ -309,20 +296,20 @@ UINT8 P_GetNextEmerald(void) // void P_GiveEmerald(boolean spawnObj) { - INT32 i; - UINT8 em; + UINT8 em = P_GetNextEmerald(); S_StartSound(NULL, sfx_cgot); // Got the emerald! - em = P_GetNextEmerald(); emeralds |= (1 << em); - if (spawnObj) + if (spawnObj && playeringame[consoleplayer]) { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - P_SetMobjState(P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z + players[i].mo->info->height, MT_GOTEMERALD), - mobjinfo[MT_GOTEMERALD].spawnstate + em); - + // The Chaos Emerald begins to orbit us! + UINT8 em = P_GetNextEmerald(); + // Only give it to ONE person! + mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD); + P_SetTarget(&emmo->target, players[consoleplayer].mo); + P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); + P_SetTarget(&players[consoleplayer].mo->tracer, emmo); } } @@ -692,10 +679,10 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) oldmare = player->mare; - if (P_TransferToNextMare(player) == false) + if (!P_TransferToNextMare(player)) { INT32 i; - INT32 total_rings = 0; + INT32 total_spheres = 0; P_SetTarget(&player->mo->target, NULL); @@ -703,7 +690,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) { for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]/* && players[i].powers[pw_carry] == CR_NIGHTSMODE*/) - total_rings += players[i].rings; + total_spheres += players[i].spheres; } for (i = 0; i < MAXPLAYERS; i++) @@ -716,13 +703,13 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) players[i].lastmare = players[i].mare; if (G_IsSpecialStage(gamemap)) { - players[i].finishedrings = (INT16)total_rings; - P_AddPlayerScore(player, total_rings * 50); + players[i].finishedspheres = (INT16)total_spheres; + P_AddPlayerScore(player, total_spheres * 50); } else { - players[i].finishedrings = (INT16)(players[i].rings); - P_AddPlayerScore(&players[i], (players[i].rings) * 50); + players[i].finishedspheres = (INT16)(players[i].spheres); + P_AddPlayerScore(&players[i], (players[i].spheres) * 50); } // Add score to leaderboards now @@ -733,20 +720,20 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) players[i].lastmarescore = players[i].marescore; players[i].marescore = 0; - players[i].rings = 0; + players[i].spheres = 0; P_DoPlayerExit(&players[i]); } } else if (oldmare != player->mare) { /// \todo Handle multi-mare special stages. - // Ring bonus - P_AddPlayerScore(player, (player->rings) * 50); + // Spheres bonus + P_AddPlayerScore(player, (player->spheres) * 50); player->lastmare = (UINT8)oldmare; player->texttimer = 4*TICRATE; player->textvar = 4; // Score and grades - player->finishedrings = (INT16)(player->rings); + player->finishedspheres = (INT16)(player->spheres); // Add score to temp leaderboards if (!(netgame||multiplayer) && P_IsLocalPlayer(player)) @@ -757,7 +744,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->marescore = 0; player->marebegunat = leveltime; - player->rings = 0; + player->spheres = 0; } else { @@ -857,7 +844,7 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) } else { - ang = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0); + ang = ((player->mo->momx || player->mo->momy) ? R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0) : player->drawangle); fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale); } @@ -923,8 +910,7 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) player->rings += num_rings; - if (!G_IsSpecialStage(gamemap) || !useNightsSS) - player->totalring += num_rings; + player->totalring += num_rings; // Can only get up to 9999 rings, sorry! if (player->rings > 9999) @@ -956,6 +942,26 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) } } +void P_GivePlayerSpheres(player_t *player, INT32 num_spheres) +{ + if (!player) + return; + + if (player->bot) + player = &players[consoleplayer]; + + if (!player->mo) + return; + + player->spheres += num_spheres; + + // Can only get up to 9999 spheres, sorry! + if (player->spheres > 9999) + player->spheres = 9999; + else if (player->spheres < 0) + player->spheres = 0; +} + // // P_GivePlayerLives // @@ -1035,10 +1041,11 @@ void P_DoSuperTransformation(player_t *player, boolean giverings) S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi + player->mo->momx = player->mo->momy = player->mo->momz = player->cmomx = player->cmomy = player->rmomx = player->rmomy = 0; + // Transformation animation P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_TRANS1); - player->mo->momx = player->mo->momy = player->mo->momz = 0; player->pflags |= PF_NOJUMPDAMAGE; // just to avoid recurling but still allow thok if (giverings) @@ -3793,12 +3800,15 @@ static void P_DoSuperStuff(player_t *player) // boolean P_SuperReady(player_t *player) { - if ((ALL7EMERALDS(emeralds) && player->rings >= 50) && !player->powers[pw_super] && !player->powers[pw_tailsfly] - && !(player->powers[pw_shield] & SH_NOSTACK) + if (!player->powers[pw_super] && !player->powers[pw_invulnerability] - && !(maptol & TOL_NIGHTS || (player->powers[pw_carry] == CR_NIGHTSMODE)) // don't turn 'regular super' in nights levels - && player->pflags & PF_JUMPED - && player->charflags & SF_SUPER) + && !player->powers[pw_tailsfly] + && (player->charflags & SF_SUPER) + && (player->pflags & PF_JUMPED) + && !(player->powers[pw_shield] & SH_NOSTACK) + && !(maptol & TOL_NIGHTS) + && ALL7EMERALDS(emeralds) + && (player->rings >= 50)) return true; return false; @@ -4484,12 +4494,12 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag)) ; - else if (P_SuperReady(player)) + /*else if (P_SuperReady(player)) { // If you can turn super and aren't already, // and you don't have a shield, do it! P_DoSuperTransformation(player, false); - } + }*/ else if (player->pflags & PF_JUMPED) { #ifdef HAVE_BLUA @@ -5953,10 +5963,10 @@ static void P_DoNiGHTSCapsule(player_t *player) if (G_IsSpecialStage(gamemap)) { // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here! for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (&players[i] != player) && players[i].rings > 0) + if (playeringame[i] && (&players[i] != player) && players[i].spheres > 0) { - player->rings += players[i].rings; - players[i].rings = 0; + player->spheres += players[i].spheres; + players[i].spheres = 0; } } @@ -5965,9 +5975,9 @@ static void P_DoNiGHTSCapsule(player_t *player) && player->mo->y == player->capsule->y && player->mo->z == player->capsule->z+(player->capsule->height/3)) { - if (player->rings > 0) + if (player->spheres > 0) { - player->rings--; + player->spheres--; player->capsule->health--; player->capsule->extravalue1++; @@ -5999,9 +6009,6 @@ static void P_DoNiGHTSCapsule(player_t *player) if (G_IsSpecialStage(gamemap)) { - // The Chaos Emerald begins to orbit us! - mobj_t *emmo; - UINT8 em = P_GetNextEmerald(); tic_t lowest_time; /*for (i = 0; i < MAXPLAYERS; i++) @@ -6016,8 +6023,10 @@ static void P_DoNiGHTSCapsule(player_t *player) if (player->powers[pw_carry] == CR_NIGHTSMODE) { + // The Chaos Emerald begins to orbit us! + UINT8 em = P_GetNextEmerald(); // Only give it to ONE person, and THAT player has to get to the goal! - emmo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->info->height, MT_GOTEMERALD); + mobj_t *emmo = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height, MT_GOTEMERALD); P_SetTarget(&emmo->target, player->mo); P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); P_SetTarget(&player->mo->tracer, emmo); @@ -6035,18 +6044,24 @@ static void P_DoNiGHTSCapsule(player_t *player) } else { - for (i = 0; i < 16; i++) + /*for (i = 0; i < 16; i++) { mobj_t *flicky = P_InternalFlickySpawn(player->capsule, 0, ((i%4) + 1)*2*FRACUNIT, true); flicky->z += player->capsule->height/2; flicky->angle = (i*(ANGLE_MAX/16)); P_InstaThrust(flicky, flicky->angle, 8*FRACUNIT); - } + }*/ + mobj_t *idya = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height, MT_GOTEMERALD); + idya->extravalue2 = player->mare/5; + P_SetTarget(&idya->target, player->mo); + P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate + ((player->mare + 1) % 5)); + P_SetTarget(&player->mo->tracer, idya); } for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mare == player->mare) P_SetTarget(&players[i].capsule, NULL); // Remove capsule from everyone now that it is dead! S_StartScreamSound(player->mo, sfx_ngdone); + P_SwitchSpheresBonusMode(true); } } else @@ -6139,7 +6154,7 @@ static void P_NiGHTSMovement(player_t *player) } else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE) // S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH - S_ChangeMusicInternal("_drown",false); + S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false); if (player->mo->z < player->mo->floorz) @@ -7477,7 +7492,7 @@ static void P_MovePlayer(player_t *player) #endif { if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously - && (!(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped + && (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super { // Force shield activation if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) @@ -7490,6 +7505,11 @@ static void P_MovePlayer(player_t *player) { switch (player->powers[pw_shield] & SH_NOSTACK) { + // Super! + case SH_NONE: + if (P_SuperReady(player)) + P_DoSuperTransformation(player, false); + break; // Whirlwind/Thundercoin shield activation case SH_WHIRLWIND: case SH_THUNDERCOIN: @@ -9563,11 +9583,8 @@ void P_PlayerThink(player_t *player) // If 11 seconds are left on the timer, // begin the drown music for countdown! - if (countdown == 11*TICRATE - 1) - { - if (P_IsLocalPlayer(player)) - S_ChangeMusicInternal("_drown", false); - } + if (countdown == 11*TICRATE - 1 && P_IsLocalPlayer(player)) + S_ChangeMusicInternal("_drown", false); // If you've hit the countdown and you haven't made // it to the exit, you're a goner! @@ -9667,7 +9684,7 @@ void P_PlayerThink(player_t *player) if (gametype != GT_COOP) player->score = 0; player->mo->health = 1; - player->rings = 0; + player->rings = player->spheres = 0; } else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP) { @@ -9720,8 +9737,8 @@ void P_PlayerThink(player_t *player) mo2 = (mobj_t *)th; - if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN - || mo2->type == MT_BLUEBALL)) + if (!(mo2->type == MT_RING || mo2->type == MT_COIN || mo2->type == MT_BLUESPHERE + || mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR)) continue; if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > FixedMul(128*FRACUNIT, player->mo->scale)) @@ -10210,7 +10227,7 @@ void P_PlayerAfterThink(player_t *player) if (player->followmobj) { P_RemoveMobj(player->followmobj); - player->followmobj = NULL; + P_SetTarget(&player->followmobj, NULL); } return; } @@ -10495,14 +10512,14 @@ void P_PlayerAfterThink(player_t *player) if (player->followmobj && (player->spectator || player->mo->health <= 0 || player->followmobj->type != player->followitem)) { P_RemoveMobj(player->followmobj); - player->followmobj = NULL; + P_SetTarget(&player->followmobj, NULL); } if (!player->spectator && player->mo->health && player->followitem) { if (!player->followmobj || P_MobjWasRemoved(player->followmobj)) { - player->followmobj = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem); + P_SetTarget(&player->followmobj, P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem)); P_SetTarget(&player->followmobj->tracer, player->mo); player->followmobj->flags2 |= MF2_LINKDRAW; } diff --git a/src/r_things.c b/src/r_things.c index b0cb3ab8e..9e858aba9 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2673,7 +2673,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) if (player->followmobj) { P_RemoveMobj(player->followmobj); - player->followmobj = NULL; + P_SetTarget(&player->followmobj, NULL); } if (player->mo) diff --git a/src/screen.c b/src/screen.c index cd97b62fa..9bbcb995c 100644 --- a/src/screen.c +++ b/src/screen.c @@ -446,10 +446,11 @@ void SCR_ClosedCaptions(void) { if (splitscreen) basey -= 8; - else if (((maptol & TOL_NIGHTS) && (modeattacking == ATTACKING_NIGHTS)) - || (cv_powerupdisplay.value == 2) + else if ((modeattacking == ATTACKING_NIGHTS) + || (!(maptol & TOL_NIGHTS) + && ((cv_powerupdisplay.value == 2) || (cv_powerupdisplay.value == 1 && ((stplyr == &players[displayplayer] && !camera.chase) - || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)))) + || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)))))) basey -= 16; } diff --git a/src/sounds.c b/src/sounds.c index d3a0ac373..4070839ab 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -141,7 +141,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing! {"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing! {"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"}, - {"cgot" , true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Chaos Emerald"}, // Got Emerald! Tails 09-02-2001 + {"cgot" , true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Emerald"}, // Got Emerald! Tails 09-02-2001 {"cybdth", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Explosion"}, {"deton", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous beeping"}, {"ding", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Ding"}, @@ -214,11 +214,12 @@ sfxinfo_t S_sfx[NUMSFX] = {"xideya", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Success"}, // Xmas {"nbmper", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, {"nxbump", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, // Xmas + {"ncchip", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got chip"}, {"ncitem", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got special"}, {"nxitem", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got special"}, // Xmas {"ngdone", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonus time start"}, {"nxdone", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonus time start"}, // Xmas - {"drill1", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drill start"}, + {"drill1", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drill"}, {"drill2", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drill"}, {"ncspec", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power-up"}, // Tails 12-15-2003 {"nghurt", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"}, @@ -228,12 +229,13 @@ sfxinfo_t S_sfx[NUMSFX] = {"hoop3", false, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hoop++"}, {"hidden", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"}, {"prloop", false, 104, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gust of wind"}, - {"timeup", true, 256, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous Countdown"}, + {"ngjump", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"}, + {"peww", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pew"}, // Halloween {"lntsit", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cacolantern awake"}, {"lntdie", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cacolantern death"}, - {"pumpkn", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pumpkin smash"}, + {"pumpkn", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pumpkin smash"}, // idspispopd {"ghosty", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Laughter"}, // Mario @@ -334,10 +336,10 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"}, {"s3k63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, {"s3k64", false, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Clatter"}, - {"s3k65", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got blue sphere"}, // Blue Spheres + {"s3k65", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got sphere"}, // Blue Spheres {"s3k66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage end"}, {"s3k67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing missile"}, - {"s3k68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Unknown possibilities"}, + {"s3k68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"}, {"s3k69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Switch click"}, {"s3k6a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage clear"}, {"s3k6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Punch"}, diff --git a/src/sounds.h b/src/sounds.h index 56189f55f..5fffc7b2e 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -280,6 +280,7 @@ typedef enum sfx_xideya, // Xmas sfx_nbmper, sfx_nxbump, // Xmas + sfx_ncchip, sfx_ncitem, sfx_nxitem, // Xmas sfx_ngdone, @@ -294,7 +295,8 @@ typedef enum sfx_hoop3, sfx_hidden, sfx_prloop, - sfx_timeup, // Was gonna be played when less than ten seconds are on the clock; uncomment uses of this to see it in-context + sfx_ngjump, + sfx_peww, // Halloween sfx_lntsit, diff --git a/src/st_stuff.c b/src/st_stuff.c index a513a028c..031aa61db 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -112,6 +112,8 @@ static patch_t *yelstat; static patch_t *nbracket; static patch_t *nhud[12]; static patch_t *nsshud; +static patch_t *nbon[12]; +static patch_t *nssbon; static patch_t *narrow[9]; static patch_t *nredar[8]; // Red arrow static patch_t *drillbar; @@ -309,8 +311,12 @@ void ST_LoadGraphics(void) yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX); nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX); for (i = 0; i < 12; ++i) + { nhud[i] = W_CachePatchName(va("NHUD%d", i+1), PU_HUDGFX); + nbon[i] = W_CachePatchName(va("NBON%d", i+1), PU_HUDGFX); + } nsshud = W_CachePatchName("NSSHUD", PU_HUDGFX); + nssbon = W_CachePatchName("NSSBON", PU_HUDGFX); minicaps = W_CachePatchName("MINICAPS", PU_HUDGFX); for (i = 0; i < 8; ++i) @@ -735,18 +741,7 @@ static inline void ST_drawRings(void) ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); - if (objectplacing) - ringnum = op_currentdoomednum; - else if (!useNightsSS && G_IsSpecialStage(gamemap)) - { - INT32 i; - ringnum = 0; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && players[i].rings > 0) - ringnum += players[i].rings; - } - else - ringnum = max(stplyr->rings, 0); + ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0)); if (cv_timetic.value == 2) // Yes, even in modeattacking ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); @@ -1394,17 +1389,17 @@ static void ST_drawNightsRecords(void) V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag, va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health, (stplyr->textvar == 3) ? M_GetText("MORE ") : "", - (G_IsSpecialStage(gamemap)) ? "SPHERE" : "RING", + (G_IsSpecialStage(gamemap)) ? "SPHERE" : "CHIP", (stplyr->capsule->health > 1) ? "S" : "")); } // End Bonus else if (stplyr->textvar == 4) { - V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "RINGS:"); + V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:"); V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:"); - V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings)); - V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings * 50)); + V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres)); + V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 148, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres * 50)); ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<lastmarescore, nightsnum, SKINCOLOR_AZURE); // If new record, say so! @@ -1462,15 +1457,15 @@ static void ST_drawNiGHTSHUD(void) { INT32 origamount; INT32 minlink = 1; - INT32 total_ringcount; - - // When debugging, show "0 Link". - if (cv_debug & DBG_NIGHTSBASIC) - minlink = 0; + INT32 total_spherecount; + const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS)); // Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional) - if (stplyr->texttimer && stplyr->textvar == 4) + if (oldspecialstage || (stplyr->texttimer && stplyr->textvar == 4)) minlink = INT32_MAX; + // When debugging, show "0 Link". + else if (cv_debug & DBG_NIGHTSBASIC) + minlink = 0; // Drill meter if ( @@ -1576,25 +1571,35 @@ static void ST_drawNiGHTSHUD(void) // Begin drawing brackets/chip display #ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_nightsrings)) + if (LUA_HudEnabled(hud_nightsspheres)) { #endif ST_DrawTopLeftOverlayPatch(16, 8, nbracket); if (G_IsSpecialStage(gamemap)) - ST_DrawTopLeftOverlayPatch(24, 16, nsshud); + ST_DrawTopLeftOverlayPatch(24, 16, ((stplyr->bonustime && (leveltime & 4)) ? nssbon : nsshud)); + else if (stplyr->bonustime) + ST_DrawTopLeftOverlayPatch(24, 16, nbon[(leveltime/2)%12]); else ST_DrawTopLeftOverlayPatch(24, 16, nhud[(leveltime/2)%12]); if (G_IsSpecialStage(gamemap)) { INT32 i; - total_ringcount = 0; + total_spherecount = 0; for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/ && players[i].rings) - total_ringcount += players[i].rings; + if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/ && players[i].spheres) + total_spherecount += players[i].spheres; } else - total_ringcount = stplyr->rings; + total_spherecount = stplyr->spheres; + + /*if (oldspecialstage) + { + if (total_spherecount < ssspheres) + total_spherecount = ssspheres - total_spherecount; + else + total_spherecount = 0; + }*/ if (stplyr->capsule) { @@ -1650,28 +1655,48 @@ static void ST_drawNiGHTSHUD(void) amount = (origamount - stplyr->capsule->health); amount = (amount * length)/origamount; - for (cfill = 0; cfill < amount && cfill < 88; ++cfill) + for (cfill = 0; cfill < amount && cfill < length; ++cfill) V_DrawScaledPatch(15 + cfill + 1, 8 + 35, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill); } - if (total_ringcount >= stplyr->capsule->health) - ST_DrawTopLeftOverlayPatch(40, 8 + 5, nredar[leveltime%8]); + if (total_spherecount >= stplyr->capsule->health) + ST_DrawTopLeftOverlayPatch(40, 8 + 5, nredar[leveltime&7]); else - ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)%8]); + ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)&7]); + } + else if (oldspecialstage && total_spherecount < ssspheres) + { + INT32 cfill, amount; + const INT32 length = 88; + UINT8 em = P_GetNextEmerald(); + ST_DrawTopLeftOverlayPatch(72, 8, nbracket); + + if (em <= 7) + ST_DrawTopLeftOverlayPatch(80, 8 + 8, emeraldpics[0][em]); + + ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)&7]); + + // Lil' white box! + V_DrawScaledPatch(15, 8 + 34, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulebar); + + amount = (total_spherecount * length)/ssspheres; + + for (cfill = 0; cfill < amount && cfill < length; ++cfill) + V_DrawScaledPatch(15 + cfill + 1, 8 + 35, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill); } else ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]); - if (total_ringcount >= 100) - V_DrawTallNum((total_ringcount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_ringcount); + if (total_spherecount >= 100) + V_DrawTallNum((total_spherecount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount); else - V_DrawTallNum(68, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_ringcount); + V_DrawTallNum(68, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount); #ifdef HAVE_BLUA } #endif // Score - if (!stplyr->exiting + if (!stplyr->exiting && !oldspecialstage #ifdef HAVE_BLUA && LUA_HudEnabled(hud_nightsscore) #endif @@ -1714,6 +1739,7 @@ static void ST_drawNiGHTSHUD(void) { INT32 realnightstime = stplyr->nightstime/TICRATE; INT32 numbersize; + UINT8 col = ((realnightstime < 10) ? SKINCOLOR_RED : SKINCOLOR_SUPERGOLD4); if (G_IsSpecialStage(gamemap)) { @@ -1744,46 +1770,66 @@ static void ST_drawNiGHTSHUD(void) else numbersize = 48/2; - ST_DrawNightsOverlayNum((160 + numbersize)<mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))) + col = SKINCOLOR_ORANGE; + + ST_DrawNightsOverlayNum((160 + numbersize)<nightstime))); } - // Show pickup durations - if (cv_debug & DBG_NIGHTSBASIC) + if (oldspecialstage) { - UINT16 pwr; - - if (stplyr->powers[pw_nights_superloop]) + if (leveltime < 5*TICRATE) { - pwr = stplyr->powers[pw_nights_superloop]; - V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_CACHE)); - V_DrawThinString(106, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); - } - - if (stplyr->powers[pw_nights_helper]) - { - pwr = stplyr->powers[pw_nights_helper]; - V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_CACHE)); - V_DrawThinString(146, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); - } - - if (stplyr->powers[pw_nights_linkfreeze]) - { - pwr = stplyr->powers[pw_nights_linkfreeze]; - V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_CACHE)); - V_DrawThinString(186, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + INT32 aflag = V_PERPLAYER; + tic_t drawtime = (5*TICRATE) - leveltime; + if (drawtime < TICRATE/2) + aflag |= (9 - 9*drawtime/(TICRATE/2)) << V_ALPHASHIFT; + // This one, not quite as much so. + V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag, + va(M_GetText("\x80GET\x82 %d\x80 SPHERE%s!"), ssspheres, + (ssspheres > 1) ? "S" : "")); } } + else + { + // Show pickup durations + if (cv_debug & DBG_NIGHTSBASIC) + { + UINT16 pwr; - // Records/extra text + if (stplyr->powers[pw_nights_superloop]) + { + pwr = stplyr->powers[pw_nights_superloop]; + V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_CACHE)); + V_DrawThinString(106, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + } + + if (stplyr->powers[pw_nights_helper]) + { + pwr = stplyr->powers[pw_nights_helper]; + V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_CACHE)); + V_DrawThinString(146, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + } + + if (stplyr->powers[pw_nights_linkfreeze]) + { + pwr = stplyr->powers[pw_nights_linkfreeze]; + V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_CACHE)); + V_DrawThinString(186, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); + } + } + + // Records/extra text #ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_nightsrecords)) + if (LUA_HudEnabled(hud_nightsrecords)) #endif - ST_drawNightsRecords(); + ST_drawNightsRecords(); + } } static inline void ST_drawWeaponSelect(INT32 xoffs, INT32 y) @@ -1952,7 +1998,7 @@ static void ST_drawTextHUD(void) } else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE)) { - if (G_IsSpecialStage(gamemap) && useNightsSS) + if (G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) else if (gametype == GT_COOP) { @@ -2070,22 +2116,22 @@ num: #undef SEP } -static void ST_drawSpecialStageHUD(void) +/*static void ST_drawSpecialStageHUD(void) { - if (totalrings > 0) + if (ssspheres > 0) { if (hudinfo[HUD_SS_TOTALRINGS].x) - ST_DrawNumFromHud(HUD_SS_TOTALRINGS, totalrings, V_HUDTRANS); + ST_DrawNumFromHud(HUD_SS_TOTALRINGS, ssspheres, V_HUDTRANS); else if (cv_timetic.value == 2) - V_DrawTallNum(hudinfo[HUD_RINGSNUMTICS].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUMTICS].f|V_PERPLAYER|V_HUDTRANS, totalrings); + V_DrawTallNum(hudinfo[HUD_RINGSNUMTICS].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUMTICS].f|V_PERPLAYER|V_HUDTRANS, ssspheres); else - V_DrawTallNum(hudinfo[HUD_RINGSNUM].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUM].f|V_PERPLAYER|V_HUDTRANS, totalrings); + V_DrawTallNum(hudinfo[HUD_RINGSNUM].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUM].f|V_PERPLAYER|V_HUDTRANS, ssspheres); } - if (leveltime < 5*TICRATE && totalrings > 0) + if (leveltime < 5*TICRATE && ssspheres > 0) { ST_DrawPatchFromHud(HUD_GETRINGS, getall, V_HUDTRANS); - ST_DrawNumFromHud(HUD_GETRINGSNUM, totalrings, V_HUDTRANS); + ST_DrawNumFromHud(HUD_GETRINGSNUM, ssspheres, V_HUDTRANS); } if (sstimer) @@ -2095,7 +2141,7 @@ static void ST_drawSpecialStageHUD(void) } else ST_DrawPatchFromHud(HUD_TIMEUP, timeup, V_HUDTRANS); -} +}*/ static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offset) { @@ -2231,7 +2277,7 @@ static void ST_overlayDrawer(void) //hu_showscores = auto hide score/time/rings when tab rankings are shown if (!(hu_showscores && (netgame || multiplayer))) { - if (maptol & TOL_NIGHTS) + if (maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap)) ST_drawNiGHTSHUD(); else { @@ -2340,10 +2386,6 @@ static void ST_overlayDrawer(void) if (gametype == GT_RACE || gametype == GT_COMPETITION) ST_drawRaceHUD(); - // Special Stage HUD - if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayer]) - ST_drawSpecialStageHUD(); - // Emerald Hunt Indicators if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER)) ST_doItemFinderIconsAndSound(); @@ -2362,15 +2404,18 @@ static void ST_overlayDrawer(void) } // This is where we draw all the fun cheese if you have the chasecam off! - if ((stplyr == &players[displayplayer] && !camera.chase) - || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)) + if (!(maptol & TOL_NIGHTS)) { - ST_drawFirstPersonHUD(); - if (cv_powerupdisplay.value) + if ((stplyr == &players[displayplayer] && !camera.chase) + || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)) + { + ST_drawFirstPersonHUD(); + if (cv_powerupdisplay.value) + ST_drawPowerupHUD(); + } + else if (cv_powerupdisplay.value == 2) ST_drawPowerupHUD(); } - else if (cv_powerupdisplay.value == 2) - ST_drawPowerupHUD(); } #ifdef HAVE_BLUA diff --git a/src/y_inter.c b/src/y_inter.c index ed9cc4185..2194dc96f 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -78,7 +78,7 @@ typedef union struct { char passed1[29]; // KNUCKLES GOT / CRAWLA HONCHO - char passed2[17]; // A CHAOS EMERALD / GOT THEM ALL! + char passed2[17]; // A CHAOS EMERALD? / GOT THEM ALL! char passed3[15]; // CAN NOW BECOME char passed4[SKINNAMESIZE+7]; // SUPER CRAWLA HONCHO INT32 passedx1; @@ -315,6 +315,8 @@ void Y_IntermissionDrawer(void) INT32 xoffset1 = 0; // Line 1 x offset INT32 xoffset2 = 0; // Line 2 x offset INT32 xoffset3 = 0; // Line 3 x offset + INT32 xoffset4 = 0; // Bonus line x offset + INT32 xoffset5 = 0; // Score line x offset UINT8 drawsection = 0; if (gottoken) // first to be behind everything else @@ -324,28 +326,40 @@ void Y_IntermissionDrawer(void) if (intertic <= 2*TICRATE) animatetic = 0; else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0') - animatetic = intertic; + animatetic = intertic + TICRATE; - if (animatetic) + if (animatetic && intertic >= animatetic) { INT32 animatetimer = (intertic - animatetic); - if (animatetimer <= 8) + if (animatetimer <= 12) { xoffset1 = -(animatetimer * 40); xoffset2 = -((animatetimer-2) * 40); + xoffset4 = -((animatetimer-4) * 40); + xoffset5 = -((animatetimer-6) * 40); if (xoffset2 > 0) xoffset2 = 0; + if (xoffset4 > 0) xoffset4 = 0; + if (xoffset5 > 0) xoffset5 = 0; } - else if (animatetimer <= 19) + else if (animatetimer < 28) { drawsection = 1; - xoffset1 = (16-animatetimer) * 40; - xoffset2 = (18-animatetimer) * 40; - xoffset3 = (20-animatetimer) * 40; + xoffset1 = (20-animatetimer) * 40; + xoffset2 = (22-animatetimer) * 40; + xoffset3 = (24-animatetimer) * 40; + xoffset4 = (26-animatetimer) * 40; + xoffset5 = (28-animatetimer) * 40; if (xoffset1 < 0) xoffset1 = 0; if (xoffset2 < 0) xoffset2 = 0; + if (xoffset3 < 0) xoffset3 = 0; + if (xoffset4 < 0) xoffset4 = 0; } else + { drawsection = 1; + if (animatetimer == 28) + S_StartSound(NULL, sfx_s3k68); + } } if (drawsection == 1) @@ -356,39 +370,60 @@ void Y_IntermissionDrawer(void) V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3); ttheight += V_LevelNameHeight(data.spec.passed4) + 2; V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4); - } - else if (data.spec.passed1[0] != '\0') - { - ttheight = 24; - V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); - ttheight += V_LevelNameHeight(data.spec.passed2) + 2; - V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2); + + V_DrawCenteredString(BASEVIDWIDTH/2 + xoffset4, 108 - 4, 0, "\x86""50 RINGS, NO SHIELD"); + V_DrawCenteredString(BASEVIDWIDTH/2 + xoffset5, 124 - 4, 0, "\x86""PRESS ""\x82""JUMP""\x86"", THEN ""\x82""SPIN"); } else { - ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2; - V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); + if (data.spec.passed1[0] != '\0') + { + ttheight = 24; + V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); + ttheight += V_LevelNameHeight(data.spec.passed2) + 2; + V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2); + } + else + { + ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2; + V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); + } + + V_DrawScaledPatch(152 + xoffset4, 108, 0, data.spec.bonuspatch); + V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 109, 0, data.spec.bonus.points); + V_DrawScaledPatch(152 + xoffset5, 124, 0, data.spec.pscore); + V_DrawTallNum(BASEVIDWIDTH + xoffset5 - 68, 125, 0, data.spec.score); } // draw the emeralds //if (intertic & 1) { + boolean drawthistic = !(ALL7EMERALDS(emeralds) && (intertic & 1)); INT32 emeraldx = 152 - 3*28; INT32 em = (gamemap - sstage_start); - for (i = 0; i < 7; ++i) + if (em == 7) { - if ((i != em) && !(intertic & 1) && (emeralds & (1 << i))) - V_DrawScaledPatch(emeraldx, 74, 0, emeraldpics[0][i]); - emeraldx += 28; + if (!stagefailed) + { + fixed_t adjust = 2*(FINESINE(FixedAngle((intertic + 1)<<(FRACBITS-4)) & FINEMASK)); + V_DrawFixedPatch(152< (3*TICRATE)/2) { @@ -896,7 +927,7 @@ void Y_Ticker(void) if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && !demoplayback) { if (M_UpdateUnlockablesAndExtraEmblems()) - S_StartSound(NULL, sfx_ncitem); + S_StartSound(NULL, sfx_s3k68); G_SaveGameData(); } @@ -1307,6 +1338,11 @@ void Y_StartIntermission(void) else strcpy(data.spec.passed1, "YOU GOT"); strcpy(data.spec.passed2, "A CHAOS EMERALD"); + if (gamemap > (sstage_start + 5)) + { + data.spec.passed2[15] = '?'; + data.spec.passed2[16] = '\0'; + } } data.spec.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed1))/2; data.spec.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed2))/2; @@ -1857,7 +1893,7 @@ static void Y_AwardSpecialStageBonus(void) if (!playeringame[i] || players[i].lives < 1) // not active or game over Y_SetNullBonus(&players[i], &localbonus); - else if (useNightsSS) // Link instead of Score + else if (maptol & TOL_NIGHTS) // Link instead of Rings Y_SetLinkBonus(&players[i], &localbonus); else Y_SetRingBonus(&players[i], &localbonus); From 77362c45cc0d6b1371f7145daaef6a1c6dd66a82 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sun, 3 Jun 2018 18:15:20 -0400 Subject: [PATCH 150/212] Fix pausing on gme --- src/sdl/mixer_sound.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 718324591..18670649e 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -475,12 +475,24 @@ void I_ShutdownMusic(void) void I_PauseSong(INT32 handle) { (void)handle; +#ifdef HAVE_LIBGME + if (gme) + { + Mix_HookMusic(NULL, NULL); + } +#endif Mix_PauseMusic(); } void I_ResumeSong(INT32 handle) { (void)handle; +#ifdef HAVE_LIBGME + if (gme) + { + Mix_HookMusic(mix_gme, gme); + } +#endif Mix_ResumeMusic(); } From 91081a3e534ad6885bac1fae3013444f9fb2c67e Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 4 Jun 2018 22:14:01 +0200 Subject: [PATCH 151/212] Disable admin password by default --- src/d_main.c | 9 --------- src/d_netcmd.c | 9 +++++++-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index fbec5f7d8..df3398752 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1051,15 +1051,6 @@ void D_SRB2Main(void) if (M_CheckParm("-password") && M_IsNextParm()) D_SetPassword(M_GetNextParm()); - else - { - size_t z; - char junkpw[25]; - for (z = 0; z < 24; z++) - junkpw[z] = (char)(rand() & 64)+32; - junkpw[24] = '\0'; - D_SetPassword(junkpw); - } // add any files specified on the command line with -file wadfile // to the wad list diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 673d64fd8..876a38523 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2656,10 +2656,12 @@ static void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, #define BASESALT "basepasswordstorage" static UINT8 adminpassmd5[16]; +static boolean adminpasswordset = false; void D_SetPassword(const char *pw) { D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &adminpassmd5); + adminpasswordset = true; } // Remote Administration @@ -2728,6 +2730,9 @@ static void Got_Login(UINT8 **cp, INT32 playernum) READMEM(*cp, sentmd5, 16); + if (!adminpasswordset) + CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[playernum]); + if (client) return; @@ -3951,7 +3956,7 @@ static void Command_RestartAudio_f(void) I_ShutdownSound(); I_StartupSound(); I_InitMusic(); - + // These must be called or no sound and music until manually set. I_SetSfxVolume(cv_soundvolume.value); @@ -3959,7 +3964,7 @@ static void Command_RestartAudio_f(void) I_SetMIDIMusicVolume(cv_midimusicvolume.value); if (Playing()) // Gotta make sure the player is in a level P_RestoreMusic(&players[consoleplayer]); - + } /** Quits a game and returns to the title screen. From c389c0b3dc5fb285f5492474f1c93b62c6336b7a Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 4 Jun 2018 22:30:27 +0200 Subject: [PATCH 152/212] xd --- src/d_netcmd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 876a38523..727d5eff4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2731,7 +2731,10 @@ static void Got_Login(UINT8 **cp, INT32 playernum) READMEM(*cp, sentmd5, 16); if (!adminpasswordset) + { CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[playernum]); + return; + } if (client) return; From 3725203bcd5537167ddf8f62c85438a9e6573459 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 5 Jun 2018 17:22:28 +0100 Subject: [PATCH 153/212] Bit of a random one today, but the branch approaches completion... * Bomb sphere! Paraloopable hazard. Replaces MT_SPECIALSPIKEBALL. * Blueberry bushes, both normal and Xmas, from patch.dta. * BSZ tulips, also from patch.dta! * Frozen Hillside badniks - Penguinator and Pophat. * Frozen Hillside ice decoration! * Fixed some big bugs with the DSZ light beams. * Made multi-mare special stages work, in a troll way - the Chaos Emerald disappears in a puff of smoke, and the Spinbobert laughter sound plays... >:3c * Reverted the mobjtype number changes from the source SOC/Lua, which we can do later when doing a final pass of the levels. * State optimisation. * Serious cruft-removal of the NiGHTS drone thinker. * Fix the issues where the player wouldn't curl into jump in waterslides or dropping off rope-hangs. * Tweak NiGHTS player flashing. * Add text colour support to the titlecard font. * Use that to make the PRESS SPIN\nMID-JUMP thing when you get all Chaos Emeralds use the titlecard font for readability. * Fix the GOT ALL EMERALDS page not lasting the correct, extended amount of time. * Fix that thing where flying mid-spin didn't enact autobrake. * Modify graymap a little on Sryder's suggestion. * [COMPLETELY UNRELATED] fix that thing where the addons menu will fail on files/paths with spaces in [/COMPLETELY UNRELATED] --- src/console.c | 2 +- src/dehacked.c | 57 ++++-- src/hardware/hw_light.c | 12 +- src/info.c | 385 +++++++++++++++++++++++++++++++--------- src/info.h | 69 +++++-- src/m_menu.c | 2 +- src/p_enemy.c | 21 ++- src/p_inter.c | 62 ++++--- src/p_mobj.c | 176 ++++++++---------- src/p_setup.c | 3 +- src/p_spec.c | 1 - src/p_user.c | 39 ++-- src/sounds.c | 8 +- src/st_stuff.c | 3 +- src/v_video.c | 62 ++++--- src/y_inter.c | 99 ++++++----- 16 files changed, 656 insertions(+), 345 deletions(-) diff --git a/src/console.c b/src/console.c index b785aa18a..9bc01cf19 100644 --- a/src/console.c +++ b/src/console.c @@ -312,7 +312,7 @@ static void CON_SetupColormaps(void) colset(lgreenmap, 97, 98, 106); colset(bluemap, 146, 147, 155); colset(redmap, 210, 32, 39); - colset(graymap, 8, 10, 15); + colset(graymap, 6, 8, 14); colset(orangemap, 51, 52, 57); colset(skymap, 129, 130, 133); colset(purplemap, 160, 161, 163); diff --git a/src/dehacked.c b/src/dehacked.c index ca17614ed..6b38ceb40 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3853,13 +3853,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_UNIDUS_BALL", // Boss Explosion - "S_BPLD1", - "S_BPLD2", - "S_BPLD3", - "S_BPLD4", - "S_BPLD5", - "S_BPLD6", - "S_BPLD7", + "S_BOSSEXPLODE", // S3&K Boss Explosion "S_SONIC3KBOSSEXPLOSION1", @@ -4368,6 +4362,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BLUESPHEREBONUS", "S_BLUESPHERESPARK", + // Bomb Sphere + "S_BOMBSPHERE1", + "S_BOMBSPHERE2", + "S_BOMBSPHERE3", + "S_BOMBSPHERE4", + // NiGHTS Chip "S_NIGHTSCHIP", "S_NIGHTSCHIPBONUS", @@ -4720,18 +4720,14 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ARROWBONK", // Trapgoyle Demon fire - "S_DEMONFIRE1", - "S_DEMONFIRE2", - "S_DEMONFIRE3", - "S_DEMONFIRE4", - "S_DEMONFIRE5", - "S_DEMONFIRE6", + "S_DEMONFIRE", // GFZ flowers "S_GFZFLOWERA", "S_GFZFLOWERB", "S_GFZFLOWERC", + "S_BLUEBERRYBUSH", "S_BERRYBUSH", "S_BUSH", @@ -5016,8 +5012,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_LAMPPOST2", // with snow "S_HANGSTAR", // Xmas GFZ bushes + "S_XMASBLUEBERRYBUSH", "S_XMASBERRYBUSH", "S_XMASBUSH", + // FHZ + "S_FHZICE1", + "S_FHZICE2", // Halloween Scenery // Pumpkins @@ -6070,6 +6070,22 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Secret badniks and hazards, shhhh + "S_PENGUINATOR_LOOK", + "S_PENGUINATOR_WADDLE1", + "S_PENGUINATOR_WADDLE2", + "S_PENGUINATOR_WADDLE3", + "S_PENGUINATOR_WADDLE4", + "S_PENGUINATOR_SLIDE1", + "S_PENGUINATOR_SLIDE2", + "S_PENGUINATOR_SLIDE3", + "S_PENGUINATOR_SLIDE4", + "S_PENGUINATOR_SLIDE5", + + "S_POPHAT_LOOK", + "S_POPHAT_SHOOT1", + "S_POPHAT_SHOOT2", + "S_POPHAT_SHOOT3", + "S_HIVEELEMENTAL_LOOK", "S_HIVEELEMENTAL_PREPARE1", "S_HIVEELEMENTAL_PREPARE2", @@ -6344,7 +6360,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Collectible Items "MT_RING", "MT_FLINGRING", // Lost ring - "MT_BLUESPHERE", // Blue sphere replacement for special stages + "MT_BLUESPHERE", // Blue sphere for special stages + "MT_BOMBSPHERE", "MT_REDTEAMRING", //Rings collectable by red team. "MT_BLUETEAMRING", //Rings collectable by blue team. "MT_TOKEN", // Special Stage Token @@ -6382,7 +6399,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BUBBLES", // Bubble source "MT_SIGN", // Level end sign "MT_SPIKEBALL", // Spike Ball - "MT_SPECIALSPIKEBALL", "MT_SPINFIRE", "MT_SPIKE", "MT_WALLSPIKE", @@ -6475,8 +6491,11 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_GFZFLOWER1", "MT_GFZFLOWER2", "MT_GFZFLOWER3", + + "MT_BLUEBERRYBUSH", "MT_BERRYBUSH", "MT_BUSH", + // Trees (both GFZ and misc) "MT_GFZTREE", "MT_GFZBERRYTREE", @@ -6601,8 +6620,12 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_LAMPPOST2", // with snow "MT_HANGSTAR", // Xmas GFZ bushes + "MT_XMASBLUEBERRYBUSH", "MT_XMASBERRYBUSH", "MT_XMASBUSH", + // FHZ + "MT_FHZICE1", + "MT_FHZICE2", // Halloween Scenery // Pumpkins @@ -6814,6 +6837,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SHLEEP", // almost-decorative sleeping enemy // Secret badniks and hazards, shhhh + "MT_PENGUINATOR", + "MT_POPHAT", + "MT_POPSHOT", + "MT_HIVEELEMENTAL", "MT_BUMBLEBORE", diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index aee6f9396..dfb2c4351 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -294,6 +294,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_FWR4 &lspr[NOLIGHT], // SPR_BUS1 &lspr[NOLIGHT], // SPR_BUS2 + &lspr[NOLIGHT], // SPR_BUS3 // Trees (both GFZ and misc) &lspr[NOLIGHT], // SPR_TRE1 &lspr[NOLIGHT], // SPR_TRE2 @@ -357,6 +358,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_XMS3 &lspr[NOLIGHT], // SPR_XMS4 &lspr[NOLIGHT], // SPR_XMS5 + &lspr[NOLIGHT], // SPR_FHZI // Halloween Scenery &lspr[RINGLIGHT_L], // SPR_PUMK @@ -368,7 +370,13 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_BSZ1 &lspr[NOLIGHT], // SPR_BSZ2 &lspr[NOLIGHT], // SPR_BSZ3 - &lspr[NOLIGHT], // SPR_BSZ4 + //&lspr[NOLIGHT], -- SPR_BSZ4 + &lspr[NOLIGHT], // SPR_BST1 + &lspr[NOLIGHT], // SPR_BST2 + &lspr[NOLIGHT], // SPR_BST3 + &lspr[NOLIGHT], // SPR_BST4 + &lspr[NOLIGHT], // SPR_BST5 + &lspr[NOLIGHT], // SPR_BST6 &lspr[NOLIGHT], // SPR_BSZ5 &lspr[NOLIGHT], // SPR_BSZ6 &lspr[NOLIGHT], // SPR_BSZ7 @@ -506,6 +514,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_SHLP // Secret badniks and hazards, shhhh + &lspr[NOLIGHT], // SPR_PENG + &lspr[NOLIGHT], // SPR_POPH, &lspr[NOLIGHT], // SPR_HIVE &lspr[NOLIGHT], // SPR_BUMB, &lspr[NOLIGHT], // SPR_BBUZ diff --git a/src/info.c b/src/info.c index f02fba8d2..dbbe54de9 100644 --- a/src/info.c +++ b/src/info.c @@ -183,6 +183,7 @@ char sprnames[NUMSPRITES + 1][5] = "FWR4", "BUS1", // GFZ Bush w/ berries "BUS2", // GFZ Bush w/o berries + "BUS3", // GFZ Bush w/ BLUE berries // Trees (both GFZ and misc) "TRE1", // GFZ "TRE2", // Checker @@ -251,6 +252,7 @@ char sprnames[NUMSPRITES + 1][5] = "XMS3", // Snowman "XMS4", // Lamppost "XMS5", // Hanging Star + "FHZI", // FHZ ice // Halloween Scenery "PUMK", // Pumpkins @@ -262,7 +264,13 @@ char sprnames[NUMSPRITES + 1][5] = "BSZ1", // Tall flowers "BSZ2", // Medium flowers "BSZ3", // Small flowers - "BSZ4", // Tulip + //"BSZ4", -- Tulips + "BST1", // Red tulip + "BST2", // Purple tulip + "BST3", // Blue tulip + "BST4", // Cyan tulip + "BST5", // Yellow tulip + "BST6", // Orange tulip "BSZ5", // Cluster of Tulips "BSZ6", // Bush "BSZ7", // Vine @@ -400,6 +408,8 @@ char sprnames[NUMSPRITES + 1][5] = "SHLP", // Shleep // Secret badniks and hazards, shhhh + "PENG", + "POPH", "HIVE", "BUMB", "BBUZ", @@ -1083,13 +1093,7 @@ state_t states[NUMSTATES] = {SPR_UNID, 1, 1, {A_UnidusBall}, 1, 0, S_UNIDUS_BALL}, // S_UNIDUS_BALL // Boss Explosion - {SPR_BOM2, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_BPLD2}, // S_BPLD1 - {SPR_BOM2, FF_FULLBRIGHT|1, 5, {NULL}, 0, 0, S_BPLD3}, // S_BPLD2 - {SPR_BOM2, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_BPLD4}, // S_BPLD3 - {SPR_BOM2, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_BPLD5}, // S_BPLD4 - {SPR_BOM2, FF_FULLBRIGHT|4, 5, {NULL}, 0, 0, S_BPLD6}, // S_BPLD5 - {SPR_BOM2, FF_FULLBRIGHT|5, 5, {NULL}, 0, 0, S_BPLD7}, // S_BPLD6 - {SPR_BOM2, FF_FULLBRIGHT|6, 5, {NULL}, 0, 0, S_NULL}, // S_BPLD7 + {SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE // S3&K Boss Explosion {SPR_BOM3, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION2}, // S_SONIC3KBOSSEXPLOSION1 @@ -1597,9 +1601,15 @@ state_t states[NUMSTATES] = // Blue Sphere for special stages {SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE - {SPR_SPHR, FF_FULLBRIGHT|FF_RANDOMANIM|FF_ANIMATE, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS + {SPR_SPHR, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS {SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK + // Bomb Sphere + {SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2}, // S_BOMBSPHERE1 + {SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3}, // S_BOMBSPHERE2 + {SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4}, // S_BOMBSPHERE3 + {SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1}, // S_BOMBSPHERE4 + // NiGHTS Chip {SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIP {SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIPBONUS @@ -1946,20 +1956,16 @@ state_t states[NUMSTATES] = {SPR_AROW, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ARROW {SPR_AROW, FF_ANIMATE, TICRATE, {A_ArrowBonks}, 7, 2, S_NULL}, // S_ARROWBONK - {SPR_CFIR, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DEMONFIRE2}, // S_DEMONFIRE1 - {SPR_CFIR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEMONFIRE3}, // S_DEMONFIRE2 - {SPR_CFIR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEMONFIRE4}, // S_DEMONFIRE3 - {SPR_CFIR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_DEMONFIRE5}, // S_DEMONFIRE4 - {SPR_CFIR, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_DEMONFIRE6}, // S_DEMONFIRE5 - {SPR_CFIR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_DEMONFIRE1}, // S_DEMONFIRE6 + {SPR_CFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 5, 2, S_NULL}, // S_DEMONFIRE // GFZ flowers {SPR_FWR1, FF_ANIMATE, -1, {NULL}, 7, 3, S_NULL}, // S_GFZFLOWERA {SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL}, // S_GFZFLOWERB {SPR_FWR3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_GFZFLOWERC - {SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BERRYBUSH - {SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSH + {SPR_BUS3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEBERRYBUSH + {SPR_BUS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BERRYBUSH + {SPR_BUS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BUSH // Trees {SPR_TRE1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GFZTREE @@ -2257,8 +2263,12 @@ state_t states[NUMSTATES] = {SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST2 {SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HANGSTAR // Xmas GFZ bushes + {SPR_BUS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBLUEBERRYBUSH {SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBERRYBUSH {SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBUSH + // FHZ + {SPR_FHZI, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE1 + {SPR_FHZI, 1, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE2 // Halloween Scenery // Pumpkins @@ -2324,12 +2334,12 @@ state_t states[NUMSTATES] = {SPR_BSZ3, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_CYAN {SPR_BSZ3, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_YELLOW {SPR_BSZ3, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZSHORTFLOWER_ORANGE - {SPR_BSZ4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTULIP_RED - {SPR_BSZ4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTULIP_PURPLE - {SPR_BSZ4, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTULIP_BLUE - {SPR_BSZ4, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTULIP_CYAN - {SPR_BSZ4, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTULIP_YELLOW - {SPR_BSZ4, 5, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTULIP_ORANGE + {SPR_BST1, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_RED + {SPR_BST2, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_PURPLE + {SPR_BST3, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_BLUE + {SPR_BST4, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_CYAN + {SPR_BST5, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_YELLOW + {SPR_BST6, FF_ANIMATE, -1, {NULL}, 11, 4, S_NULL}, // S_BSZTULIP_ORANGE {SPR_BSZ5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_RED {SPR_BSZ5, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_PURPLE {SPR_BSZ5, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BSZCLUSTER_BLUE @@ -3366,6 +3376,22 @@ state_t states[NUMSTATES] = {SPR_SHLP, 3, 400, {A_SetObjectFlags}, MF_SLIDEME|MF_ENEMY|MF_BOUNCE|MF_NOCLIP|MF_NOCLIPHEIGHT, 0, S_NULL}, // S_SHLEEPBOUNCE3 // Secret badniks and hazards, shhhh + {SPR_PENG, 0, 2, {A_Look}, 0, 0, S_PENGUINATOR_LOOK}, // S_PENGUINATOR_LOOK + {SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE2}, // S_PENGUINATOR_WADDLE1 + {SPR_PENG, 1, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE3}, // S_PENGUINATOR_WADDLE2 + {SPR_PENG, 0, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE4}, // S_PENGUINATOR_WADDLE3 + {SPR_PENG, 2, 2, {A_Chase}, 0, 0, S_PENGUINATOR_WADDLE1}, // S_PENGUINATOR_WADDLE4 + {SPR_PENG, 0, 0, {A_FaceTarget}, 0, 0, S_PENGUINATOR_SLIDE2}, // S_PENGUINATOR_SLIDE1 + {SPR_PENG, 3, 5, {A_BunnyHop}, 4, 10, S_PENGUINATOR_SLIDE3}, // S_PENGUINATOR_SLIDE2 + {SPR_PENG, 4, 90, {A_PlayAttackSound}, 0, 0, S_PENGUINATOR_SLIDE4}, // S_PENGUINATOR_SLIDE3 + {SPR_PENG, 3, 5, {A_Thrust}, 0, 1, S_PENGUINATOR_SLIDE5}, // S_PENGUINATOR_SLIDE4 + {SPR_PENG, 0, 5, {A_FaceTarget}, 0, 0, S_PENGUINATOR_LOOK}, // S_PENGUINATOR_SLIDE5 + + {SPR_POPH, 0, 2, {A_Look}, (2048<<16)|1, 0, S_POPHAT_LOOK}, // S_POPHAT_LOOK + {SPR_POPH, 1, 2, {A_LobShot}, MT_POPSHOT, (70<<16)|60, S_POPHAT_SHOOT2}, // S_POPHAT_SHOOT1 + {SPR_POPH, 2, 1, {NULL}, 0, 0, S_POPHAT_SHOOT3}, // S_POPHAT_SHOOT2 + {SPR_POPH, 0, 57, {NULL}, 0, 0, S_POPHAT_LOOK}, // S_POPHAT_SHOOT3 + {SPR_HIVE, 0, 5, {A_Look}, 1, 1, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_LOOK {SPR_HIVE, 0, 14, {A_PlaySound}, sfx_s3k76, 1, S_HIVEELEMENTAL_PREPARE2}, // S_HIVEELEMENTAL_PREPARE1 {SPR_HIVE, 0, 6, {A_PlaySound}, sfx_s3k8c, 1, S_HIVEELEMENTAL_SHOOT1}, // S_HIVEELEMENTAL_PREPARE2 @@ -3513,22 +3539,22 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN - {SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEA}, // S_ROCKCRUMBLEA - {SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEB}, // S_ROCKCRUMBLEB - {SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEC}, // S_ROCKCRUMBLEC - {SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLED}, // S_ROCKCRUMBLED - {SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEE}, // S_ROCKCRUMBLEE - {SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEF}, // S_ROCKCRUMBLEF - {SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEG}, // S_ROCKCRUMBLEG - {SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEH}, // S_ROCKCRUMBLEH - {SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEI}, // S_ROCKCRUMBLEI - {SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEJ}, // S_ROCKCRUMBLEJ - {SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEK}, // S_ROCKCRUMBLEK - {SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEL}, // S_ROCKCRUMBLEL - {SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEM}, // S_ROCKCRUMBLEM - {SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEN}, // S_ROCKCRUMBLEN - {SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEO}, // S_ROCKCRUMBLEO - {SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_ROCKCRUMBLEP}, // S_ROCKCRUMBLEP + {SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEA + {SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEB + {SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEC + {SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLED + {SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEE + {SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEF + {SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEG + {SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEH + {SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEI + {SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEJ + {SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEK + {SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEL + {SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEM + {SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEN + {SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEO + {SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEP #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK @@ -4024,7 +4050,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CRUSHSTACEAN - 126, // doomednum + 610, //126, // doomednum S_CRUSHSTACEAN_ROAM1, // spawnstate 1, // spawnhealth S_NULL, // seestate @@ -4538,7 +4564,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_BOSSEXPLODE -1, // doomednum - S_BPLD1, // spawnstate + S_BOSSEXPLODE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -5143,7 +5169,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_BPLD1, // deathstate + S_BOSSEXPLODE, // deathstate S_NULL, // xdeathstate sfx_cybdth, // deathsound 48*FRACUNIT, // speed @@ -5278,7 +5304,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_BPLD1, // deathstate + S_BOSSEXPLODE, // deathstate S_NULL, // xdeathstate sfx_bexpld, // deathsound 10*FRACUNIT, // speed @@ -5440,7 +5466,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_BPLD1, // deathstate + S_BOSSEXPLODE, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 10*FRACUNIT, // speed @@ -5467,7 +5493,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_BPLD1, // deathstate + S_BOSSEXPLODE, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 10*FRACUNIT, // speed @@ -5779,6 +5805,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_BLUESPHEREBONUS // raisestate }, + { // MT_BOMBSPHERE + 520, // doomednum + S_BOMBSPHERE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + MT_NULL, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BOSSEXPLODE, // deathstate + S_NULL, // xdeathstate + sfx_cybdth, // deathsound + 38*FRACUNIT, // speed + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_REDTEAMRING 308, // doomednum S_TEAMRING, // spawnstate @@ -6637,33 +6690,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_SPECIALSPIKEBALL - 521, // doomednum - S_SPIKEBALL1, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // 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 - 10*FRACUNIT, // speed - 12*FRACUNIT, // radius - 24*FRACUNIT, // height - 0, // display offset - 100, // mass - 1, // damage - sfx_None, // activesound - MF_SPECIAL|MF_NOGRAVITY, // flags - S_NULL // raisestate - }, - { // MT_SPINFIRE -1, // doomednum S_SPINFIRE1, // spawnstate @@ -8664,7 +8690,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_DEMONFIRE -1, // doomednum - S_DEMONFIRE1, // spawnstate + S_DEMONFIRE, // spawnstate 1, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8770,6 +8796,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BLUEBERRYBUSH + 803, // doomednum + S_BLUEBERRYBUSH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_BERRYBUSH 804, // doomednum S_BERRYBUSH, // spawnstate @@ -9311,7 +9364,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIGGARGOYLE - 1011, // doomednum + 1009, // doomednum S_BIGGARGOYLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9581,7 +9634,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_DSZ2STALAGMITE - 1009, // doomednum + 999, // doomednum S_DSZ2STALAGMITE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9630,7 +9683,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -11524,6 +11577,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_XMASBLUEBERRYBUSH + 1859, // doomednum + S_XMASBLUEBERRYBUSH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_XMASBERRYBUSH 1857, // doomednum S_XMASBERRYBUSH, // spawnstate @@ -11578,6 +11658,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_FHZICE1 + 4028, // doomednum + S_FHZICE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_FHZICE2 + 4029, // doomednum + S_FHZICE1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 8*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_JACKO1 3520, // doomednum S_JACKO1, // spawnstate @@ -12387,7 +12521,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -12414,7 +12548,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -12441,7 +12575,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -12468,7 +12602,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -12495,7 +12629,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -12522,7 +12656,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -14457,9 +14591,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_ORBITEM1, // meleestate S_ORBIDYA1, // missilestate - S_NULL, // deathstate + S_XPLD1, // deathstate S_NULL, // xdeathstate - sfx_None, // deathsound + sfx_s3k8a, // deathsound 8, // speed 8*FRACUNIT, // radius 16*FRACUNIT, // height @@ -16454,7 +16588,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_SHLEEP 1601, // doomednum S_SHLEEP1, // spawnstate - 1, // spawnhealth + 1, // spawnhealth S_NULL, // seestate sfx_None, // seesound 0, // reactiontime @@ -16478,6 +16612,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_PENGUINATOR + 2017, // doomednum + S_PENGUINATOR_LOOK, // spawnstate + 1, // spawnhealth + S_PENGUINATOR_WADDLE1, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_s3k8a, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_PENGUINATOR_SLIDE1, // meleestate + S_PENGUINATOR_SLIDE1, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 5, // speed + 24*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_SLIDEME, // flags + S_NULL // raisestate + }, + + { // MT_POPHAT + 2018, // doomednum -- happy anniversary! + S_POPHAT_LOOK, // spawnstate + 1, // spawnhealth + S_POPHAT_SHOOT1, // seestate + sfx_None, // seesound + 1, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY, // flags + S_NULL // raisestate + }, + + { // MT_POPSHOT + -1, // doomednum + S_ROCKCRUMBLEI, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_cannon, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD1, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_MISSILE, // flags + S_NULL // raisestate + }, + { // MT_HIVEELEMENTAL 3190, // doomednum S_HIVEELEMENTAL_LOOK, // spawnstate diff --git a/src/info.h b/src/info.h index 4e316efdb..5b1169e22 100644 --- a/src/info.h +++ b/src/info.h @@ -402,6 +402,7 @@ typedef enum sprite SPR_FWR4, SPR_BUS1, // GFZ Bush w/ berries SPR_BUS2, // GFZ Bush w/o berries + SPR_BUS3, // GFZ Bush w/ BLUE berries // Trees (both GFZ and misc) SPR_TRE1, // GFZ SPR_TRE2, // Checker @@ -470,6 +471,7 @@ typedef enum sprite SPR_XMS3, // Snowman SPR_XMS4, // Lamppost SPR_XMS5, // Hanging Star + SPR_FHZI, // FHZ Ice // Halloween Scenery SPR_PUMK, // Pumpkins @@ -481,7 +483,13 @@ typedef enum sprite SPR_BSZ1, // Tall flowers SPR_BSZ2, // Medium flowers SPR_BSZ3, // Small flowers - SPR_BSZ4, // Tulip + //SPR_BSZ4, -- Tulips + SPR_BST1, // Red tulip + SPR_BST2, // Purple tulip + SPR_BST3, // Blue tulip + SPR_BST4, // Cyan tulip + SPR_BST5, // Yellow tulip + SPR_BST6, // Orange tulip SPR_BSZ5, // Cluster of Tulips SPR_BSZ6, // Bush SPR_BSZ7, // Vine @@ -619,6 +627,8 @@ typedef enum sprite SPR_SHLP, // Shleep // Secret badniks and hazards, shhhh + SPR_PENG, + SPR_POPH, SPR_HIVE, SPR_BUMB, SPR_BBUZ, @@ -1210,13 +1220,7 @@ typedef enum state S_UNIDUS_BALL, // Boss Explosion - S_BPLD1, - S_BPLD2, - S_BPLD3, - S_BPLD4, - S_BPLD5, - S_BPLD6, - S_BPLD7, + S_BOSSEXPLODE, // S3&K Boss Explosion S_SONIC3KBOSSEXPLOSION1, @@ -1725,6 +1729,12 @@ typedef enum state S_BLUESPHEREBONUS, S_BLUESPHERESPARK, + // Bomb Sphere + S_BOMBSPHERE1, + S_BOMBSPHERE2, + S_BOMBSPHERE3, + S_BOMBSPHERE4, + // NiGHTS Chip S_NIGHTSCHIP, S_NIGHTSCHIPBONUS, @@ -2074,18 +2084,14 @@ typedef enum state S_ARROWBONK, // Trapgoyle Demon fire - S_DEMONFIRE1, - S_DEMONFIRE2, - S_DEMONFIRE3, - S_DEMONFIRE4, - S_DEMONFIRE5, - S_DEMONFIRE6, + S_DEMONFIRE, // GFZ flowers S_GFZFLOWERA, S_GFZFLOWERB, S_GFZFLOWERC, + S_BLUEBERRYBUSH, S_BERRYBUSH, S_BUSH, @@ -2370,8 +2376,12 @@ typedef enum state S_LAMPPOST2, // with snow S_HANGSTAR, // Xmas GFZ bushes + S_XMASBLUEBERRYBUSH, S_XMASBERRYBUSH, S_XMASBUSH, + // FHZ + S_FHZICE1, + S_FHZICE2, // Halloween Scenery // Pumpkins @@ -3423,6 +3433,22 @@ typedef enum state S_SHLEEPBOUNCE3, // Secret badniks and hazards, shhhh + S_PENGUINATOR_LOOK, + S_PENGUINATOR_WADDLE1, + S_PENGUINATOR_WADDLE2, + S_PENGUINATOR_WADDLE3, + S_PENGUINATOR_WADDLE4, + S_PENGUINATOR_SLIDE1, + S_PENGUINATOR_SLIDE2, + S_PENGUINATOR_SLIDE3, + S_PENGUINATOR_SLIDE4, + S_PENGUINATOR_SLIDE5, + + S_POPHAT_LOOK, + S_POPHAT_SHOOT1, + S_POPHAT_SHOOT2, + S_POPHAT_SHOOT3, + S_HIVEELEMENTAL_LOOK, S_HIVEELEMENTAL_PREPARE1, S_HIVEELEMENTAL_PREPARE2, @@ -3717,7 +3743,8 @@ typedef enum mobj_type // Collectible Items MT_RING, MT_FLINGRING, // Lost ring - MT_BLUESPHERE, // Blue sphere replacement for special stages + MT_BLUESPHERE, // Blue sphere for special stages + MT_BOMBSPHERE, MT_REDTEAMRING, //Rings collectable by red team. MT_BLUETEAMRING, //Rings collectable by blue team. MT_TOKEN, // Special Stage token for special stage @@ -3755,7 +3782,6 @@ typedef enum mobj_type MT_BUBBLES, // Bubble source MT_SIGN, // Level end sign MT_SPIKEBALL, // Spike Ball - MT_SPECIALSPIKEBALL, MT_SPINFIRE, MT_SPIKE, MT_WALLSPIKE, @@ -3848,8 +3874,11 @@ typedef enum mobj_type MT_GFZFLOWER1, MT_GFZFLOWER2, MT_GFZFLOWER3, + + MT_BLUEBERRYBUSH, MT_BERRYBUSH, MT_BUSH, + // Trees (both GFZ and misc) MT_GFZTREE, MT_GFZBERRYTREE, @@ -3974,8 +4003,12 @@ typedef enum mobj_type MT_LAMPPOST2, // with snow MT_HANGSTAR, // Xmas GFZ bushes + MT_XMASBLUEBERRYBUSH, MT_XMASBERRYBUSH, MT_XMASBUSH, + // FHZ + MT_FHZICE1, + MT_FHZICE2, // Halloween Scenery // Pumpkins @@ -4187,6 +4220,10 @@ typedef enum mobj_type MT_SHLEEP, // almost-decorative sleeping enemy // Secret badniks and hazards, shhhh + MT_PENGUINATOR, + MT_POPHAT, + MT_POPSHOT, + MT_HIVEELEMENTAL, MT_BUMBLEBORE, diff --git a/src/m_menu.c b/src/m_menu.c index f10c6b653..26ab7ca3e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5222,7 +5222,7 @@ static void M_HandleAddons(INT32 choice) case EXT_SOC: case EXT_WAD: case EXT_PK3: - COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); + COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); addonsresponselimit = 5; break; default: diff --git a/src/p_enemy.c b/src/p_enemy.c index 2f1fa842e..367eec60f 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5346,7 +5346,7 @@ void A_RotateSpikeBall(mobj_t *actor) return; #endif - if (actor->type == MT_SPECIALSPIKEBALL) // don't remove this, these spikeballs share the same states as the rotating spikeballs + if (actor->type == MT_SPIKEBALL) // don't remove this, these spikeballs share the same states as the rotating spikeballs return; if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen. @@ -11323,21 +11323,20 @@ void A_LightBeamReset(mobj_t *actor) return; #endif - P_SetScale(actor, FRACUNIT + P_SignedRandom()*FRACUNIT/256); - actor->destscale = actor->scale; + actor->destscale = FRACUNIT + P_SignedRandom()*FRACUNIT/256; + P_SetScale(actor, actor->destscale); if (!actor->spawnpoint) return; // this can't work properly welp - actor->momx = P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; - actor->momy = P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/128; - actor->momz = P_SignedRandom()*FRACUNIT/128; + actor->momx = -(P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128; + actor->momy = (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128; + actor->momz = (P_SignedRandom()*FRACUNIT)/128; - P_UnsetThingPosition(actor); - actor->x = actor->spawnpoint->x*FRACUNIT + P_SignedRandom()*FINECOSINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; - actor->y = actor->spawnpoint->y*FRACUNIT + P_SignedRandom()*FINESINE((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT)/2; - actor->z = actor->spawnpoint->z*FRACUNIT + P_SignedRandom()*FRACUNIT/2; - P_SetThingPosition(actor); + P_TeleportMove(actor, + actor->spawnpoint->x*FRACUNIT - (P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2, + actor->spawnpoint->y*FRACUNIT + (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2, + actor->spawnpoint->z*FRACUNIT + (P_SignedRandom()*FRACUNIT)/2); } // Function: A_MineExplode diff --git a/src/p_inter.c b/src/p_inter.c index 33a5abcd2..f3fb5f6e1 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -474,7 +474,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_FLINGRING: case MT_COIN: case MT_FLINGCOIN: - if (!(P_CanPickupItem(player, false))) + case MT_NIGHTSSTAR: + if (!(P_CanPickupItem(player, false)) && !(special->flags2 & MF2_NIGHTSPULL)) return; special->momx = special->momy = special->momz = 0; @@ -484,39 +485,31 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_DoNightsScore(player); break; case MT_BLUESPHERE: - if (!(P_CanPickupItem(player, false))) - return; - - special->momx = special->momy = special->momz = 0; - P_GivePlayerSpheres(player, 1); - - special->destscale = ((player->powers[pw_carry] == CR_NIGHTSMODE) ? 4 : 2)*special->scale; - if (states[special->info->deathstate].tics > 0) - special->scalespeed = FixedDiv(FixedDiv(special->destscale, special->scale), states[special->info->deathstate].tics<scalespeed = 4*FRACUNIT/5; - - if (maptol & TOL_NIGHTS) - P_DoNightsScore(player); - break; case MT_NIGHTSCHIP: - if (!(P_CanPickupItem(player, false))) + if (!(P_CanPickupItem(player, false)) && !(special->flags2 & MF2_NIGHTSPULL)) return; special->momx = special->momy = special->momz = 0; P_GivePlayerSpheres(player, 1); + if (special->type == MT_BLUESPHERE) + { + special->destscale = ((player->powers[pw_carry] == CR_NIGHTSMODE) ? 4 : 2)*special->scale; + if (states[special->info->deathstate].tics > 0) + special->scalespeed = FixedDiv(FixedDiv(special->destscale, special->scale), states[special->info->deathstate].tics<scalespeed = 4*FRACUNIT/5; + } + if (maptol & TOL_NIGHTS) P_DoNightsScore(player); break; - case MT_NIGHTSSTAR: - if (!(P_CanPickupItem(player, false))) + case MT_BOMBSPHERE: + if (!(P_CanPickupItem(player, false)) && !(special->flags2 & MF2_NIGHTSPULL)) return; special->momx = special->momy = special->momz = 0; - - if (maptol & TOL_NIGHTS) - P_DoNightsScore(player); + P_DamageMobj(toucher, special, special, 1, 0); break; case MT_AUTOPICKUP: case MT_BOUNCEPICKUP: @@ -755,6 +748,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_NIGHTSDRONE: { boolean spec = G_IsSpecialStage(gamemap); + boolean cangiveemmy = false; if (player->bot) return; if (player->exiting) @@ -776,7 +770,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // Well no one has an emerald, so exit anyway! } - P_GiveEmerald(false); + cangiveemmy = true; // Don't play Ideya sound in special stage mode } else @@ -815,7 +809,21 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) while ((hnext = hnext->hnext)) P_SetTarget(&hnext->target, toucher); } + return; } + + if (!cangiveemmy) + return; + + if (player->exiting) + P_GiveEmerald(false); + else if (player->mo->tracer && player->mare) + { + P_KillMobj(toucher->tracer, NULL, NULL, 0); // No emerald for you just yet! + S_StartSound(NULL, sfx_ghosty); + special->flags2 |= MF2_DONTDRAW; + } + return; } case MT_NIGHTSLOOPHELPER: @@ -922,9 +930,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } } - if (!(mo2->type == MT_RING || mo2->type == MT_COIN || mo2->type == MT_BLUESPHERE + if (!(mo2->type == MT_RING || mo2->type == MT_COIN + || mo2->type == MT_BLUESPHERE || mo2->type == MT_BOMBSPHERE || mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR - || ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL)))) + || ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL)))) continue; // Yay! The thing's in reach! Pull it in! @@ -942,6 +951,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->powers[pw_carry] == CR_NIGHTSMODE && !toucher->target) return; + if (toucher->tracer) + return; // Don't have multiple ideya + if (player->mare != special->threshold) // wrong mare return; diff --git a/src/p_mobj.c b/src/p_mobj.c index 587615448..cc28fb5a0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2133,7 +2133,7 @@ void P_XYMovement(mobj_t *mo) if (mo->flags & MF_NOCLIPHEIGHT) return; // no frictions for objects that can pass through floors - if (mo->flags & MF_MISSILE || mo->flags2 & MF2_SKULLFLY || mo->type == MT_SHELL || mo->type == MT_VULTURE) + if (mo->flags & MF_MISSILE || mo->flags2 & MF2_SKULLFLY || mo->type == MT_SHELL || mo->type == MT_VULTURE || mo->type == MT_PENGUINATOR) return; // no friction for missiles ever if (player && player->homing) // no friction for homing @@ -2514,6 +2514,7 @@ static boolean P_ZMovement(mobj_t *mo) case MT_RING: // Ignore still rings case MT_COIN: case MT_BLUESPHERE: + case MT_BOMBSPHERE: case MT_NIGHTSCHIP: case MT_NIGHTSSTAR: case MT_REDTEAMRING: @@ -7747,109 +7748,79 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_NIGHTSDRONE: + // GOAL mode? if (mobj->state >= &states[S_NIGHTSDRONE_SPARKLING1] && mobj->state <= &states[S_NIGHTSDRONE_SPARKLING16]) { - mobj->flags2 &= ~MF2_DONTDRAW; - mobj->z = mobj->floorz + mobj->height + (mobj->spawnpoint->options >> ZSHIFT) * FRACUNIT; - mobj->angle = 0; + INT32 i; + boolean bonustime = false; - if (!mobj->target) - { - mobj_t *goalpost = P_SpawnMobj(mobj->x, mobj->y, mobj->z + FRACUNIT, MT_NIGHTSGOAL); - CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n"); - goalpost->angle = mobj->angle; - P_SetTarget(&mobj->target, goalpost); - } + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) + { + bonustime = true; + break; + } - if (G_IsSpecialStage(gamemap)) - { // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime. - INT32 i; - boolean bonustime = false; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime) - { - bonustime = true; - break; - } - if (!bonustime) - { - /*mobj->flags &= ~MF_NOGRAVITY; - P_SetMobjState(mobj, S_NIGHTSDRONE1);*/ - mobj->flags2 |= MF2_DONTDRAW; - } - } - else if (mobj->tracer && mobj->tracer->player) + if (!bonustime) { - if (!(mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE)) - { - mobj->flags &= ~MF_NOGRAVITY; - mobj->flags2 &= ~MF2_DONTDRAW; - P_SetMobjState(mobj, S_NIGHTSDRONE1); - } - else if (!mobj->tracer->player->bonustime) - { - mobj->flags &= ~MF_NOGRAVITY; - P_SetMobjState(mobj, S_NIGHTSDRONE1); - } + CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); + P_RemoveMobj(mobj->target); + P_SetTarget(&mobj->target, NULL); + + mobj->flags &= ~MF_NOGRAVITY; + mobj->flags2 |= MF2_DONTDRAW; + P_SetMobjState(mobj, S_NIGHTSDRONE1); } } + // Invisible/bouncing mode. else { - if (G_IsSpecialStage(gamemap)) - { // Never show the NiGHTS drone in special stages. Check ANYONE for bonustime. - INT32 i; + INT32 i; + boolean bonustime = false; - boolean bonustime = false; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime) - { - bonustime = true; - break; - } - - if (bonustime) - { - P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1); - mobj->flags |= MF_NOGRAVITY; - } - else - { - if (mobj->target) - { - CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); - P_RemoveMobj(mobj->target); - P_SetTarget(&mobj->target, NULL); - } - mobj->flags2 |= MF2_DONTDRAW; - } - } - else if (mobj->tracer && mobj->tracer->player) - { - if (mobj->target) - { - CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); - P_RemoveMobj(mobj->target); - P_SetTarget(&mobj->target, NULL); - } - - if (mobj->tracer->player->powers[pw_carry] == CR_NIGHTSMODE) - { - if (mobj->tracer->player->bonustime) - { - P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1); - mobj->flags |= MF_NOGRAVITY; - } - else - mobj->flags2 |= MF2_DONTDRAW; - } - else // Not NiGHTS - mobj->flags2 &= ~MF2_DONTDRAW; - } + // Bouncy bouncy! mobj->angle += ANG10; if (mobj->flags2 & MF2_DONTDRAW) mobj->momz = 0; else if (mobj->z <= mobj->floorz) mobj->momz = 5*FRACUNIT; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) + { + bonustime = true; + break; + } + + if (bonustime) + { + mobj->z = mobj->floorz + mobj->height; + mobj->angle = mobj->momz = 0; + + if (mobj->spawnpoint) + mobj->z += (mobj->spawnpoint->options >> ZSHIFT)<target, P_SpawnMobjFromMobj(mobj, 0, 0, FRACUNIT, MT_NIGHTSGOAL)); + + mobj->flags2 &= ~MF2_DONTDRAW; + mobj->flags |= MF_NOGRAVITY; + P_SetMobjState(mobj, S_NIGHTSDRONE_SPARKLING1); + } + else if (!G_IsSpecialStage(gamemap)) + { + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].powers[pw_carry] != CR_NIGHTSMODE) + { + bonustime = true; // variable reuse + break; + } + + if (bonustime) + mobj->flags2 &= ~MF2_DONTDRAW; + else + mobj->flags2 |= MF2_DONTDRAW; + } } break; case MT_PLAYER: @@ -7882,6 +7853,7 @@ void P_MobjThinker(mobj_t *mobj) case MT_RING: case MT_COIN: case MT_BLUESPHERE: + case MT_BOMBSPHERE: case MT_NIGHTSCHIP: case MT_NIGHTSSTAR: case MT_REDTEAMRING: @@ -8713,6 +8685,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_EXTRALARGEBUBBLE: mobj->fuse += 30 * TICRATE; break; + case MT_NIGHTSDRONE: + if (G_IsSpecialStage(gamemap)) + mobj->flags2 |= MF2_DONTDRAW; + break; case MT_EGGCAPSULE: mobj->extravalue1 = -1; // timer for how long a player has been at the capsule break; @@ -9869,7 +9845,7 @@ void P_SpawnMapThing(mapthing_t *mthing) ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS); else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE) z = ONFLOORZ; - else if (i == MT_SPECIALSPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN) + else if (i == MT_BOMBSPHERE || i == MT_SPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN) { if (mthing->options & MTF_OBJECTFLIP) { @@ -11063,10 +11039,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) else if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) ringthing = MT_BLUESPHERE; + if (ringthing != MT_BLUESPHERE && ultimatemode) + return; // No rings in Ultimate! + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ringthing = ((ringthing == MT_BLUESPHERE) ? MT_NIGHTSCHIP : MT_NIGHTSSTAR); - else if (ringthing != MT_BLUESPHERE && ultimatemode) - return; // No rings in Ultimate! // Set proper height if (mthing->options & MTF_OBJECTFLIP) @@ -11130,10 +11107,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (mthing->type == 601) dist = 128*FRACUNIT; + if (ultimatemode) + return; // No rings in Ultimate! + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ringthing = MT_NIGHTSSTAR; - else if (ultimatemode) - return; // No rings in Ultimate! for (r = 1; r <= 5; r++) { @@ -11181,10 +11159,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (mthing->type == 603) iterations = 10; + if (ultimatemode) + return; // No rings in Ultimate! + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ringthing = MT_NIGHTSSTAR; - else if (ultimatemode) - return; // No rings in Ultimate! closestangle = FixedAngle(mthing->angle*FRACUNIT); fa = (closestangle >> ANGLETOFINESHIFT); @@ -11274,10 +11253,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) break; } + if (ringthing != MT_BLUESPHERE && ultimatemode) + continue; // No rings in Ultimate! + if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ringthing = ((ringthing == MT_BLUESPHERE) ? MT_NIGHTSCHIP : MT_NIGHTSSTAR); - else if (ringthing == MT_RING && ultimatemode) - continue; // No rings in Ultimate! fa = i*FINEANGLES/numitems; v[0] = FixedMul(FINECOSINE(fa),size); diff --git a/src/p_setup.c b/src/p_setup.c index 076c8dba7..5aedbe382 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -826,7 +826,8 @@ void P_ReloadRings(void) } continue; } - if (!(mo->type == MT_RING || mo->type == MT_COIN || mo->type == MT_BLUESPHERE + if (!(mo->type == MT_RING || mo->type == MT_COIN + || mo->type == MT_BLUESPHERE || mo->type == MT_BOMBSPHERE || mo->type == MT_NIGHTSCHIP || mo->type == MT_NIGHTSSTAR)) continue; diff --git a/src/p_spec.c b/src/p_spec.c index 2999d94ac..707f8222e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -7656,7 +7656,6 @@ void T_Pusher(pusher_t *p) thing->player->pflags |= jumped; thing->player->pflags |= PF_SLIDING; - P_SetPlayerMobjState (thing, thing->info->painstate); // Whee! thing->angle = R_PointToAngle2 (0, 0, xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR)); if (!demoplayback || P_AnalogMove(thing->player)) diff --git a/src/p_user.c b/src/p_user.c index 8d05d2b01..40d909d25 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -6953,12 +6953,17 @@ static void P_MovePlayer(player_t *player) if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->exiting || !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1] - && player->mo->state < &states[S_PLAY_NIGHTS_TRANS6]))) + && player->mo->state < &states[S_PLAY_NIGHTS_TRANS6]))) // Note the < instead of <= { skin_t *skin = ((skin_t *)(player->mo->skin)); - if (skin->flags & SF_SUPER && player->mo->color < MAXSKINCOLORS) + if (skin->flags & SF_SUPER) + { + player->mo->color = skin->supercolor + + ((player->nightstime == player->startedtime) + ? 4 + : abs((((signed)leveltime >> 1) % 9) - 4)); // This is where super flashing is handled. G_GhostAddColor(GHC_SUPER); - player->mo->color = (skin->flags & SF_SUPER) ? skin->supercolor + abs((((signed)(player->startedtime - player->nightstime) >> 1) % 9) - 4) : player->mo->color; // This is where super flashing is handled. + } } if (!player->capsule && !player->bonustime) @@ -7961,17 +7966,18 @@ static void P_DoRopeHang(player_t *player) if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope { - P_SetTarget(&player->mo->tracer, NULL); - player->pflags |= P_GetJumpFlags(player); + P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); + + P_SetTarget(&player->mo->tracer, NULL); player->powers[pw_carry] = CR_NONE; - if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED) - && !(player->panim == PA_JUMP)) - P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); return; } + if (player->mo->state-states != S_PLAY_RIDE) + P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); + // If not allowed to move, we're done here. if (!speed) return; @@ -8062,10 +8068,7 @@ static void P_DoRopeHang(player_t *player) if (player->mo->tracer->flags & MF_SLIDEME) { player->pflags |= P_GetJumpFlags(player); - - if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED) - && !(player->panim == PA_JUMP)) - P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); + P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); } P_SetTarget(&player->mo->tracer, NULL); @@ -9737,7 +9740,8 @@ void P_PlayerThink(player_t *player) mo2 = (mobj_t *)th; - if (!(mo2->type == MT_RING || mo2->type == MT_COIN || mo2->type == MT_BLUESPHERE + if (!(mo2->type == MT_RING || mo2->type == MT_COIN + || mo2->type == MT_BLUESPHERE || mo2->type == MT_BOMBSPHERE || mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR)) continue; @@ -9774,8 +9778,6 @@ void P_PlayerThink(player_t *player) ticmiss++; P_DoRopeHang(player); - if (player->mo->state-states != S_PLAY_RIDE) - P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); P_DoJumpStuff(player, &player->cmd); } else //if (player->powers[pw_carry] == CR_ZOOMTUBE) @@ -9891,7 +9893,8 @@ void P_PlayerThink(player_t *player) if (!player->powers[pw_carry] && ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) && !(cmd->forwardmove || cmd->sidemove) - && (player->rmomx || player->rmomy)) + && (player->rmomx || player->rmomy) + && (!player->capsule || (player->capsule->reactiontime != (player-players)+1))) { fixed_t acceleration = (player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration) * player->thrustfactor * 20; angle_t moveAngle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); @@ -9913,7 +9916,7 @@ void P_PlayerThink(player_t *player) || player->climbing || player->pflags & (PF_SPINNING|PF_SLIDING)) player->pflags &= ~PF_APPLYAUTOBRAKE; - else if (currentlyonground) + else if (currentlyonground || player->powers[pw_tailsfly]) player->pflags |= PF_APPLYAUTOBRAKE; } } @@ -10345,7 +10348,7 @@ void P_PlayerAfterThink(player_t *player) if (P_IsLocalPlayer(player) && (player->pflags & PF_WPNDOWN) && player->currentweapon != oldweapon) S_StartSound(NULL, sfx_wepchg); - if (player->pflags & PF_SLIDING) + if ((player->pflags & PF_SLIDING) && ((player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE)) != PF_JUMPED)) P_SetPlayerMobjState(player->mo, player->mo->info->painstate); /* if (player->powers[pw_carry] == CR_NONE && player->mo->tracer && !player->homing) diff --git a/src/sounds.c b/src/sounds.c index 4070839ab..5b9f83e15 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -143,12 +143,12 @@ sfxinfo_t S_sfx[NUMSFX] = {"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"}, {"cgot" , true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Emerald"}, // Got Emerald! Tails 09-02-2001 {"cybdth", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Explosion"}, - {"deton", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous beeping"}, + {"deton", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Threatening beeping"}, {"ding", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Ding"}, {"dmpain", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machine damage"}, {"drown", false, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drowning"}, {"fizzle", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Electric fizzle"}, - {"gbeep", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous beeping"}, // Grenade beep + {"gbeep", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Threatening beeping"}, // Grenade beep {"wepfir", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing weapon"}, // defaults to thok {"ghit" , false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Goop splash"}, {"gloop", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Splash"}, @@ -244,11 +244,11 @@ sfxinfo_t S_sfx[NUMSFX] = {"mario2", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Koopa shell"}, {"mario3", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power-up"}, {"mario4", true, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got coin"}, - {"mario5", false, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boot"}, + {"mario5", false, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boot-stomp"}, {"mario6", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"}, {"mario7", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"}, {"mario8", false, 48, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"}, - {"mario9", true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Emerging"}, + {"mario9", true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Emerging power-up"}, {"marioa", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "One-up"}, {"thwomp", true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Thwomp"}, diff --git a/src/st_stuff.c b/src/st_stuff.c index 031aa61db..3cc40124d 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1093,7 +1093,8 @@ static void ST_drawInput(void) ((!stplyr->powers[pw_carry] && (stplyr->pflags & PF_APPLYAUTOBRAKE) && !(stplyr->cmd.sidemove || stplyr->cmd.forwardmove) - && (stplyr->rmomx || stplyr->rmomy)) + && (stplyr->rmomx || stplyr->rmomy) + && (!stplyr->capsule || (stplyr->capsule->reactiontime != (stplyr-players)+1))) ? 0 : V_GRAYMAP), "AUTOBRAKE"); y -= 8; diff --git a/src/v_video.c b/src/v_video.c index 6ad6c08aa..d2c645d55 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1624,7 +1624,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) { INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0; const char *ch = string; - INT32 charflags = 0; + INT32 charflags = (option & V_CHARCOLORMASK); const UINT8 *colormap = NULL; INT32 spacewidth = 4, charwidth = 0; @@ -1644,8 +1644,6 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) left = (scrwidth - BASEVIDWIDTH)/2; } - charflags = (option & V_CHARCOLORMASK); - switch (option & V_SPACINGMASK) { case V_MONOSPACE: @@ -2154,8 +2152,10 @@ INT32 V_CreditStringWidth(const char *string) // void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH; + INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0; const char *ch = string; + INT32 charflags = (option & V_CHARCOLORMASK); + const UINT8 *colormap = NULL; if (option & V_NOSCALESTART) { @@ -2164,21 +2164,31 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) scrwidth = vid.width; } else - dupx = dupy = 1; - - for (;;) { - c = *ch++; - if (!c) + dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } + + for (;;ch++) + { + if (!*ch) break; - if (c == '\n') + if (*ch & 0x80) //color parsing -x 2.16.09 + { + // manually set flags override color codes + if (!(option & V_CHARCOLORMASK)) + charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK; + continue; + } + if (*ch == '\n') { cx = x; cy += 12*dupy; continue; } - c = toupper(c) - LT_FONTSTART; + c = toupper(*ch) - LT_FONTSTART; if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) { cx += 16*dupx; @@ -2186,17 +2196,19 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) } w = SHORT(lt_font[c]->width) * dupx; - if (cx + w > scrwidth) - break; + if (cx+left > scrwidth) + break; //left boundary check - if (cx < 0) + if (cx+left + w < 0) { cx += w; continue; } - V_DrawScaledPatch(cx, cy, option, lt_font[c]); + colormap = V_GetStringColormap(charflags); + V_DrawFixedPatch(cx<= LT_FONTSIZE || !lt_font[c]) w += 16; @@ -2265,11 +2279,9 @@ INT32 V_StringWidth(const char *string, INT32 option) for (i = 0; i < strlen(string); i++) { - c = string[i]; - if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if (string[i] & 0x80) continue; - - c = toupper(c) - HU_FONTSTART; + c = toupper(string[i]) - HU_FONTSTART; if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) w += spacewidth; else @@ -2307,11 +2319,9 @@ INT32 V_SmallStringWidth(const char *string, INT32 option) for (i = 0; i < strlen(string); i++) { - c = string[i]; - if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if (string[i] & 0x80) continue; - - c = toupper(c) - HU_FONTSTART; + c = toupper(string[i]) - HU_FONTSTART; if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) w += spacewidth; else @@ -2346,11 +2356,9 @@ INT32 V_ThinStringWidth(const char *string, INT32 option) for (i = 0; i < strlen(string); i++) { - c = string[i]; - if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + if (string[i] & 0x80) continue; - - c = toupper(c) - HU_FONTSTART; + c = toupper(string[i]) - HU_FONTSTART; if (c < 0 || c >= HU_FONTSIZE || !tny_font[c]) w += spacewidth; else diff --git a/src/y_inter.c b/src/y_inter.c index 2194dc96f..4d1e2baf0 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -77,7 +77,7 @@ typedef union struct { - char passed1[29]; // KNUCKLES GOT / CRAWLA HONCHO + char passed1[29]; // KNUCKLES GOT / CRAWLA HONCHO char passed2[17]; // A CHAOS EMERALD? / GOT THEM ALL! char passed3[15]; // CAN NOW BECOME char passed4[SKINNAMESIZE+7]; // SUPER CRAWLA HONCHO @@ -315,8 +315,9 @@ void Y_IntermissionDrawer(void) INT32 xoffset1 = 0; // Line 1 x offset INT32 xoffset2 = 0; // Line 2 x offset INT32 xoffset3 = 0; // Line 3 x offset - INT32 xoffset4 = 0; // Bonus line x offset - INT32 xoffset5 = 0; // Score line x offset + INT32 xoffset4 = 0; // Line 4 x offset + INT32 xoffset5 = 0; // Line 5 x offset + INT32 xoffset6 = 0; // Line 6 x offset UINT8 drawsection = 0; if (gottoken) // first to be behind everything else @@ -331,39 +332,46 @@ void Y_IntermissionDrawer(void) if (animatetic && intertic >= animatetic) { INT32 animatetimer = (intertic - animatetic); - if (animatetimer <= 12) + if (animatetimer <= 14) { xoffset1 = -(animatetimer * 40); xoffset2 = -((animatetimer-2) * 40); - xoffset4 = -((animatetimer-4) * 40); - xoffset5 = -((animatetimer-6) * 40); + xoffset3 = -((animatetimer-4) * 40); + xoffset4 = -((animatetimer-6) * 40); + xoffset5 = -((animatetimer-8) * 40); if (xoffset2 > 0) xoffset2 = 0; + if (xoffset3 > 0) xoffset3 = 0; if (xoffset4 > 0) xoffset4 = 0; if (xoffset5 > 0) xoffset5 = 0; } - else if (animatetimer < 28) + else if (animatetimer < 32) { drawsection = 1; - xoffset1 = (20-animatetimer) * 40; - xoffset2 = (22-animatetimer) * 40; - xoffset3 = (24-animatetimer) * 40; - xoffset4 = (26-animatetimer) * 40; - xoffset5 = (28-animatetimer) * 40; + xoffset1 = (22-animatetimer) * 40; + xoffset2 = (24-animatetimer) * 40; + xoffset3 = (26-animatetimer) * 40; + xoffset4 = (28-animatetimer) * 40; + xoffset5 = (30-animatetimer) * 40; + xoffset6 = (32-animatetimer) * 40; if (xoffset1 < 0) xoffset1 = 0; if (xoffset2 < 0) xoffset2 = 0; if (xoffset3 < 0) xoffset3 = 0; if (xoffset4 < 0) xoffset4 = 0; + if (xoffset5 < 0) xoffset5 = 0; } else { drawsection = 1; - if (animatetimer == 28) + if (animatetimer == 32) S_StartSound(NULL, sfx_s3k68); } } if (drawsection == 1) { + const char *ringtext = "\x86" "50 RINGS, NO SHIELD"; + const char *tut1text = "\x86" "PRESS " "\x82" "SPIN"; + const char *tut2text = "\x86" "MID-" "\x82" "JUMP"; ttheight = 16; V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); ttheight += V_LevelNameHeight(data.spec.passed3) + 2; @@ -371,8 +379,12 @@ void Y_IntermissionDrawer(void) ttheight += V_LevelNameHeight(data.spec.passed4) + 2; V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4); - V_DrawCenteredString(BASEVIDWIDTH/2 + xoffset4, 108 - 4, 0, "\x86""50 RINGS, NO SHIELD"); - V_DrawCenteredString(BASEVIDWIDTH/2 + xoffset5, 124 - 4, 0, "\x86""PRESS ""\x82""JUMP""\x86"", THEN ""\x82""SPIN"); + ttheight = 108; + V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset4 - (V_LevelNameWidth(ringtext)/2), ttheight, 0, ringtext); + ttheight += V_LevelNameHeight(ringtext) + 2; + V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text); + ttheight += V_LevelNameHeight(tut1text) + 2; + V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset6 - (V_LevelNameWidth(tut2text)/2), ttheight, 0, tut2text); } else { @@ -389,10 +401,24 @@ void Y_IntermissionDrawer(void) V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); } - V_DrawScaledPatch(152 + xoffset4, 108, 0, data.spec.bonuspatch); - V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 109, 0, data.spec.bonus.points); - V_DrawScaledPatch(152 + xoffset5, 124, 0, data.spec.pscore); - V_DrawTallNum(BASEVIDWIDTH + xoffset5 - 68, 125, 0, data.spec.score); + V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatch); + V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonus.points); + V_DrawScaledPatch(152 + xoffset4, 124, 0, data.spec.pscore); + V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125, 0, data.spec.score); + + // Draw continues! + if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay + { + UINT8 continues = data.spec.continues & 0x7F; + + V_DrawScaledPatch(152 + xoffset5, 150, 0, data.spec.pcontinues); + for (i = 0; i < continues; ++i) + { + if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10)) + break; + V_DrawContinueIcon(246 + xoffset5 - (i*12), 162, 0, *data.spec.playerchar, *data.spec.playercolor); + } + } } // draw the emeralds @@ -467,20 +493,6 @@ void Y_IntermissionDrawer(void) } } } - - // Draw continues! - if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay - { - UINT8 continues = data.spec.continues & 0x7F; - - V_DrawScaledPatch(152, 150, 0, data.spec.pcontinues); - for (i = 0; i < continues; ++i) - { - if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10)) - break; - V_DrawContinueIcon(246 - (i*12), 162, 0, *data.spec.playerchar, *data.spec.playercolor); - } - } } else if (intertype == int_match || intertype == int_race) { @@ -881,7 +893,7 @@ void Y_Ticker(void) { INT32 i; UINT32 oldscore = data.spec.score; - boolean skip = false; + boolean skip = false, super = false; if (!intertic) // first time only { @@ -893,15 +905,22 @@ void Y_Ticker(void) return; for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (players[i].cmd.buttons & BT_USE)) - skip = true; + if (playeringame[i]) + { + if (players[i].cmd.buttons & BT_USE) + skip = true; + if (players[i].charflags & SF_SUPER) + super = true; + } - if (((data.spec.continues & 0x80) || ALL7EMERALDS(emeralds)) && tallydonetic != -1) + if (tallydonetic != -1 && ((data.spec.continues & 0x80) || (super && ALL7EMERALDS(emeralds)))) { if ((intertic - tallydonetic) > (3*TICRATE)/2) { endtic = intertic + 4*TICRATE; // 4 second pause after end of tally - S_StartSound(NULL, sfx_s3kac); // bingly-bingly-bing! + if (data.spec.continues & 0x80) + S_StartSound(NULL, sfx_s3kac); // bingly-bingly-bing! + } return; } @@ -918,7 +937,7 @@ void Y_Ticker(void) if (!data.spec.bonus.points) { tallydonetic = intertic; - if (!(data.spec.continues & 0x80)) // don't set endtic yet! + if (!((data.spec.continues & 0x80) || (super && ALL7EMERALDS(emeralds)))) // don't set endtic yet! endtic = intertic + 4*TICRATE; // 4 second pause after end of tally S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching! @@ -1317,7 +1336,7 @@ void Y_StartIntermission(void) data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0'; strcpy(data.spec.passed2, "GOT THEM ALL!"); - if (skins[players[consoleplayer].skin].flags & SF_SUPER) + if (players[consoleplayer].charflags & SF_SUPER) { strcpy(data.spec.passed3, "CAN NOW BECOME"); snprintf(data.spec.passed4, From 9c2d30ce3521ccab3661c2ea96f3266638d895ae Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 5 Jun 2018 20:47:30 +0100 Subject: [PATCH 154/212] * Almost everything except players and badniks get removed on deathpit collision, as requested by Nev (very useful for the Bridge). May need serious checking for mobjtypes this is safe to do for. * Flames fall with flameholders. * New modification to teleport cheat: -sp allows instantaneous jump to any starpost in the map, including spawnpoints as starpost index 0! * Also, -ang and -aim , which can be combined with -nop to pivot on the spot. --- src/info.c | 2 +- src/m_cheat.c | 227 ++++++++++++++++++++++++++++++++++++++++++-------- src/p_inter.c | 25 +++--- src/p_mobj.c | 54 +++++++----- 4 files changed, 240 insertions(+), 68 deletions(-) diff --git a/src/info.c b/src/info.c index dbbe54de9..d2bd1dab5 100644 --- a/src/info.c +++ b/src/info.c @@ -6740,7 +6740,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, diff --git a/src/m_cheat.c b/src/m_cheat.c index 81a8702fd..15a3353c4 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -499,56 +499,211 @@ void Command_Teleport_f(void) REQUIRE_INLEVEL; REQUIRE_SINGLEPLAYER; - if (COM_Argc() < 3 || COM_Argc() > 7) + if (COM_Argc() < 3 || COM_Argc() > 11) { - CONS_Printf(M_GetText("teleport -x -y -z : teleport to a location\n")); + CONS_Printf(M_GetText("teleport -x -y -z -ang -aim : teleport to a location\nteleport -sp : teleport to specified checkpoint\n")); return; } if (!p->mo) return; - i = COM_CheckParm("-x"); - if (i) - intx = atoi(COM_Argv(i + 1)); - else - { - CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "X"); - return; - } - - i = COM_CheckParm("-y"); - if (i) - inty = atoi(COM_Argv(i + 1)); - else - { - CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "Y"); - return; - } - - ss = R_PointInSubsector(intx*FRACUNIT, inty*FRACUNIT); - if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) - { - CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); - return; - } - i = COM_CheckParm("-z"); + i = COM_CheckParm("-sp"); if (i) { - intz = atoi(COM_Argv(i + 1)); - intz <<= FRACBITS; - if (intz < ss->sector->floorheight) - intz = ss->sector->floorheight; - if (intz > ss->sector->ceilingheight - p->mo->height) - intz = ss->sector->ceilingheight - p->mo->height; + INT32 starpostnum = atoi(COM_Argv(i + 1)); // starpost number + INT32 starpostpath = atoi(COM_Argv(i + 2)); // quick, dirty way to distinguish between paths + + if (starpostnum < 0 || starpostpath < 0) + { + CONS_Alert(CONS_NOTICE, M_GetText("Negative starpost indexing is not valid.\n")); + return; + } + + if (!starpostnum) // spawnpoints... + { + mapthing_t *mt; + + if (starpostpath >= numcoopstarts) + { + CONS_Alert(CONS_NOTICE, M_GetText("Player %d spawnpoint not found (%d max).\n"), starpostpath+1, numcoopstarts-1); + return; + } + + mt = playerstarts[starpostpath]; // Given above check, should never be NULL. + intx = mt->x<y<sector->ceilingheight - ss->sector->floorheight < p->mo->height) + { + CONS_Alert(CONS_NOTICE, M_GetText("Spawnpoint not in a valid location.\n")); + return; + } + + // Flagging a player's ambush will make them start on the ceiling + // Objectflip inverts + if (!!(mt->options & MTF_AMBUSH) ^ !!(mt->options & MTF_OBJECTFLIP)) + { + intz = ss->sector->ceilingheight - p->mo->height; + if (mt->options >> ZSHIFT) + intz -= ((mt->options >> ZSHIFT) << FRACBITS); + } + else + { + intz = ss->sector->floorheight; + if (mt->options >> ZSHIFT) + intz += ((mt->options >> ZSHIFT) << FRACBITS); + } + + if (mt->options & MTF_OBJECTFLIP) // flip the player! + { + p->mo->eflags |= MFE_VERTICALFLIP; + p->mo->flags2 |= MF2_OBJECTFLIP; + } + else + { + p->mo->eflags &= ~MFE_VERTICALFLIP; + p->mo->flags2 &= ~MF2_OBJECTFLIP; + } + + localangle = p->mo->angle = p->drawangle = FixedAngle(mt->angle<next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_STARPOST) + continue; + + if (mo2->health != starpostnum) + { + if (mo2->health > starpostmax) + starpostmax = mo2->health; + continue; + } + + if (intz--) + continue; + + break; + } + + if (th == &thinkercap) + { + if (intz == starpostpath) + CONS_Alert(CONS_NOTICE, M_GetText("No starpost of position %d found (%d max).\n"), starpostnum, starpostmax); + else + CONS_Alert(CONS_NOTICE, M_GetText("Starpost of position %d, %d not found (%d, %d max).\n"), starpostnum, starpostpath, starpostmax, (starpostpath-intz)-1); + return; + } + + ss = R_IsPointInSubsector(mo2->x, mo2->y); + if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) + { + CONS_Alert(CONS_NOTICE, M_GetText("Starpost not in a valid location.\n")); + return; + } + + intx = mo2->x; + inty = mo2->y; + intz = mo2->z; + + if (mo2->flags2 & MF2_OBJECTFLIP) // flip the player! + { + p->mo->eflags |= MFE_VERTICALFLIP; + p->mo->flags2 |= MF2_OBJECTFLIP; + } + else + { + p->mo->eflags &= ~MFE_VERTICALFLIP; + p->mo->flags2 &= ~MF2_OBJECTFLIP; + } + + localangle = p->mo->angle = p->drawangle = mo2->angle; + } + + CONS_Printf(M_GetText("Teleporting to checkpoint %d, %d...\n"), starpostnum, starpostpath); } else - intz = ss->sector->floorheight; + { + i = COM_CheckParm("-nop"); // undocumented stupid addition to allow pivoting on the spot with -ang and -aim + if (i) + { + intx = p->mo->x; + inty = p->mo->y; + } + else + { + i = COM_CheckParm("-x"); + if (i) + intx = atoi(COM_Argv(i + 1))<sector->ceilingheight - ss->sector->floorheight < p->mo->height) + { + CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); + return; + } + i = COM_CheckParm("-z"); + if (i) + { + intz = atoi(COM_Argv(i + 1))<sector->floorheight) + intz = ss->sector->floorheight; + if (intz > ss->sector->ceilingheight - p->mo->height) + intz = ss->sector->ceilingheight - p->mo->height; + } + else + intz = ((p->mo->eflags & MFE_VERTICALFLIP) ? ss->sector->ceilingheight : ss->sector->floorheight); + + i = COM_CheckParm("-ang"); + if (i) + localangle = p->drawangle = p->mo->angle = FixedAngle(atoi(COM_Argv(i + 1))<= ANGLE_90 && aim <= ANGLE_270) + { + CONS_Alert(CONS_NOTICE, M_GetText("Not a valid aiming angle (between +/-90).\n")); + return; + } + localaiming = p->aiming = aim; + } + + CONS_Printf(M_GetText("Teleporting to %d, %d, %d...\n"), FixedInt(intx), FixedInt(inty), FixedInt(intz)); + } P_MapStart(); - if (!P_TeleportMove(p->mo, intx*FRACUNIT, inty*FRACUNIT, intz)) + if (!P_TeleportMove(p->mo, intx, inty, intz)) CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); else S_StartSound(p->mo, sfx_mixup); diff --git a/src/p_inter.c b/src/p_inter.c index f3fb5f6e1..8f8c1f4fa 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -104,8 +104,13 @@ void P_ClearStarPost(INT32 postnum) mo2 = (mobj_t *)th; - if (mo2->type == MT_STARPOST && mo2->health <= postnum) - P_SetMobjState(mo2, mo2->info->seestate); + if (mo2->type != MT_STARPOST) + return; + + if (mo2->health > postnum) + return; + + P_SetMobjState(mo2, mo2->info->seestate); } return; } @@ -1364,7 +1369,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_ClearStarPost(special->health); - // Find all starposts in the level with this value. + // Find all starposts in the level with this value - INCLUDING this one! + if (!(netgame && circuitmap && player != &players[consoleplayer])) { thinker_t *th; mobj_t *mo2; @@ -1376,21 +1382,16 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) mo2 = (mobj_t *)th; - if (mo2 == special) + if (mo2->type != MT_STARPOST) + continue; + if (mo2->health != special->health) continue; - if (mo2->type == MT_STARPOST && mo2->health == special->health) - { - if (!(netgame && circuitmap && player != &players[consoleplayer])) - P_SetMobjState(mo2, mo2->info->painstate); - } + P_SetMobjState(mo2, mo2->info->painstate); } } S_StartSound(toucher, special->info->painsound); - - if (!(netgame && circuitmap && player != &players[consoleplayer])) - P_SetMobjState(special, special->info->painstate); return; case MT_FAKEMOBILE: diff --git a/src/p_mobj.c b/src/p_mobj.c index cc28fb5a0..5a8729df2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2404,6 +2404,7 @@ boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover) static boolean P_ZMovement(mobj_t *mo) { fixed_t dist, delta; + boolean onground; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -2421,13 +2422,14 @@ static boolean P_ZMovement(mobj_t *mo) mo->eflags &= ~MFE_APPLYPMOMZ; } mo->z += mo->momz; + onground = P_IsObjectOnGround(mo); #ifdef ESLOPE if (mo->standingslope) { if (mo->flags & MF_NOCLIPHEIGHT) mo->standingslope = NULL; - else if (!P_IsObjectOnGround(mo)) + else if (!onground) P_SlopeLaunch(mo); } #endif @@ -2571,15 +2573,9 @@ static boolean P_ZMovement(mobj_t *mo) break; } - if (P_CheckDeathPitCollide(mo)) + if (!mo->player && P_CheckDeathPitCollide(mo)) { - if (mo->flags & MF_PUSHABLE) - { - // Remove other pushable items from death pits. - P_RemoveMobj(mo); - return false; - } - else if (mo->flags & MF_ENEMY || mo->flags & MF_BOSS) + if (mo->flags & MF_ENEMY || mo->flags & MF_BOSS) { // Kill enemies and bosses that fall into death pits. if (mo->health) @@ -2588,6 +2584,11 @@ static boolean P_ZMovement(mobj_t *mo) return false; } } + else + { + P_RemoveMobj(mo); + return false; + } } if (P_MobjFlip(mo)*mo->momz < 0 @@ -2870,6 +2871,8 @@ static boolean P_ZMovement(mobj_t *mo) static void P_PlayerZMovement(mobj_t *mo) { + boolean onground; + I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -2903,6 +2906,7 @@ static void P_PlayerZMovement(mobj_t *mo) } mo->z += mo->momz; + onground = P_IsObjectOnGround(mo); // Have player fall through floor? if (mo->player->playerstate == PST_DEAD @@ -2914,13 +2918,13 @@ static void P_PlayerZMovement(mobj_t *mo) { if (mo->flags & MF_NOCLIPHEIGHT) mo->standingslope = NULL; - else if (!P_IsObjectOnGround(mo)) + else if (!onground) P_SlopeLaunch(mo); } #endif // clip movement - if (P_IsObjectOnGround(mo) && !(mo->flags & MF_NOCLIPHEIGHT)) + if (onground && !(mo->flags & MF_NOCLIPHEIGHT)) { if (mo->eflags & MFE_VERTICALFLIP) mo->z = mo->ceilingz - mo->height; @@ -3222,19 +3226,14 @@ static boolean P_SceneryZMovement(mobj_t *mo) P_RemoveMobj(mo); return false; } - default: break; } - // Fix for any silly pushables like the egg statues that are also scenery for some reason -- Monster Iestyn if (P_CheckDeathPitCollide(mo)) { - if (mo->flags & MF_PUSHABLE) - { - P_RemoveMobj(mo); - return false; - } + P_RemoveMobj(mo); + return false; } // clip movement @@ -7483,6 +7482,19 @@ void P_MobjThinker(mobj_t *mobj) mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); P_SetThingPosition(mobj); break; + case MT_FLAME: + if (mobj->flags2 & MF2_BOSSNOTRAP) + { + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + P_RemoveMobj(mobj); + return; + } + mobj->z = mobj->target->z + mobj->target->momz; + if (!(mobj->eflags & MFE_VERTICALFLIP)) + mobj->z += mobj->target->height; + } + break; case MT_WAVINGFLAG: { fixed_t base = (leveltime<<(FRACBITS+1)); @@ -10474,7 +10486,11 @@ ML_EFFECT4 : Don't clip inside the ground break; case MT_FLAMEHOLDER: if (!(mthing->options & MTF_OBJECTSPECIAL)) // Spawn the fire - P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); + { + mobj_t *flame = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); + P_SetTarget(&flame->target, mobj); + flame->flags2 |= MF2_BOSSNOTRAP; + } break; case MT_SMASHINGSPIKEBALL: if (mthing->angle > 0) From adf8f0e3914e9b7fd60e3e861ded4d5dec732cb5 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 00:40:23 +0100 Subject: [PATCH 155/212] * Some minor info.c tweaks I discovered I needed to make while transferring material across from patch.dta to srb2.pk3. * Making the particle generator dynamic, as requested by Nev3r. * i....... think this is done? i'll double check in the morning. --- src/dehacked.c | 2 -- src/info.c | 9 +++--- src/info.h | 2 -- src/p_enemy.c | 48 ------------------------------ src/p_mobj.c | 80 +++++++++++++++++++++++++++++++++++++------------- 5 files changed, 64 insertions(+), 77 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 6b38ceb40..31d4129df 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1651,7 +1651,6 @@ static actionpointer_t actionpointers[] = {{A_GiveShield}, "A_GIVESHIELD"}, {{A_GravityBox}, "A_GRAVITYBOX"}, {{A_ScoreRise}, "A_SCORERISE"}, - {{A_ParticleSpawn}, "A_PARTICLESPAWN"}, {{A_AttractChase}, "A_ATTRACTCHASE"}, {{A_DropMine}, "A_DROPMINE"}, {{A_FishJump}, "A_FISHJUMP"}, @@ -5702,7 +5701,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SEED", "S_PARTICLE", - "S_PARTICLEGEN", // Score Logos "S_SCRA", // 100 diff --git a/src/info.c b/src/info.c index d2bd1dab5..734d46231 100644 --- a/src/info.c +++ b/src/info.c @@ -2786,7 +2786,7 @@ state_t states[NUMSTATES] = {SPR_STEM, 4, 2, {NULL}, 0, 0, S_STEAM6}, // S_STEAM5 {SPR_STEM, 5, 2, {NULL}, 0, 0, S_STEAM7}, // S_STEAM6 {SPR_STEM, 6, 2, {NULL}, 0, 0, S_STEAM8}, // S_STEAM7 - {SPR_STEM, 7, 18, {NULL}, 0, 0, S_STEAM1}, // S_STEAM8 + {SPR_NULL, 0, 18, {NULL}, 0, 0, S_STEAM1}, // S_STEAM8 // Bumpers {SPR_BUMP, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BUMPER @@ -2963,7 +2963,6 @@ state_t states[NUMSTATES] = // Particle sprite {SPR_PRTL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_PARTICLE - {SPR_NULL, 0, 3, {A_ParticleSpawn}, 0, 0, S_PARTICLEGEN}, // S_PARTICLEGEN {SPR_SCOR, 0, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRA - 100 {SPR_SCOR, 1, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRB - 200 @@ -14499,7 +14498,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_PARTICLEGEN 757, // doomednum - S_PARTICLEGEN, // spawnstate + S_INVISIBLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -14520,7 +14519,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags S_NULL // raisestate }, @@ -16619,7 +16618,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_PENGUINATOR_WADDLE1, // seestate sfx_None, // seesound 0, // reactiontime - sfx_s3k8a, // attacksound + sfx_ngjump, // attacksound S_NULL, // painstate 200, // painchance sfx_None, // painsound diff --git a/src/info.h b/src/info.h index 5b1169e22..c9f7299d8 100644 --- a/src/info.h +++ b/src/info.h @@ -57,7 +57,6 @@ void A_ExtraLife(); // Extra Life void A_GiveShield(); // Obtained Shield void A_GravityBox(); void A_ScoreRise(); // Rise the score logo -void A_ParticleSpawn(); void A_AttractChase(); // Ring Chase void A_DropMine(); // Drop Mine from Skim or Jetty-Syn Bomber void A_FishJump(); // Fish Jump @@ -3066,7 +3065,6 @@ typedef enum state S_SEED, S_PARTICLE, - S_PARTICLEGEN, // Score Logos S_SCRA, // 100 diff --git a/src/p_enemy.c b/src/p_enemy.c index 367eec60f..7ad33ef2d 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -112,7 +112,6 @@ void A_ExtraLife(mobj_t *actor); void A_GiveShield(mobj_t *actor); void A_GravityBox(mobj_t *actor); void A_ScoreRise(mobj_t *actor); -void A_ParticleSpawn(mobj_t *actor); void A_BunnyHop(mobj_t *actor); void A_BubbleSpawn(mobj_t *actor); void A_FanBubbleSpawn(mobj_t *actor); @@ -3958,53 +3957,6 @@ void A_ScoreRise(mobj_t *actor) P_SetObjectMomZ(actor, actor->info->speed, false); } -// Function: A_ParticleSpawn -// -// Description: Hyper-specialised function for spawning a particle for MT_PARTICLEGEN. -// -// var1 = unused -// var2 = unused -// -void A_ParticleSpawn(mobj_t *actor) -{ - INT32 i = 0; - mobj_t *spawn; - -#ifdef HAVE_BLUA - if (LUA_CallAction("A_ParticleSpawn", actor)) - return; -#endif - if (!actor->health) - return; - - if (!actor->lastlook) - return; - - if (!actor->threshold) - return; - - for (i = 0; i < actor->lastlook; i++) - { - spawn = P_SpawnMobj( - actor->x + FixedMul(FixedMul(actor->friction, actor->scale), FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), - actor->y + FixedMul(FixedMul(actor->friction, actor->scale), FINESINE(actor->angle>>ANGLETOFINESHIFT)), - actor->z, - (mobjtype_t)actor->threshold); - P_SetScale(spawn, actor->scale); - spawn->momz = FixedMul(actor->movefactor, spawn->scale); - spawn->destscale = spawn->scale/100; - spawn->scalespeed = spawn->scale/actor->health; - spawn->tics = (tic_t)actor->health; - spawn->flags2 |= (actor->flags2 & MF2_OBJECTFLIP); - spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones - - actor->angle += actor->movedir; - } - - actor->angle += (angle_t)actor->movecount; - actor->tics = (tic_t)actor->reactiontime; -} - // Function: A_BunnyHop // // Description: Makes object hop like a bunny. diff --git a/src/p_mobj.c b/src/p_mobj.c index 5a8729df2..301536ef4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7116,6 +7116,59 @@ void P_MobjThinker(mobj_t *mobj) return; } break; + case MT_PARTICLEGEN: + if (!mobj->lastlook) + return; + + if (!mobj->threshold) + return; + + if (--mobj->fuse <= 0) + { + INT32 i = 0; + mobj_t *spawn; + fixed_t bottomheight, topheight; + INT32 type = mobj->threshold, line = mobj->cvmem; + + mobj->fuse = (tic_t)mobj->reactiontime; + + bottomheight = lines[line].frontsector->floorheight; + topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; + + if (mobj->waterbottom != bottomheight || mobj->watertop != topheight) + { + if (mobj->movefactor && (topheight > bottomheight)) + mobj->health = (tic_t)(FixedDiv((topheight - bottomheight), abs(mobj->movefactor)) >> FRACBITS); + else + mobj->health = 0; + + mobj->z = ((mobj->flags2 & MF2_OBJECTFLIP) ? topheight : bottomheight); + } + + if (!mobj->health) + return; + + for (i = 0; i < mobj->lastlook; i++) + { + spawn = P_SpawnMobj( + mobj->x + FixedMul(FixedMul(mobj->friction, mobj->scale), FINECOSINE(mobj->angle>>ANGLETOFINESHIFT)), + mobj->y + FixedMul(FixedMul(mobj->friction, mobj->scale), FINESINE(mobj->angle>>ANGLETOFINESHIFT)), + mobj->z, + (mobjtype_t)mobj->threshold); + P_SetScale(spawn, mobj->scale); + spawn->momz = FixedMul(mobj->movefactor, spawn->scale); + spawn->destscale = spawn->scale/100; + spawn->scalespeed = spawn->scale/mobj->health; + spawn->tics = (tic_t)mobj->health; + spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP); + spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + + mobj->angle += mobj->movedir; + } + + mobj->angle += (angle_t)mobj->movecount; + } + break; default: if (mobj->fuse) { // Scenery object fuse! Very basic! @@ -10321,8 +10374,8 @@ ML_EFFECT4 : Don't clip inside the ground } case MT_PARTICLEGEN: { - fixed_t radius, speed, bottomheight, topheight; - INT32 type, numdivisions, time, anglespeed, ticcount; + fixed_t radius, speed; + INT32 type, numdivisions, anglespeed, ticcount; angle_t angledivision; INT32 line; const size_t mthingi = (size_t)(mthing - mapthings); @@ -10341,13 +10394,9 @@ ML_EFFECT4 : Don't clip inside the ground else type = (INT32)MT_PARTICLE; - speed = abs(sides[lines[line].sidenum[0]].textureoffset); - bottomheight = lines[line].frontsector->floorheight; - topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; - if (!lines[line].backsector || (ticcount = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS)) < 1) - ticcount = states[S_PARTICLEGEN].tics; + ticcount = 3; numdivisions = (mthing->options >> ZSHIFT); @@ -10365,18 +10414,9 @@ ML_EFFECT4 : Don't clip inside the ground angledivision = 0; } - if ((speed) && (topheight > bottomheight)) - time = (INT32)(FixedDiv((topheight - bottomheight), speed) >> FRACBITS); - else - time = 1; // There's no reasonable way to set it, so just show the object for one tic and move on. - + speed = abs(sides[lines[line].sidenum[0]].textureoffset); if (mthing->options & MTF_OBJECTFLIP) - { - mobj->z = topheight; speed *= -1; - } - else - mobj->z = bottomheight; CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n" "Radius is %d\n" @@ -10384,20 +10424,20 @@ ML_EFFECT4 : Don't clip inside the ground "Anglespeed is %d\n" "Numdivisions is %d\n" "Angledivision is %d\n" - "Time is %d\n" "Type is %d\n" "Tic seperation is %d\n", - sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, time, type, ticcount); + sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, type, ticcount); mobj->angle = 0; mobj->movefactor = speed; mobj->lastlook = numdivisions; mobj->movedir = angledivision*ANG1; mobj->movecount = anglespeed*ANG1; - mobj->health = time; mobj->friction = radius; mobj->threshold = type; mobj->reactiontime = ticcount; + mobj->cvmem = line; + mobj->watertop = mobj->waterbottom = 0; break; } From db8f3e83b282a90b84696202be5c19d294a37e42 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 00:48:14 +0100 Subject: [PATCH 156/212] There's always something... a slightly more forgiving radius for the Crushstacean's claw, since I've gotten hit whilst apparently jumping at a safe place next to the claw a few times this evening. --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 734d46231..3a864217c 100644 --- a/src/info.c +++ b/src/info.c @@ -4092,7 +4092,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_pop, // deathsound 1, // speed - 32*FRACUNIT, // radius + 22*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset (sfx_s3k49<<8), // mass From 5032ae255241e880c72026d1605d7e48b88b9785 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 14:42:50 +0100 Subject: [PATCH 157/212] * Patch.pk3 as requested by literally everyone else on the team. * Enable SECTORSPECIALAFTERTHINK since we probably really want to use that sloped lava wave in RVZ. * Allow for infinite lives to be set via the setlives command/Pandora's Box. * Refactor P_DoFiring(), with guidance from Sal. * Correct the CRAWLA HONCHO\nCAN NOW BECOME\nSUPER CRAWLA HONCHO sliding movement in non-green resolutions. --- src/config.h.in | 4 +- src/d_main.c | 12 +- src/doomdef.h | 2 +- src/m_cheat.c | 12 +- src/m_menu.c | 7 +- src/p_user.c | 365 ++++++++++++++++++++++++------------------------ src/sounds.c | 4 +- src/y_inter.c | 23 +-- 8 files changed, 222 insertions(+), 207 deletions(-) diff --git a/src/config.h.in b/src/config.h.in index 7c9ebe6cb..174b34430 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -16,7 +16,7 @@ #define ASSET_HASH_RINGS_DTA "${SRB2_ASSET_rings.dta_HASH}" #define ASSET_HASH_ZONES_DTA "${SRB2_ASSET_zones.dta_HASH}" #ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_DTA "${SRB2_ASSET_patch.dta_HASH}" +#define ASSET_HASH_PATCH_PK3 "${SRB2_ASSET_patch.pk3_HASH}" #endif #define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}" @@ -36,7 +36,7 @@ #define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799" #define ASSET_HASH_RINGS_DTA "85901ad4bf94637e5753d2ac2c03ea26" #ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_DTA "dbbf8bc6121618ee3be2d5b14650429b" +#define ASSET_HASH_PATCH_PK3 "dbbf8bc6121618ee3be2d5b14650429b" #endif #endif diff --git a/src/d_main.c b/src/d_main.c index 05aa3e675..6ded3de84 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -843,7 +843,7 @@ static void IdentifyVersion(void) #ifdef USE_PATCH_DTA // Add our crappy patches to fix our bugs - D_AddFile(va(pandf,srb2waddir,"patch.dta")); + D_AddFile(va(pandf,srb2waddir,"patch.pk3")); #endif #if !defined (HAVE_SDL) || defined (HAVE_MIXER) @@ -1125,11 +1125,11 @@ void D_SRB2Main(void) #ifndef DEVELOP // md5s last updated 12/14/14 // Check MD5s of autoloaded files - //W_VerifyFileMD5(0, ASSET_HASH_SRB2_PK3); // srb2.pk3 - //W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta - //W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta + W_VerifyFileMD5(0, ASSET_HASH_SRB2_PK3); // srb2.pk3 + W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta + W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta #ifdef USE_PATCH_DTA - W_VerifyFileMD5(3, ASSET_HASH_PATCH_DTA); // patch.dta + W_VerifyFileMD5(3, ASSET_HASH_PATCH_PK3); // patch.pk3 #endif // don't check music.dta because people like to modify it, and it doesn't matter if they do @@ -1138,7 +1138,7 @@ void D_SRB2Main(void) mainwads = 3; // there are 3 wads not to unload #ifdef USE_PATCH_DTA - ++mainwads; // patch.dta adds one more + ++mainwads; // patch.pk3 adds one more #endif #ifdef DEVELOP ++mainwads; // music_new, too diff --git a/src/doomdef.h b/src/doomdef.h index 32771163e..b09aaa415 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -569,6 +569,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Handle touching sector specials in P_PlayerAfterThink instead of P_PlayerThink. /// \note Required for proper collision with moving sloped surfaces that have sector specials on them. -//#define SECTORSPECIALSAFTERTHINK +#define SECTORSPECIALSAFTERTHINK #endif // __DOOMDEF__ diff --git a/src/m_cheat.c b/src/m_cheat.c index 15a3353c4..5ac742270 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -899,9 +899,15 @@ void Command_Setlives_f(void) if (COM_Argc() > 1) { - // P_GivePlayerLives does value clamping - players[consoleplayer].lives = 0; - P_GivePlayerLives(&players[consoleplayer], atoi(COM_Argv(1))); + SINT8 lives = atoi(COM_Argv(1)); + if (lives == -1) + players[consoleplayer].lives = 0x7f; // infinity! + else + { + // P_GivePlayerLives does value clamping + players[consoleplayer].lives = 0; + P_GivePlayerLives(&players[consoleplayer], atoi(COM_Argv(1))); + } G_SetGameModified(multiplayer); } diff --git a/src/m_menu.c b/src/m_menu.c index 26ab7ca3e..45510625e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -458,7 +458,7 @@ consvar_t cv_ghost_guest = {"ghost_guest", "Show", CV_SAVE, ghost2_cons_ static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; static CV_PossibleValue_t ringlimit_cons_t[] = {{0, "MIN"}, {9999, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t liveslimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t liveslimit_cons_t[] = {{-1, "MIN"}, {99, "MAX"}, {0, NULL}}; static CV_PossibleValue_t dummymares_cons_t[] = { {-1, "END"}, {0,"Overall"}, {1,"Mare 1"}, {2,"Mare 2"}, {3,"Mare 3"}, {4,"Mare 4"}, {5,"Mare 5"}, {6,"Mare 6"}, {7,"Mare 7"}, {8,"Mare 8"}, {0,NULL} }; @@ -5266,7 +5266,10 @@ static void M_PandorasBox(INT32 choice) { (void)choice; CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0)); - CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives); + if (players[consoleplayer].lives == 0x7f) + CV_StealthSetValue(&cv_dummylives, -1); + else + CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives); CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues); SR_PandorasBox[6].status = ((players[consoleplayer].charflags & SF_SUPER) #ifndef DEVELOP diff --git a/src/p_user.c b/src/p_user.c index 40d909d25..4c333ec50 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3491,194 +3491,199 @@ static void P_SetWeaponDelay(player_t *player, INT32 delay) static void P_DoFiring(player_t *player, ticcmd_t *cmd) { INT32 i; + mobj_t *mo = NULL; I_Assert(player != NULL); I_Assert(!P_MobjWasRemoved(player->mo)); - if (cmd->buttons & BT_ATTACK || cmd->buttons & BT_FIRENORMAL) + if (!(cmd->buttons & (BT_ATTACK|BT_FIRENORMAL))) { - if (!(player->pflags & PF_ATTACKDOWN) && (player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER && !player->climbing) - { - player->pflags |= PF_ATTACKDOWN; - P_SpawnPlayerMissile(player->mo, MT_FIREBALL, 0); - S_StartSound(player->mo, sfx_mario7); - } - else if (G_RingSlingerGametype() && (!G_TagGametype() || player->pflags & PF_TAGIT) - && !player->weapondelay && !player->climbing - && !(player->pflags & PF_ATTACKDOWN)) - { - mobj_t *mo = NULL; - player->pflags |= PF_ATTACKDOWN; - - #define TAKE_AMMO(player, power) \ - player->powers[power]--; \ - if (player->rings < 1) \ - { \ - if (player->powers[power] > 0) \ - player->powers[power]--; \ - } \ - else \ - player->rings--; - - if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring. - goto firenormal; //code repetition sucks. - // Bounce ring - else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering]) - { - TAKE_AMMO(player, pw_bouncering); - P_SetWeaponDelay(player, TICRATE/4); - - mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING); - - if (mo) - mo->fuse = 3*TICRATE; // Bounce Ring time - } - // Rail ring - else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring]) - { - TAKE_AMMO(player, pw_railring); - P_SetWeaponDelay(player, (3*TICRATE)/2); - - mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW); - - // Rail has no unique thrown object, therefore its sound plays here. - S_StartSound(player->mo, sfx_rail1); - } - // Automatic - else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring]) - { - TAKE_AMMO(player, pw_automaticring); - player->pflags &= ~PF_ATTACKDOWN; - P_SetWeaponDelay(player, 2); - - mo = P_SpawnPlayerMissile(player->mo, MT_THROWNAUTOMATIC, MF2_AUTOMATIC); - } - // Explosion - else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring]) - { - TAKE_AMMO(player, pw_explosionring); - P_SetWeaponDelay(player, (3*TICRATE)/2); - - mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION); - } - // Grenade - else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering]) - { - TAKE_AMMO(player, pw_grenadering); - P_SetWeaponDelay(player, TICRATE/3); - - mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION); - - if (mo) - { - //P_InstaThrust(mo, player->mo->angle, FixedMul(mo->info->speed, player->mo->scale)); - mo->fuse = mo->info->reactiontime; - } - } - // Scatter - // Note: Ignores MF2_RAILRING - else if (player->currentweapon == WEP_SCATTER && player->powers[pw_scatterring]) - { - fixed_t oldz = player->mo->z; - angle_t shotangle = player->mo->angle; - angle_t oldaiming = player->aiming; - - TAKE_AMMO(player, pw_scatterring); - P_SetWeaponDelay(player, (2*TICRATE)/3); - - // Center - mo = P_SpawnPlayerMissile(player->mo, MT_THROWNSCATTER, MF2_SCATTER); - if (mo) - shotangle = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y); - - // Left - mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle-ANG2, true, MF2_SCATTER); - - // Right - mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle+ANG2, true, MF2_SCATTER); - - // Down - player->mo->z += FixedMul(12*FRACUNIT, player->mo->scale); - player->aiming += ANG1; - mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER); - - // Up - player->mo->z -= FixedMul(24*FRACUNIT, player->mo->scale); - player->aiming -= ANG2; - mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER); - - player->mo->z = oldz; - player->aiming = oldaiming; - return; - } - // No powers, just a regular ring. - else - { -firenormal: - // Infinity ring was selected. - // Mystic wants this ONLY to happen specifically if it's selected, - // and to not be able to get around it EITHER WAY with firenormal. - - // Infinity Ring - if (player->currentweapon == 0 - && player->powers[pw_infinityring]) - { - P_SetWeaponDelay(player, TICRATE/4); - - mo = P_SpawnPlayerMissile(player->mo, MT_THROWNINFINITY, 0); - - player->powers[pw_infinityring]--; - } - // Red Ring - else - { - if (player->rings <= 0) - return; - P_SetWeaponDelay(player, TICRATE/4); - - mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, 0); - - if (mo) - P_ColorTeamMissile(mo, player); - - player->rings--; - } - } - - #undef TAKE_AMMO - - if (mo) - { - if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING) - { - const boolean nblockmap = !(mo->flags & MF_NOBLOCKMAP); - for (i = 0; i < 256; i++) - { - if (nblockmap) - { - P_UnsetThingPosition(mo); - mo->flags |= MF_NOBLOCKMAP; - P_SetThingPosition(mo); - } - - if (i&1) - P_SpawnMobj(mo->x, mo->y, mo->z, MT_SPARK); - - if (P_RailThinker(mo)) - break; // mobj was removed (missile hit a wall) or couldn't move - } - - // Other rail sound plays at contact point. - S_StartSound(mo, sfx_rail2); - } - } - } + // Not holding any firing buttons anymore. + // Release the grenade / whatever. + player->pflags &= ~PF_ATTACKDOWN; return; } - // Not holding any firing buttons anymore. - // Release the grenade / whatever. - player->pflags &= ~PF_ATTACKDOWN; + if (player->pflags & PF_ATTACKDOWN || player->climbing || (G_TagGametype() && !(player->pflags & PF_TAGIT))) + return; + + if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) + { + player->pflags |= PF_ATTACKDOWN; + mo = P_SpawnPlayerMissile(player->mo, MT_FIREBALL, 0); + if (mo && ((mo->info->speed>>FRACBITS) * mo->scale) < player->speed) + P_InstaThrust(mo, player->mo->angle, player->speed); + S_StartSound(player->mo, sfx_mario7); + return; + } + + if (!G_RingSlingerGametype() || player->weapondelay) + return; + + player->pflags |= PF_ATTACKDOWN; + +#define TAKE_AMMO(player, power) \ + player->powers[power]--; \ + if (player->rings < 1) \ + { \ + if (player->powers[power] > 0) \ + player->powers[power]--; \ + } \ + else \ + player->rings--; + + if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring. + goto firenormal; //code repetition sucks. + // Bounce ring + else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering]) + { + TAKE_AMMO(player, pw_bouncering); + P_SetWeaponDelay(player, TICRATE/4); + + mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING); + + if (mo) + mo->fuse = 3*TICRATE; // Bounce Ring time + } + // Rail ring + else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring]) + { + TAKE_AMMO(player, pw_railring); + P_SetWeaponDelay(player, (3*TICRATE)/2); + + mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW); + + // Rail has no unique thrown object, therefore its sound plays here. + S_StartSound(player->mo, sfx_rail1); + } + // Automatic + else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring]) + { + TAKE_AMMO(player, pw_automaticring); + player->pflags &= ~PF_ATTACKDOWN; + P_SetWeaponDelay(player, 2); + + mo = P_SpawnPlayerMissile(player->mo, MT_THROWNAUTOMATIC, MF2_AUTOMATIC); + } + // Explosion + else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring]) + { + TAKE_AMMO(player, pw_explosionring); + P_SetWeaponDelay(player, (3*TICRATE)/2); + + mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION); + } + // Grenade + else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering]) + { + TAKE_AMMO(player, pw_grenadering); + P_SetWeaponDelay(player, TICRATE/3); + + mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION); + + if (mo) + { + //P_InstaThrust(mo, player->mo->angle, FixedMul(mo->info->speed, player->mo->scale)); + mo->fuse = mo->info->reactiontime; + } + } + // Scatter + // Note: Ignores MF2_RAILRING + else if (player->currentweapon == WEP_SCATTER && player->powers[pw_scatterring]) + { + fixed_t oldz = player->mo->z; + angle_t shotangle = player->mo->angle; + angle_t oldaiming = player->aiming; + + TAKE_AMMO(player, pw_scatterring); + P_SetWeaponDelay(player, (2*TICRATE)/3); + + // Center + mo = P_SpawnPlayerMissile(player->mo, MT_THROWNSCATTER, MF2_SCATTER); + if (mo) + shotangle = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y); + + // Left + mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle-ANG2, true, MF2_SCATTER); + + // Right + mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle+ANG2, true, MF2_SCATTER); + + // Down + player->mo->z += FixedMul(12*FRACUNIT, player->mo->scale); + player->aiming += ANG1; + mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER); + + // Up + player->mo->z -= FixedMul(24*FRACUNIT, player->mo->scale); + player->aiming -= ANG2; + mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER); + + player->mo->z = oldz; + player->aiming = oldaiming; + return; + } + // No powers, just a regular ring. + else + { +firenormal: + // Infinity ring was selected. + // Mystic wants this ONLY to happen specifically if it's selected, + // and to not be able to get around it EITHER WAY with firenormal. + + // Infinity Ring + if (player->currentweapon == 0 + && player->powers[pw_infinityring]) + { + P_SetWeaponDelay(player, TICRATE/4); + + mo = P_SpawnPlayerMissile(player->mo, MT_THROWNINFINITY, 0); + + player->powers[pw_infinityring]--; + } + // Red Ring + else + { + if (player->rings <= 0) + return; + P_SetWeaponDelay(player, TICRATE/4); + + mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, 0); + + if (mo) + P_ColorTeamMissile(mo, player); + + player->rings--; + } + } + + #undef TAKE_AMMO + + if (mo) + { + if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING) + { + const boolean nblockmap = !(mo->flags & MF_NOBLOCKMAP); + for (i = 0; i < 256; i++) + { + if (nblockmap) + { + P_UnsetThingPosition(mo); + mo->flags |= MF_NOBLOCKMAP; + P_SetThingPosition(mo); + } + + if (i&1) + P_SpawnMobj(mo->x, mo->y, mo->z, MT_SPARK); + + if (P_RailThinker(mo)) + break; // mobj was removed (missile hit a wall) or couldn't move + } + + // Other rail sound plays at contact point. + S_StartSound(mo, sfx_rail2); + } + } } // diff --git a/src/sounds.c b/src/sounds.c index 5b9f83e15..3382ba8a4 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -240,8 +240,8 @@ sfxinfo_t S_sfx[NUMSFX] = // Mario {"koopfr" , true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"}, - {"mario1", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hitting a ceiling"}, - {"mario2", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Koopa shell"}, + {"mario1", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hit"}, + {"mario2", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonk"}, {"mario3", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power-up"}, {"mario4", true, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got coin"}, {"mario5", false, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boot-stomp"}, diff --git a/src/y_inter.c b/src/y_inter.c index 4d1e2baf0..8e42d480a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -331,14 +331,15 @@ void Y_IntermissionDrawer(void) if (animatetic && intertic >= animatetic) { + const INT32 scradjust = (vid.width/vid.dupx)>>3; // 40 for BASEVIDWIDTH INT32 animatetimer = (intertic - animatetic); if (animatetimer <= 14) { - xoffset1 = -(animatetimer * 40); - xoffset2 = -((animatetimer-2) * 40); - xoffset3 = -((animatetimer-4) * 40); - xoffset4 = -((animatetimer-6) * 40); - xoffset5 = -((animatetimer-8) * 40); + xoffset1 = -(animatetimer * scradjust); + xoffset2 = -((animatetimer-2) * scradjust); + xoffset3 = -((animatetimer-4) * scradjust); + xoffset4 = -((animatetimer-6) * scradjust); + xoffset5 = -((animatetimer-8) * scradjust); if (xoffset2 > 0) xoffset2 = 0; if (xoffset3 > 0) xoffset3 = 0; if (xoffset4 > 0) xoffset4 = 0; @@ -347,12 +348,12 @@ void Y_IntermissionDrawer(void) else if (animatetimer < 32) { drawsection = 1; - xoffset1 = (22-animatetimer) * 40; - xoffset2 = (24-animatetimer) * 40; - xoffset3 = (26-animatetimer) * 40; - xoffset4 = (28-animatetimer) * 40; - xoffset5 = (30-animatetimer) * 40; - xoffset6 = (32-animatetimer) * 40; + xoffset1 = (22-animatetimer) * scradjust; + xoffset2 = (24-animatetimer) * scradjust; + xoffset3 = (26-animatetimer) * scradjust; + xoffset4 = (28-animatetimer) * scradjust; + xoffset5 = (30-animatetimer) * scradjust; + xoffset6 = (32-animatetimer) * scradjust; if (xoffset1 < 0) xoffset1 = 0; if (xoffset2 < 0) xoffset2 = 0; if (xoffset3 < 0) xoffset3 = 0; From 33e0343cac248780fe4c526462154c4bbb7202b8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 15:13:09 +0100 Subject: [PATCH 158/212] * Consistency in realtime. * Actual indication of modified game status on the addons menu. * Yes, I know this has nothing to do with the branch, I'm just doing little things I found useful. --- src/m_menu.c | 14 +++++++++++--- src/p_user.c | 12 +----------- src/st_stuff.c | 21 ++++++++++++++------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 45510625e..e42c40fd6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4938,6 +4938,7 @@ static void M_DrawAddons(void) { INT32 x, y; ssize_t i, max; + const char* topstr; // hack - need to refresh at end of frame to handle addfile... if (refreshdirmenu & M_AddonsRefresh()) @@ -4949,9 +4950,16 @@ static void M_DrawAddons(void) if (addonsresponselimit) addonsresponselimit--; - V_DrawCenteredString(BASEVIDWIDTH/2, 4+offs, 0, (Playing() - ? "\x85""Adding files mid-game may cause problems." - : LOCATIONSTRING)); + if (Playing()) + topstr = "\x85""Adding files mid-game may cause problems."; + else if (savemoddata) + topstr = "\x83""Add-on has its own data, saving enabled."; + else if (modifiedgame) + topstr = "\x87""Game is modified, saving is disabled."; + else + topstr = LOCATIONSTRING; + + V_DrawCenteredString(BASEVIDWIDTH/2, 4+offs, 0, topstr); if (numwadfiles <= mainwads+1) y = 0; diff --git a/src/p_user.c b/src/p_user.c index 4c333ec50..bb5457a9a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9710,17 +9710,7 @@ void P_PlayerThink(player_t *player) // Synchronizes the "real" amount of time spent in the level. if (!player->exiting) - { - if (gametype == GT_RACE || gametype == GT_COMPETITION) - { - if (leveltime >= 4*TICRATE) - player->realtime = leveltime - 4*TICRATE; - else - player->realtime = 0; - } - else - player->realtime = leveltime; - } + player->realtime = leveltime; if (player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing] && G_GametypeHasSpectators()) { diff --git a/src/st_stuff.c b/src/st_stuff.c index 3cc40124d..14e82df1e 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -665,9 +665,9 @@ static void ST_drawTime(void) else { // Counting down the hidetime? - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (leveltime <= (hidetime*TICRATE))) + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime <= (hidetime*TICRATE))) { - tics = (hidetime*TICRATE - leveltime); + tics = (hidetime*TICRATE - stplyr->realtime); if (tics < 3*TICRATE) ST_drawRaceNum(tics); downwards = true; @@ -675,15 +675,22 @@ static void ST_drawTime(void) else { // Hidetime finish! - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (leveltime < ((hidetime+1)*TICRATE))) - ST_drawRaceNum(hidetime*TICRATE - leveltime); + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime < ((hidetime+1)*TICRATE))) + ST_drawRaceNum(hidetime*TICRATE - stplyr->realtime); // Time limit? - if (gametype != GT_RACE && gametype != GT_COMPETITION && gametype != GT_COOP && cv_timelimit.value && timelimitintics > 0) + if (gametype == GT_RACE || gametype == GT_COMPETITION) { - if (timelimitintics >= leveltime) + if (stplyr->realtime >= 4*TICRATE) + tics = stplyr->realtime - 4*TICRATE; + else + tics = 0; + } + else if (gametype != GT_COOP && cv_timelimit.value && timelimitintics > 0) + { + if (timelimitintics >= stplyr->realtime) { - tics = (timelimitintics - leveltime); + tics = (timelimitintics - stplyr->realtime); if (tics < 3*TICRATE) ST_drawRaceNum(tics); } From 13053bd1ba1500b0c5beae3a750f845a28c48bd4 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 16:07:14 +0100 Subject: [PATCH 159/212] FINAL CHANGE, I PROMISE, I THINK * MainCfg property smpstage_start - controls the special stage multiplayer games go to. --- src/dehacked.c | 16 +++++++++++++++- src/doomstat.h | 3 +-- src/g_game.c | 38 ++++++++++++++++++-------------------- src/p_user.c | 8 +++++--- src/y_inter.c | 4 ++-- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 31d4129df..9904acf78 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2670,7 +2670,21 @@ static void readmaincfg(MYFILE *f) value = get_number(word2); sstage_start = (INT16)value; - sstage_end = (INT16)(sstage_start+6); // 7 special stages total + sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo + } + else if (fastcmp(word, "SMPSTAGE_START")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + smpstage_start = (INT16)value; + smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total } else if (fastcmp(word, "REDTEAM")) { diff --git a/src/doomstat.h b/src/doomstat.h index 3a2084e29..24b9e5753 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -126,8 +126,7 @@ extern INT32 secondarydisplayplayer; // for splitscreen // Maps of special importance extern INT16 spstage_start; -extern INT16 sstage_start; -extern INT16 sstage_end; +extern INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; extern INT16 titlemap; extern boolean hidetitlepics; diff --git a/src/g_game.c b/src/g_game.c index 79f62bcd1..89a8d318b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -121,8 +121,7 @@ INT16 lastmap; // last level you were at (returning from special stages) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) INT16 spstage_start; -INT16 sstage_start; -INT16 sstage_end; +INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; INT16 titlemap = 0; boolean hidetitlepics = false; @@ -2795,7 +2794,11 @@ INT32 G_GetGametypeByName(const char *gametypestr) // boolean G_IsSpecialStage(INT32 mapnum) { - if (gametype == GT_COOP && modeattacking != ATTACKING_RECORD && mapnum >= sstage_start && mapnum <= sstage_end) + if (gametype != GT_COOP || modeattacking == ATTACKING_RECORD) + return false; + if (mapnum >= sstage_start && mapnum <= sstage_end) + return true; + if (mapnum >= smpstage_start && mapnum <= smpstage_end) return true; return false; @@ -3018,23 +3021,17 @@ static void G_DoCompleted(void) if ((gottoken = (gametype == GT_COOP && token))) { + INT16 i; token--; - if (!(emeralds & EMERALD1)) - nextmap = (INT16)(sstage_start - 1); // Special Stage 1 - else if (!(emeralds & EMERALD2)) - nextmap = (INT16)(sstage_start); // Special Stage 2 - else if (!(emeralds & EMERALD3)) - nextmap = (INT16)(sstage_start + 1); // Special Stage 3 - else if (!(emeralds & EMERALD4)) - nextmap = (INT16)(sstage_start + 2); // Special Stage 4 - else if (!(emeralds & EMERALD5)) - nextmap = (INT16)(sstage_start + 3); // Special Stage 5 - else if (!(emeralds & EMERALD6)) - nextmap = (INT16)(sstage_start + 4); // Special Stage 6 - else if (!(emeralds & EMERALD7)) - nextmap = (INT16)(sstage_start + 5); // Special Stage 7 - else + for (i = 0; i < 7; i++) + if (!(emeralds & i)) + { + nextmap = ((netgame || multiplayer) ? smpstage_start : sstage_start) + i - 1; // to special stage! + break; + } + + if (i == 7) gottoken = false; } @@ -3206,8 +3203,9 @@ void G_LoadGameSettings(void) { // defaults spstage_start = 1; - sstage_start = 50; - sstage_end = 57; // 8 special stages in vanilla SRB2 + sstage_start = smpstage_start = 50; + sstage_end = smpstage_end = 57; // 7 special stages in vanilla SRB2 + sstage_end++; // plus one weirdo // initialize free sfx slots for skin sounds S_InitRuntimeSounds(); diff --git a/src/p_user.c b/src/p_user.c index bb5457a9a..d8f406bd7 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -283,9 +283,11 @@ boolean P_PlayerMoving(INT32 pnum) // UINT8 P_GetNextEmerald(void) { - if (gamemap < sstage_start || gamemap > sstage_end) - return 0; - return (UINT8)(gamemap - sstage_start); + if (gamemap >= sstage_start && gamemap <= sstage_end) + return (UINT8)(gamemap - sstage_start); + if (gamemap >= smpstage_start || gamemap <= smpstage_end) + return (UINT8)(gamemap - smpstage_start); + return 0; } // diff --git a/src/y_inter.c b/src/y_inter.c index 8e42d480a..6937fce07 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -427,7 +427,7 @@ void Y_IntermissionDrawer(void) { boolean drawthistic = !(ALL7EMERALDS(emeralds) && (intertic & 1)); INT32 emeraldx = 152 - 3*28; - INT32 em = (gamemap - sstage_start); + INT32 em = P_GetNextEmerald(); if (em == 7) { @@ -1358,7 +1358,7 @@ void Y_StartIntermission(void) else strcpy(data.spec.passed1, "YOU GOT"); strcpy(data.spec.passed2, "A CHAOS EMERALD"); - if (gamemap > (sstage_start + 5)) + if (P_GetNextEmerald() > 6) { data.spec.passed2[15] = '?'; data.spec.passed2[16] = '\0'; From 0bb5419785862e0560cb349f44dbbb6717a20d84 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 17:11:12 +0100 Subject: [PATCH 160/212] CORRECTION OF MINOR ANNOYANCES * On request of Nev3r and Sphere (combined with my own annoyances), make SOC-loading in .pk3 files use the /SOC folder rather than the /SOCS folder. * Make the Crushstacean's claw launch sounds stop when killed. --- src/p_inter.c | 1 + src/p_setup.c | 2 +- src/w_wad.c | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 8f8c1f4fa..753134bf2 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2391,6 +2391,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_RemoveMobj(chain); chain = chainnext; } + S_StopSound(target->tracer); P_KillMobj(target->tracer, inflictor, source, damagetype); } break; diff --git a/src/p_setup.c b/src/p_setup.c index 5aedbe382..556428cbb 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3378,7 +3378,7 @@ boolean P_AddWadFile(const char *wadfilename) for (i = 0; i < numlumps; i++, lumpinfo++) { // lumpinfo = FindFolder("Lua/", &luaPos, &luaNum, lumpinfo, &numlumps, &i); -// lumpinfo = FindFolder("SOCs/", &socPos, &socNum, lumpinfo, &numlumps, &i); +// lumpinfo = FindFolder("SOC/", &socPos, &socNum, lumpinfo, &numlumps, &i); lumpinfo = FindFolder("Sounds/", &sfxPos, &sfxNum, lumpinfo, &numlumps, &i); lumpinfo = FindFolder("Music/", &musPos, &musNum, lumpinfo, &numlumps, &i); // lumpinfo = FindFolder("Sprites/", &sprPos, &sprNum, lumpinfo, &numlumps, &i); diff --git a/src/w_wad.c b/src/w_wad.c index 1b0e501a6..7babd22ef 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -194,11 +194,11 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum) for (; posStart < posEnd; posStart++) LUA_LoadLump(wadnum, posStart); } - posStart = W_CheckNumForFolderStartPK3("SOCs/", wadnum, 0); + posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0); if (posStart != INT16_MAX) { - posEnd = W_CheckNumForFolderEndPK3("SOCs/", wadnum, posStart); - posStart++; // first "lump" will be "SOCs/" folder itself, so ignore it + posEnd = W_CheckNumForFolderEndPK3("SOC/", wadnum, posStart); + posStart++; // first "lump" will be "SOC/" folder itself, so ignore it for(; posStart < posEnd; posStart++) { lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart]; From 3f7ffc61a5a9a8539421d0827183a31f3c59fcd9 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 18:48:37 +0100 Subject: [PATCH 161/212] Fixed the fireball Sal sleepily helped me with. --- src/p_user.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index d8f406bd7..21bcc985a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3513,8 +3513,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) { player->pflags |= PF_ATTACKDOWN; mo = P_SpawnPlayerMissile(player->mo, MT_FIREBALL, 0); - if (mo && ((mo->info->speed>>FRACBITS) * mo->scale) < player->speed) - P_InstaThrust(mo, player->mo->angle, player->speed); + P_InstaThrust(mo, player->mo->angle, ((mo->info->speed>>FRACBITS)*player->mo->scale) + player->speed); S_StartSound(player->mo, sfx_mario7); return; } From 01dfe31c3c22182b2bd652d0c9d0c1ee685a931a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 21:48:27 +0100 Subject: [PATCH 162/212] So MI tells me there's a good reason why that was not done. :V --- src/p_user.c | 12 +++++++++++- src/st_stuff.c | 9 +-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 21bcc985a..35af9dcea 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9711,7 +9711,17 @@ void P_PlayerThink(player_t *player) // Synchronizes the "real" amount of time spent in the level. if (!player->exiting) - player->realtime = leveltime; + { + if (gametype == GT_RACE || gametype == GT_COMPETITION) + { + if (leveltime >= 4*TICRATE) + player->realtime = leveltime - 4*TICRATE; + else + player->realtime = 0; + } + else + player->realtime = leveltime; + } if (player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing] && G_GametypeHasSpectators()) { diff --git a/src/st_stuff.c b/src/st_stuff.c index 14e82df1e..baa17e9f3 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -679,14 +679,7 @@ static void ST_drawTime(void) ST_drawRaceNum(hidetime*TICRATE - stplyr->realtime); // Time limit? - if (gametype == GT_RACE || gametype == GT_COMPETITION) - { - if (stplyr->realtime >= 4*TICRATE) - tics = stplyr->realtime - 4*TICRATE; - else - tics = 0; - } - else if (gametype != GT_COOP && cv_timelimit.value && timelimitintics > 0) + if (gametype != GT_COOP && gametype != GT_RACE && gametype != GT_COMPETITION && cv_timelimit.value && timelimitintics > 0) { if (timelimitintics >= stplyr->realtime) { From e054208a31b874b33624505a1bf11587a2678f7a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 6 Jun 2018 22:36:55 +0100 Subject: [PATCH 163/212] Fix hanging bug if A_ConnectToGround's supplied object's height is zero. --- src/p_enemy.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 7ad33ef2d..a03cec9c2 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -11391,7 +11391,8 @@ void A_ConnectToGround(mobj_t *actor) return; #endif - P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); + if (actor->subsector->sector->ffloors) + P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); if (actor->flags2 & MF2_OBJECTFLIP) { @@ -11406,15 +11407,18 @@ void A_ConnectToGround(mobj_t *actor) if (locvar2) { + workh = FixedMul(mobjinfo[locvar2].height, actor->scale); if (actor->flags2 & MF2_OBJECTFLIP) - workz -= FixedMul(mobjinfo[locvar2].height, actor->scale); + workz -= workh; work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2); + workz += dir*workh; } if (!locvar1) return; - workh = FixedMul(mobjinfo[locvar1].height, actor->scale); + if (!(workh = FixedMul(mobjinfo[locvar1].height, actor->scale))) + return; if (actor->flags2 & MF2_OBJECTFLIP) workz -= workh; From 35a5f7447ea72804e029d81e9cd37524246c6448 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 7 Jun 2018 15:10:43 +0100 Subject: [PATCH 164/212] * Remove flashing from spheres in bonus time through #ifdef. * Fix inconsistency in counting nummaprings. * Prevent perfect bonus in non-special stage NiGHTS maps. --- src/p_mobj.c | 1 + src/p_setup.c | 12 +++++++++++- src/st_stuff.c | 10 ++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 301536ef4..99ffdc871 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8765,6 +8765,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_RING: case MT_COIN: + case MT_NIGHTSSTAR: nummaprings++; default: break; diff --git a/src/p_setup.c b/src/p_setup.c index 556428cbb..17cf3bfc7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -852,7 +852,12 @@ void P_ReloadRings(void) mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) ->sector->floorheight>>FRACBITS); - P_SpawnHoopsAndRings(mt, true); + P_SpawnHoopsAndRings(mt, +#ifdef MANIASPHERES + true); +#else + !G_IsSpecialStage(gamemap)); // prevent flashing spheres in special stages +#endif } } for (i = 0; i < numHoops; i++) @@ -866,6 +871,11 @@ void P_SwitchSpheresBonusMode(boolean bonustime) mobj_t *mo; thinker_t *th; +#ifndef MANIASPHERES + if (G_IsSpecialStage(gamemap)) // prevent flashing spheres in special stages + return; +#endif + // scan the thinkers to find spheres to switch for (th = thinkercap.next; th != &thinkercap; th = th->next) { diff --git a/src/st_stuff.c b/src/st_stuff.c index baa17e9f3..1fd6a6186 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1577,11 +1577,13 @@ static void ST_drawNiGHTSHUD(void) #endif ST_DrawTopLeftOverlayPatch(16, 8, nbracket); if (G_IsSpecialStage(gamemap)) - ST_DrawTopLeftOverlayPatch(24, 16, ((stplyr->bonustime && (leveltime & 4)) ? nssbon : nsshud)); - else if (stplyr->bonustime) - ST_DrawTopLeftOverlayPatch(24, 16, nbon[(leveltime/2)%12]); + ST_DrawTopLeftOverlayPatch(24, 16, ( +#ifdef MANIASPHERES + (stplyr->bonustime && (leveltime & 4)) ? nssbon : +#endif + nsshud)); else - ST_DrawTopLeftOverlayPatch(24, 16, nhud[(leveltime/2)%12]); + ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12))); if (G_IsSpecialStage(gamemap)) { From a7c6977b6e04b2dc40c10498a6e34d8dfd15b232 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 8 Jun 2018 17:16:20 +0100 Subject: [PATCH 165/212] * Make bomb spheres respawn with new laps * Make the mapthing detection for stuff to be spawned by P_SpawnHoopsAndRings more consistent. * Make NiGHTS stuff prevent perfect bonus. --- src/p_mobj.c | 183 +++++++++++++++++++++++++------------------------- src/p_setup.c | 15 +++-- src/y_inter.c | 2 +- 3 files changed, 100 insertions(+), 100 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 99ffdc871..2dbce6033 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8753,6 +8753,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_NIGHTSDRONE: if (G_IsSpecialStage(gamemap)) mobj->flags2 |= MF2_DONTDRAW; + nummaprings = -1; // no perfect bonus, rings are free break; case MT_EGGCAPSULE: mobj->extravalue1 = -1; // timer for how long a player has been at the capsule @@ -8766,7 +8767,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_RING: case MT_COIN: case MT_NIGHTSSTAR: - nummaprings++; + if (nummaprings >= 0) + nummaprings++; default: break; } @@ -8900,6 +8902,7 @@ void P_RemoveMobj(mobj_t *mobj) if (mobj->spawnpoint && (mobj->type == MT_RING || mobj->type == MT_COIN + || mobj->type == MT_NIGHTSSTAR || mobj->type == MT_REDTEAMRING || mobj->type == MT_BLUETEAMRING || P_WeaponOrPanel(mobj->type)) @@ -9303,7 +9306,7 @@ void P_RespawnSpecials(void) #endif ss->sector->ceilingheight) - (mthing->options >> ZSHIFT) * FRACUNIT; if (mthing->options & MTF_AMBUSH - && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i))) + && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || i == MT_NIGHTSSTAR || P_WeaponOrPanel(i))) z -= 24*FRACUNIT; z -= mobjinfo[i].height; // Don't forget the height! } @@ -9315,7 +9318,7 @@ void P_RespawnSpecials(void) #endif ss->sector->floorheight) + (mthing->options >> ZSHIFT) * FRACUNIT; if (mthing->options & MTF_AMBUSH - && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i))) + && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || i == MT_NIGHTSSTAR || P_WeaponOrPanel(i))) z += 24*FRACUNIT; } @@ -9714,12 +9717,11 @@ void P_SpawnMapThing(mapthing_t *mthing) else if (mthing->type == 750) // Slope vertex point (formerly chaos spawn) return; - else if (mthing->type == 300 // Ring - || mthing->type == 308 || mthing->type == 309 // Team Rings - || mthing->type == 1706 // Nights Wing - || (mthing->type >= 600 && mthing->type <= 609) // Placement patterns - || mthing->type == 1705 || mthing->type == 1713 // NiGHTS Hoops - || mthing->type == 1800) // Mario Coin + else if (mthing->type == mobjinfo[MT_RING].doomednum || mthing->type == mobjinfo[MT_COIN].doomednum + || mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum + || mthing->type == mobjinfo[MT_BLUESPHERE].doomednum || mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum + || (mthing->type >= 600 && mthing->type <= 609) // circles and diagonals + || mthing->type == 1705 || mthing->type == 1713 || mthing->type == 1800) // hoops { // Don't spawn hoops, wings, or rings yet! return; @@ -9842,9 +9844,7 @@ void P_SpawnMapThing(mapthing_t *mthing) if (gametype != GT_CTF) // CTF specific things { - if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING) - i = MT_RING; - else if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX) + if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX) i = MT_RING_BOX; else if (i == MT_BLUEFLAG || i == MT_REDFLAG) return; // No flags in non-CTF modes! @@ -9882,11 +9882,9 @@ void P_SpawnMapThing(mapthing_t *mthing) { if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX || i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX - || i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX) - return; // No shields in Ultimate mode - - if (i == MT_RING_BOX && !G_IsSpecialStage(gamemap)) - return; // No rings in Ultimate mode (except special stages) + || i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX + || i == MT_RING_BOX) + return; // No rings or shields in Ultimate mode // Don't include the gold repeating boxes here please. // They're likely facets of the level's design and therefore required to progress. @@ -9911,7 +9909,7 @@ void P_SpawnMapThing(mapthing_t *mthing) ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS); else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE) z = ONFLOORZ; - else if (i == MT_BOMBSPHERE || i == MT_SPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN) + else if (i == MT_SPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN) { if (mthing->options & MTF_OBJECTFLIP) { @@ -10665,7 +10663,7 @@ ML_EFFECT4 : Don't clip inside the ground } //count 10 ring boxes into the number of rings equation too. - if (i == MT_RING_BOX) + if (i == MT_RING_BOX && nummaprings >= 0) nummaprings += 10; if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED) @@ -11080,79 +11078,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) return; } - // All manners of rings and coins - else if (mthing->type == mobjinfo[MT_RING].doomednum || mthing->type == mobjinfo[MT_COIN].doomednum || - mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum || - mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) - { - - // Which ringthing to use - if (mthing->type == mobjinfo[MT_COIN].doomednum) - ringthing = MT_COIN; - else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF - ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; - else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto - ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; - else if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) - ringthing = MT_BLUESPHERE; - - if (ringthing != MT_BLUESPHERE && ultimatemode) - return; // No rings in Ultimate! - - if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) - ringthing = ((ringthing == MT_BLUESPHERE) ? MT_NIGHTSCHIP : MT_NIGHTSSTAR); - - // Set proper height - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : -#endif - sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); - } - else - { - z = -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); - } - - if (mthing->options & MTF_AMBUSH) // Special flag for rings - { - if (mthing->options & MTF_OBJECTFLIP) - z -= 24*FRACUNIT; - else - z += 24*FRACUNIT; - } - - mthing->z = (INT16)(z>>FRACBITS); - - mobj = P_SpawnMobj(x, y, z, ringthing); - mobj->spawnpoint = mthing; - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mthing->mobj = mobj; - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) - P_SetMobjState(mobj, mobj->info->raisestate); - else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); - } // *** // Special placement patterns // *** @@ -11347,7 +11272,79 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) P_SetMobjState(mobj, mobj->info->seestate); } - return; + } + // All manners of rings and coins + else + { + + // Which ringthing to use + if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) + ringthing = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? MT_NIGHTSCHIP : MT_BLUESPHERE; + else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) + ringthing = MT_BOMBSPHERE; + else + { + if (ultimatemode) + return; // No rings in Ultimate! + + if (mthing->type == mobjinfo[MT_COIN].doomednum) + ringthing = MT_COIN; + else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF + ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; + else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto + ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; + } + + // Set proper height + if (mthing->options & MTF_OBJECTFLIP) + { + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[ringthing].height; + if (mthing->options >> ZSHIFT) + z -= ((mthing->options >> ZSHIFT) << FRACBITS); + } + else + { + z = +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; + if (mthing->options >> ZSHIFT) + z += ((mthing->options >> ZSHIFT) << FRACBITS); + } + + if (mthing->options & MTF_AMBUSH) // Special flag for rings + { + if (mthing->options & MTF_OBJECTFLIP) + z -= 24*FRACUNIT; + else + z += 24*FRACUNIT; + } + + mthing->z = (INT16)(z>>FRACBITS); + + mobj = P_SpawnMobj(x, y, z, ringthing); + mobj->spawnpoint = mthing; + + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + } + + mobj->angle = FixedAngle(mthing->angle*FRACUNIT); + mthing->mobj = mobj; + if (mthing->options & MTF_AMBUSH) + mobj->flags2 |= MF2_AMBUSH; + + if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) + P_SetMobjState(mobj, mobj->info->raisestate); + else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); } } diff --git a/src/p_setup.c b/src/p_setup.c index 17cf3bfc7..17c5739ef 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -842,9 +842,10 @@ void P_ReloadRings(void) for (i = 0; i < nummapthings; i++, mt++) { // Notice an omission? We handle hoops differently. - if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum - || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_COIN].doomednum - || (mt->type >= 600 && mt->type <= 609)) // circles + if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_COIN].doomednum + || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum + || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum + || (mt->type >= 600 && mt->type <= 609)) // circles and diagonals { mt->mobj = NULL; @@ -1085,9 +1086,11 @@ static void P_LoadThings(void) mt = mapthings; for (i = 0; i < nummapthings; i++, mt++) { - if (mt->type == 300 || mt->type == 308 || mt->type == 309 - || mt->type == 1706 || (mt->type >= 600 && mt->type <= 609) - || mt->type == 1705 || mt->type == 1713 || mt->type == 1800) + if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_COIN].doomednum + || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum + || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum + || (mt->type >= 600 && mt->type <= 609) // circles and diagonals + || mt->type == 1705 || mt->type == 1713 || mt->type == 1800) // hoops { mt->mobj = NULL; diff --git a/src/y_inter.c b/src/y_inter.c index 6937fce07..a26f59ce8 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1801,7 +1801,7 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct) if (!playeringame[i]) continue; sharedringtotal += players[i].rings; } - if (!sharedringtotal || sharedringtotal < nummaprings) + if (!sharedringtotal || nummaprings == -1 || sharedringtotal < nummaprings) data.coop.gotperfbonus = 0; else data.coop.gotperfbonus = 1; From 30843fecb60b1bff2ac7a7ca6f10398afa717005 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 8 Jun 2018 21:11:59 +0100 Subject: [PATCH 166/212] My little experiments with super transformation animation! (Requires new player.dta.) --- src/info.c | 8 ++++---- src/p_user.c | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/info.c b/src/info.c index 3a864217c..ad5d604e4 100644 --- a/src/info.c +++ b/src/info.c @@ -723,12 +723,12 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_MLEL, 35, {NULL}, 0, 0, S_PLAY_WALK}, // S_PLAY_MELEE_LANDING // SF_SUPER - {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER, 3, {NULL}, 0, 0, S_PLAY_SUPER_TRANS2}, // S_PLAY_SUPER_TRANS1 + {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_ANIMATE, 7, {NULL}, 0, 4, S_PLAY_SUPER_TRANS2}, // S_PLAY_SUPER_TRANS1 {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER, 3, {NULL}, 0, 0, S_PLAY_SUPER_TRANS3}, // S_PLAY_SUPER_TRANS2 {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_SUPER_TRANS4}, // S_PLAY_SUPER_TRANS3 {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_SUPER_TRANS5}, // S_PLAY_SUPER_TRANS4 {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_SUPER_TRANS6}, // S_PLAY_SUPER_TRANS5 - {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 20, {A_FadeOverlay}, 0, 0, S_PLAY_FLOAT}, // S_PLAY_SUPER_TRANS6 + {SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 19, {A_FadeOverlay}, 0, 0, S_PLAY_FALL}, // S_PLAY_SUPER_TRANS6 {SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY @@ -743,12 +743,12 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_SIGN, 1, {NULL}, 0, 24, S_PLAY_SIGN}, // S_PLAY_SIGN // NiGHTS Player, transforming - {SPR_PLAY, SPR2_TRNS, 3, {NULL}, 0, 0, S_PLAY_NIGHTS_TRANS2}, // S_PLAY_NIGHTS_TRANS1 + {SPR_PLAY, SPR2_TRNS|FF_ANIMATE, 7, {NULL}, 0, 4, S_PLAY_NIGHTS_TRANS2}, // S_PLAY_NIGHTS_TRANS1 {SPR_PLAY, SPR2_TRNS, 3, {NULL}, 0, 0, S_PLAY_NIGHTS_TRANS3}, // S_PLAY_NIGHTS_TRANS2 {SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_TRANS4}, // S_PLAY_NIGHTS_TRANS3 {SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_TRANS5}, // S_PLAY_NIGHTS_TRANS4 {SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_TRANS6}, // S_PLAY_NIGHTS_TRANS5 - {SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 25, {A_FadeOverlay}, 4, 0, S_PLAY_NIGHTS_FLOAT}, // S_PLAY_NIGHTS_TRANS5 + {SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 21, {A_FadeOverlay}, 2, 0, S_PLAY_NIGHTS_FLOAT}, // S_PLAY_NIGHTS_TRANS5 // NiGHTS Player, stand, float, pain, pull and attack {SPR_PLAY, SPR2_NSTD, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_STAND}, // S_PLAY_NIGHTS_STAND diff --git a/src/p_user.c b/src/p_user.c index 35af9dcea..8d5f6c05c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1048,8 +1048,6 @@ void P_DoSuperTransformation(player_t *player, boolean giverings) // Transformation animation P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_TRANS1); - player->pflags |= PF_NOJUMPDAMAGE; // just to avoid recurling but still allow thok - if (giverings) player->rings = 50; From adc0e3d6c306d2f773b849159a61866e8011c37a Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 8 Jun 2018 22:30:38 +0100 Subject: [PATCH 167/212] Kart Krew discovered a crash, and I was already fiddling around with this, so... --- src/p_mobj.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 2dbce6033..efac937b8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9728,7 +9728,10 @@ void P_SpawnMapThing(mapthing_t *mthing) } // check for players specially - if (mthing->type > 0 && mthing->type <= 32) +#if MAXPLAYERS > 32 +You should think about modifying the deathmatch starts to take full advantage of this! +#endif + if (mthing->type > 0 && mthing->type <= MAXPLAYERS) { // save spots for respawning in network games if (!metalrecording) From 16c8d17a4c5c0ba73fe0d3f7a2a891743fd1674a Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 9 Jun 2018 18:06:14 +0100 Subject: [PATCH 168/212] * (probably) fix crash with followmobj not being properly invalidated on mapload * clean up P_LevelInitStuff * [unrelated] make the bot use directionchar if you are (i only realised it wasn't as a consequence of testing this) --- src/b_bot.c | 3 +-- src/p_setup.c | 54 ++++++++++++++++++++++++--------------------------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/b_bot.c b/src/b_bot.c index 543bcb183..5f884896f 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -275,8 +275,7 @@ void B_RespawnBot(INT32 playernum) player->accelstart = sonic->player->accelstart; player->thrustfactor = sonic->player->thrustfactor; player->normalspeed = sonic->player->normalspeed; - player->pflags |= PF_AUTOBRAKE; - player->pflags &= ~PF_DIRECTIONCHAR; + player->pflags |= PF_AUTOBRAKE|(sonic->player->pflags & PF_DIRECTIONCHAR); P_TeleportMove(tails, x, y, z); if (player->charability == CA_FLY) diff --git a/src/p_setup.c b/src/p_setup.c index 17c5739ef..39c675318 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2360,6 +2360,8 @@ static void P_LevelInitStuff(void) } } + countdown = countdown2 = 0; + for (i = 0; i < MAXPLAYERS; i++) { if (canresetlives && (netgame || multiplayer) && playeringame[i] && (gametype == GT_COMPETITION || players[i].lives <= 0)) @@ -2368,42 +2370,36 @@ static void P_LevelInitStuff(void) players[i].lives = cv_startinglives.value; } - players[i].realtime = countdown = countdown2 = 0; + // obliteration station... + players[i].rings = players[i].spheres = + players[i].xtralife = players[i].deadtimer = + players[i].numboxes = players[i].totalring = + players[i].laps = players[i].aiming = + players[i].losstime = players[i].timeshit = + players[i].marescore = players[i].lastmarescore = + players[i].maxlink = players[i].startedtime = + players[i].finishedtime = players[i].finishedspheres = + players[i].lastmare = players[i].marebegunat = + players[i].textvar = players[i].texttimer = + players[i].linkcount = players[i].linktimer = + players[i].flyangle = players[i].anotherflyangle = + players[i].nightstime = players[i].mare = + players[i].realtime = players[i].exiting = 0; + // i guess this could be part of the above but i feel mildly uncomfortable implicitly casting players[i].gotcontinue = false; - players[i].xtralife = players[i].deadtimer = players[i].numboxes = players[i].totalring = players[i].laps = 0; - players[i].rings = 0; - players[i].spheres = 0; - players[i].aiming = 0; - players[i].pflags &= ~PF_GAMETYPEOVER; - - players[i].losstime = 0; - players[i].timeshit = 0; - - players[i].marescore = players[i].lastmarescore = players[i].maxlink = 0; - players[i].startedtime = players[i].finishedtime = players[i].finishedspheres = 0; - players[i].lastmare = players[i].marebegunat = 0; - - // Don't show anything - players[i].textvar = players[i].texttimer = 0; - - players[i].linkcount = players[i].linktimer = 0; - players[i].flyangle = players[i].anotherflyangle = 0; - players[i].nightstime = players[i].mare = 0; - P_SetTarget(&players[i].capsule, NULL); + // aha, the first evidence this shouldn't be a memset! players[i].drillmeter = 40*20; - players[i].exiting = 0; P_ResetPlayer(&players[i]); + // hit these too + players[i].pflags &= ~(PF_GAMETYPEOVER|PF_TRANSFERTOCLOSEST); - players[i].mo = NULL; - - // we must unset axis details too - players[i].axis1 = players[i].axis2 = NULL; - - // and this stupid flag as a result - players[i].pflags &= ~PF_TRANSFERTOCLOSEST; + // unset ALL the pointers. P_SetTarget isn't needed here because if this + // function is being called we're just going to clobber the data anyways + players[i].mo = players[i].followmobj = players[i].awayviewmobj = NULL; + players[i].capsule = players[i].axis1 = players[i].axis2 = NULL; } } From 9a309b29c66e55be342d0153fdd83ea0dc9c36df Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 9 Jun 2018 18:20:59 +0100 Subject: [PATCH 169/212] * Made P_LevelInitStuff's stuff clearer. * Changed a caption I'd meant to modify earlier in the branch's lifespan. --- src/p_setup.c | 28 ++++++++++++++-------------- src/sounds.c | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 39c675318..dc963c6c7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2371,19 +2371,19 @@ static void P_LevelInitStuff(void) } // obliteration station... - players[i].rings = players[i].spheres = - players[i].xtralife = players[i].deadtimer = - players[i].numboxes = players[i].totalring = - players[i].laps = players[i].aiming = - players[i].losstime = players[i].timeshit = - players[i].marescore = players[i].lastmarescore = - players[i].maxlink = players[i].startedtime = - players[i].finishedtime = players[i].finishedspheres = - players[i].lastmare = players[i].marebegunat = - players[i].textvar = players[i].texttimer = - players[i].linkcount = players[i].linktimer = - players[i].flyangle = players[i].anotherflyangle = - players[i].nightstime = players[i].mare = + players[i].rings = players[i].spheres =\ + players[i].xtralife = players[i].deadtimer =\ + players[i].numboxes = players[i].totalring =\ + players[i].laps = players[i].aiming =\ + players[i].losstime = players[i].timeshit =\ + players[i].marescore = players[i].lastmarescore =\ + players[i].maxlink = players[i].startedtime =\ + players[i].finishedtime = players[i].finishedspheres =\ + players[i].lastmare = players[i].marebegunat =\ + players[i].textvar = players[i].texttimer =\ + players[i].linkcount = players[i].linktimer =\ + players[i].flyangle = players[i].anotherflyangle =\ + players[i].nightstime = players[i].mare =\ players[i].realtime = players[i].exiting = 0; // i guess this could be part of the above but i feel mildly uncomfortable implicitly casting @@ -2398,7 +2398,7 @@ static void P_LevelInitStuff(void) // unset ALL the pointers. P_SetTarget isn't needed here because if this // function is being called we're just going to clobber the data anyways - players[i].mo = players[i].followmobj = players[i].awayviewmobj = NULL; + players[i].mo = players[i].followmobj = players[i].awayviewmobj =\ players[i].capsule = players[i].axis1 = players[i].axis2 = NULL; } } diff --git a/src/sounds.c b/src/sounds.c index 3382ba8a4..35b21e590 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -299,7 +299,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k3d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pop"}, {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"}, {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"}, - {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction shot"}, + {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction blast"}, {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"}, {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"}, {"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"}, From 3bc8987586688367fd80c8493907132f4136c473 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 9 Jun 2018 19:22:28 +0100 Subject: [PATCH 170/212] Disable bumper score icon in NiGHTS to match enemies. --- src/p_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index c24dd6791..8353a1384 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -391,8 +391,8 @@ springstate: P_SetMobjState(spring, spring->info->raisestate); if (object->player && spring->reactiontime && !(spring->info->flags & MF_ENEMY)) { - mobj_t *scoremobj = P_SpawnMobj(spring->x, spring->y, spring->z + (spring->height/2), MT_SCORE); - P_SetMobjState(scoremobj, mobjinfo[MT_SCORE].spawnstate+11); + if (object->player->powers[pw_carry] != CR_NIGHTSMODE) // don't make graphic in NiGHTS + P_SetMobjState(P_SpawnMobj(spring->x, spring->y, spring->z + (spring->height/2), MT_SCORE), mobjinfo[MT_SCORE].spawnstate+11); P_AddPlayerScore(object->player, 10); spring->reactiontime--; } From eb948cf78a36fd568cddae9de9faef4285fcca65 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 9 Jun 2018 21:12:56 +0100 Subject: [PATCH 171/212] Restore music upon successful completion of old-style special stage --- src/p_tick.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_tick.c b/src/p_tick.c index 7d59aba6f..a51ce2eb6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -483,6 +483,7 @@ static inline void P_DoSpecialStageStuff(void) sstimer = 0; P_GiveEmerald(true); + P_RestoreMusic(&players[consoleplayer]); } } else From c5ab2ffa11ee412c646c5539faf413692d90996e Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 9 Jun 2018 21:42:37 +0100 Subject: [PATCH 172/212] At FF and Sphere's suggestion, make the ring hoops work natively in normal stages and require more replacing for special stage conversion purposes. --- src/p_mobj.c | 62 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index efac937b8..2131c42d1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10809,6 +10809,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sector_t *sec; TVector v, *res; angle_t closestangle, fa; + boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; @@ -11095,7 +11096,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (ultimatemode) return; // No rings in Ultimate! - if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + if (nightsreplace) ringthing = MT_NIGHTSSTAR; for (r = 1; r <= 5; r++) @@ -11147,7 +11148,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (ultimatemode) return; // No rings in Ultimate! - if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + if (nightsreplace) ringthing = MT_NIGHTSSTAR; closestangle = FixedAngle(mthing->angle*FRACUNIT); @@ -11217,33 +11218,42 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) closestangle = FixedAngle(mthing->angle*FRACUNIT); + switch (mthing->type) + { + case 604: + case 605: + if (ultimatemode) + return; // No rings in Ultimate! + if (nightsreplace) + ringthing = MT_NIGHTSSTAR; + break; + case 608: + case 609: + /*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere + break;*/ + case 606: + case 607: + ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; + break; + default: + break; + } + // Create the hoop! for (i = 0; i < numitems; i++) { - switch (mthing->type) + if (mthing->type == 608 || mthing->type == 609) { - case 604: - case 605: - ringthing = MT_BLUESPHERE; - break; - case 608: - case 609: - ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; - break; - case 606: - case 607: - ringthing = MT_RING; - break; - default: - break; + if (i & 1) + { + if (ultimatemode) + continue; // No rings in Ultimate! + ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING; + } + else + ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; } - if (ringthing != MT_BLUESPHERE && ultimatemode) - continue; // No rings in Ultimate! - - if ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) - ringthing = ((ringthing == MT_BLUESPHERE) ? MT_NIGHTSCHIP : MT_NIGHTSSTAR); - fa = i*FINEANGLES/numitems; v[0] = FixedMul(FINECOSINE(fa),size); v[1] = 0; @@ -11282,7 +11292,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) // Which ringthing to use if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) - ringthing = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? MT_NIGHTSCHIP : MT_BLUESPHERE; + ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) ringthing = MT_BOMBSPHERE; else @@ -11290,7 +11300,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (ultimatemode) return; // No rings in Ultimate! - if (mthing->type == mobjinfo[MT_COIN].doomednum) + if (nightsreplace) + ringthing = MT_NIGHTSSTAR; + else if (mthing->type == mobjinfo[MT_COIN].doomednum) ringthing = MT_COIN; else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; From ea915e5778702dbb86cb88a42c165f45489199a2 Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 9 Jun 2018 22:58:03 +0100 Subject: [PATCH 173/212] Fix papersprites more for real this time (Seperate AL and AR sprites were broken, I figured out I was a dunce, oh noey) --- src/hardware/hw_main.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 72c487565..2f49ed7d1 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5248,8 +5248,7 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif - if (sprframe->rotate != SRF_SINGLE) - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + ang = R_PointToAngle (thing->x, thing->y) - thing->angle; if (sprframe->rotate == SRF_SINGLE) { @@ -5258,7 +5257,7 @@ static void HWR_ProjectSprite(mobj_t *thing) lumpoff = sprframe->lumpid[0]; //Fab: see note above flip = sprframe->flip; // Will only be 0x00 or 0xFF - if (papersprite && (R_PointToAngle (thing->x, thing->y) - thing->angle < ANGLE_180)) + if (papersprite && ang < ANGLE_180) { if (flip) flip = 0; @@ -5279,6 +5278,14 @@ static void HWR_ProjectSprite(mobj_t *thing) //Fab: lumpid is the index for spritewidth,spriteoffset... tables lumpoff = sprframe->lumpid[rot]; flip = sprframe->flip & (1<skin && ((skin_t *)thing->skin)->flags & SF_HIRES) @@ -5286,16 +5293,8 @@ static void HWR_ProjectSprite(mobj_t *thing) if (papersprite) { - if (flip && sprframe->rotate != SRF_SINGLE) - { - rightsin = FIXED_TO_FLOAT(FINESINE((thing->angle+ANGLE_180)>>ANGLETOFINESHIFT)); - rightcos = FIXED_TO_FLOAT(FINECOSINE((thing->angle+ANGLE_180)>>ANGLETOFINESHIFT)); - } - else - { - rightsin = FIXED_TO_FLOAT(FINESINE((thing->angle)>>ANGLETOFINESHIFT)); - rightcos = FIXED_TO_FLOAT(FINECOSINE((thing->angle)>>ANGLETOFINESHIFT)); - } + rightsin = FIXED_TO_FLOAT(FINESINE((thing->angle)>>ANGLETOFINESHIFT)); + rightcos = FIXED_TO_FLOAT(FINECOSINE((thing->angle)>>ANGLETOFINESHIFT)); } else { From 934c1789414dca04376de2a41f39ba5e911fc4e6 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 10 Jun 2018 20:02:34 +0100 Subject: [PATCH 174/212] Remove unpopular exitlevel limitation. --- src/d_netcmd.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index bd1f93512..25c4147e5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3929,28 +3929,7 @@ static void Command_ExitLevel_f(void) else if (gamestate != GS_LEVEL || demoplayback) CONS_Printf(M_GetText("You must be in a level to use this.\n")); else - { - if ((netgame || multiplayer) - && ((mapheaderinfo[gamemap-1]->nextlevel <= 0) - || (mapheaderinfo[gamemap-1]->nextlevel > NUMMAPS) - || !(mapvisited[mapheaderinfo[gamemap-1]->nextlevel-1]))) - { - UINT8 i; - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && players[i].exiting) - break; - } - - if (i == MAXPLAYERS) - { - CONS_Printf(M_GetText("Someone must finish the level for you to use this.\n")); - return; - } - } - SendNetXCmd(XD_EXITLEVEL, NULL, 0); - } } static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) From 54e92a96b35dedce8cbbd4ab597da1d2ef52973c Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 11 Jun 2018 19:36:47 +0100 Subject: [PATCH 175/212] backport fix to L/R sprite loading code from internal basically we don't want L/R sprites to always be flipped, for obvious reasons --- src/r_things.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/r_things.c b/src/r_things.c index 1352209d7..fa0316bf7 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -148,7 +148,11 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch sprtemp[frame].lumppat[r + rightfactor] = lumppat; sprtemp[frame].lumpid[r + rightfactor] = lumpid; } - sprtemp[frame].flip |= (flipped ? (0x0F << rightfactor) : 0); // 00001111 or 11110000 in binary, depending on rotation being ROT_L or ROT_R + if (flipped) + sprtemp[frame].flip |= (0x0F< Date: Mon, 11 Jun 2018 20:23:00 +0100 Subject: [PATCH 176/212] Do the usual hack for loading a lump from a map WAD in a pk3, but this time for P_LoadThingsOnly --- src/p_setup.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index a5544c26b..127a5b880 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2402,7 +2402,17 @@ void P_LoadThingsOnly(void) P_LevelInitStuff(); - P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 + { // HACK: Open wad file rather quickly so we can use the things lump + UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); + filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); + fileinfo += ML_THINGS; // we only need the THINGS lump + P_PrepareRawThings(wadData + fileinfo->filepos, fileinfo->size); + Z_Free(wadData); // we're done with this now + } + else // phew it's just a WAD + P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + P_LoadThings(); From a56811cb0d898f224c4ef3306646264922a7bfc3 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 12 Jun 2018 01:08:03 +0100 Subject: [PATCH 177/212] Fix all the Floral Fieldsing pv2 discovered. --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 719e8fdce..5b62875cb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3025,7 +3025,7 @@ static void G_DoCompleted(void) token--; for (i = 0; i < 7; i++) - if (!(emeralds & i)) + if (!(emeralds & (1< Date: Tue, 12 Jun 2018 02:26:42 +0100 Subject: [PATCH 178/212] Fix the starposts not being cleared properly. --- src/p_inter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 753134bf2..033d148a8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -105,10 +105,10 @@ void P_ClearStarPost(INT32 postnum) mo2 = (mobj_t *)th; if (mo2->type != MT_STARPOST) - return; + continue; if (mo2->health > postnum) - return; + continue; P_SetMobjState(mo2, mo2->info->seestate); } From 37e1fae07d984fe5466d587c66a003759ce919e4 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 13 Jun 2018 18:10:32 +0100 Subject: [PATCH 179/212] Fixing dehacked.c consistency. --- src/dehacked.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 9904acf78..c4d0bc104 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4391,12 +4391,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Gravity Wells for special stages "S_GRAVWELLGREEN", - "S_GRAVWELLGREEN2", - "S_GRAVWELLGREEN3", - "S_GRAVWELLRED", - "S_GRAVWELLRED2", - "S_GRAVWELLRED3", // Individual Team Rings "S_TEAMRING", @@ -4701,6 +4696,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_THUNDERCOIN_ICON1", "S_THUNDERCOIN_ICON2", + // --- + "S_ROCKET", "S_LASER", @@ -6080,7 +6077,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SHLEEPBOUNCE2", "S_SHLEEPBOUNCE3", - // Secret badniks and hazards, shhhh "S_PENGUINATOR_LOOK", "S_PENGUINATOR_WADDLE1", From 2ab1d91ec902bb993d461b749bc44514a731dfbf Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 19 Jun 2018 21:58:49 +0100 Subject: [PATCH 180/212] * Fix nextstate, radius, and painchance of fire torch decoration. * Fix waving flag object type's... flags. *womp womp* --- src/info.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/info.c b/src/info.c index ad5d604e4..225e47d80 100644 --- a/src/info.c +++ b/src/info.c @@ -2145,7 +2145,7 @@ state_t states[NUMSTATES] = {SPR_FLMH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FLAMEHOLDER - {SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_NULL}, // S_FIRETORCH + {SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH}, // S_FIRETORCH {SPR_CFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG {SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG @@ -10505,7 +10505,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance + MT_FLAMEPARTICLE, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate @@ -10513,7 +10513,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 24*FRACUNIT, // radius + 16*FRACUNIT, // radius 80*FRACUNIT, // height 0, // display offset 100, // mass @@ -10546,7 +10546,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_PUSHABLE, // flags + MF_SOLID, // flags S_NULL // raisestate }, @@ -10573,7 +10573,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags S_NULL // raisestate }, From 1ffa45f875f1df64d44e4b4b9c286321975324c3 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 19 Jun 2018 23:16:49 +0100 Subject: [PATCH 181/212] Rework software coronas a bit, apply them to the flame and flame holder too, and spawn them only if MTF_EXTRA is given. --- src/p_mobj.c | 87 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 2131c42d1..be373fbf4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7540,6 +7540,8 @@ void P_MobjThinker(mobj_t *mobj) { if (!mobj->target || P_MobjWasRemoved(mobj->target)) { + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) + P_RemoveMobj(mobj->tracer); P_RemoveMobj(mobj); return; } @@ -7547,6 +7549,12 @@ void P_MobjThinker(mobj_t *mobj) if (!(mobj->eflags & MFE_VERTICALFLIP)) mobj->z += mobj->target->height; } + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) + { + mobj->tracer->z = mobj->z + P_MobjFlip(mobj)*20*mobj->scale; + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->tracer->z += mobj->height; + } break; case MT_WAVINGFLAG: { @@ -8692,29 +8700,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } } break; - case MT_CANDLE: - case MT_CANDLEPRICKET: - { - // Fake corona!! - mobj_t *corona = P_SpawnMobjFromMobj(mobj, 0, 0, ((mobj->type == MT_CANDLE) ? 40 : 176)<tracer, mobj); - //corona->flags2 |= MF2_LINKDRAW; -- crash??????? can't debug right now... - corona->sprite = SPR_FLAM; - corona->frame = (FF_FULLBRIGHT|FF_TRANS90|12); - corona->tics = -1; - if (mobj->type == MT_CANDLE) - P_SetScale(corona, (corona->destscale = mobj->scale*3)); - } - break; - case MT_JACKO1: - case MT_JACKO2: - case MT_JACKO3: - { - mobj_t *overlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&overlay->target, mobj); - P_SetMobjState(overlay, mobj->info->raisestate); - } - break; case MT_EGGMOBILE2: // Special condition for the 2nd boss. mobj->watertop = mobj->info->speed; @@ -10041,6 +10026,54 @@ You should think about modifying the deathmatch starts to take full advantage of if (mthing->angle > 0) mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1; break; +#define makesoftwarecorona(mo, h) \ + corona = P_SpawnMobjFromMobj(mo, 0, 0, h<sprite = SPR_FLAM;\ + corona->frame = (FF_FULLBRIGHT|FF_TRANS90|12);\ + corona->tics = -1 + case MT_FLAME: + if (mthing->options & MTF_EXTRA) + { + mobj_t *corona; + makesoftwarecorona(mobj, 20); + P_SetScale(corona, (corona->destscale = mobj->scale*3)); + P_SetTarget(&mobj->tracer, corona); + } + break; + case MT_FLAMEHOLDER: + if (!(mthing->options & MTF_OBJECTSPECIAL)) // Spawn the fire + { + mobj_t *flame = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); + P_SetTarget(&flame->target, mobj); + flame->flags2 |= MF2_BOSSNOTRAP; + if (mthing->options & MTF_EXTRA) + { + mobj_t *corona; + makesoftwarecorona(flame, 20); + P_SetScale(corona, (corona->destscale = flame->scale*3)); + P_SetTarget(&flame->tracer, corona); + } + } + break; + case MT_CANDLE: + case MT_CANDLEPRICKET: + if (mthing->options & MTF_EXTRA) + { + mobj_t *corona; + makesoftwarecorona(mobj, ((mobj->type == MT_CANDLE) ? 42 : 176)); + } + break; +#undef makesoftwarecorona + case MT_JACKO1: + case MT_JACKO2: + case MT_JACKO3: + if (!(mthing->options & MTF_EXTRA)) // take the torch out of the crafting recipe + { + mobj_t *overlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, mobj); + P_SetMobjState(overlay, mobj->info->raisestate); + } + break; case MT_WATERDRIP: if (mthing->angle) mobj->tics = 3*TICRATE + mthing->angle; @@ -10526,14 +10559,6 @@ ML_EFFECT4 : Don't clip inside the ground #undef doleaf } break; - case MT_FLAMEHOLDER: - if (!(mthing->options & MTF_OBJECTSPECIAL)) // Spawn the fire - { - mobj_t *flame = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); - P_SetTarget(&flame->target, mobj); - flame->flags2 |= MF2_BOSSNOTRAP; - } - break; case MT_SMASHINGSPIKEBALL: if (mthing->angle > 0) mobj->tics += mthing->angle; From a601cacfffcc0ce5c7dad98921c4697d90f0f1a0 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Wed, 20 Jun 2018 14:04:49 +0200 Subject: [PATCH 182/212] Added sprite2 to precipmobj_t --- src/p_mobj.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.h b/src/p_mobj.h index f6ebd3cad..2ca8ebd70 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -388,6 +388,7 @@ typedef struct precipmobj_s angle_t angle; // orientation spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h + UINT8 sprite2; // player sprites UINT16 anim_duration; // for FF_ANIMATE states struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears From aed30519d4413e14c26f114e67f29e73d4c35ec5 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 23 Jun 2018 18:47:32 +0100 Subject: [PATCH 183/212] Fix HWR_ProjectSprite to check properly whether the displayed player's mobj or its subsector exists, to avoid a crash when checking for fake planes. (also use viewplayer since its available to use, silly hardware code) Also tweaked a weird splitscreen check in HWR_DrawSpriteShadow; still investigating whether stplyr is ever not player 2 when it's player 2's view, but this looks better for now --- src/hardware/hw_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a5fe6b673..5d9c2993b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3941,7 +3941,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t angle_t shadowdir; // Set direction - if (splitscreen && stplyr != &players[displayplayer]) + if (splitscreen && stplyr == &players[secondarydisplayplayer]) shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value); else shadowdir = localangle + FixedAngle(cv_cam_rotate.value); @@ -5302,7 +5302,10 @@ static void HWR_ProjectSprite(mobj_t *thing) } heightsec = thing->subsector->sector->heightsec; - phs = players[displayplayer].mo->subsector->sector->heightsec; + if (viewplayer->mo && viewplayer->mo->subsector) + phs = viewplayer->mo->subsector->sector->heightsec; + else + phs = -1; if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { From 415c0952740f8dd0587f07e0688286ebf60a6e27 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Tue, 26 Jun 2018 17:46:04 +0100 Subject: [PATCH 184/212] fix the multiplayer menu not allowing the full max length for player names unlike the "name" console command --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 0ab771579..79ac6800b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6543,7 +6543,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice) if (choice < 32 || choice > 127 || itemOn != 0) break; l = strlen(setupm_name); - if (l < MAXPLAYERNAME-1) + if (l < MAXPLAYERNAME) { S_StartSound(NULL,sfx_menu1); // Tails setupm_name[l] =(char)choice; From d8a86a8d744f13f6206b1aefa25ce1bb2047323a Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Tue, 26 Jun 2018 21:41:05 +0100 Subject: [PATCH 185/212] Fix OpenGL completely missing the ability to alter FOF wall pegging by lower unpegged flag. Stupid OpenGL. Sorry in advance Lat'! --- src/hardware/hw_main.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a5fe6b673..1caf84fe9 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2182,27 +2182,34 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) } else if (drawtextured) { -#ifdef ESLOPE // P.S. this is better-organized than the old version - fixed_t offs = sides[(newline ? newline : rover->master)->sidenum[0]].rowoffset; - grTex = HWR_GetTexture(texnum); - - wallVerts[3].t = (*rover->topheight - h + offs) * grTex->scaleY; - wallVerts[2].t = (*rover->topheight - hS + offs) * grTex->scaleY; - wallVerts[0].t = (*rover->topheight - l + offs) * grTex->scaleY; - wallVerts[1].t = (*rover->topheight - lS + offs) * grTex->scaleY; -#else - grTex = HWR_GetTexture(texnum); + fixed_t texturevpeg; + // Wow, how was this missing from OpenGL for so long? + // ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software + // -- Monster Iestyn 26/06/18 if (newline) { - wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY; + texturevpeg = sides[newline->sidenum[0]].rowoffset; + if (newline->flags & ML_DONTPEGBOTTOM) + texturevpeg -= *rover->topheight - *rover->bottomheight; } else { - wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY; + texturevpeg = sides[rover->master->sidenum[0]].rowoffset; + if (gr_linedef->flags & ML_DONTPEGBOTTOM) + texturevpeg -= *rover->topheight - *rover->bottomheight; } + + grTex = HWR_GetTexture(texnum); + +#ifdef ESLOPE + wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; + wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY; + wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; + wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY; +#else + wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; + wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; #endif wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; From 80d6253eec9d82c65cae1b40a6bca6fdf4fcd3a2 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 30 Jun 2018 18:09:39 +0100 Subject: [PATCH 186/212] Don't re-enable MD5 checks yet, we're not even near RC phase yet --- src/d_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index b43efa109..c24e84b02 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1120,11 +1120,11 @@ void D_SRB2Main(void) #ifndef DEVELOP // md5s last updated 12/14/14 // Check MD5s of autoloaded files - W_VerifyFileMD5(0, ASSET_HASH_SRB2_PK3); // srb2.pk3 - W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta - W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta + //W_VerifyFileMD5(0, ASSET_HASH_SRB2_PK3); // srb2.pk3 + //W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta + //W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta #ifdef USE_PATCH_DTA - W_VerifyFileMD5(3, ASSET_HASH_PATCH_PK3); // patch.pk3 + //W_VerifyFileMD5(3, ASSET_HASH_PATCH_PK3); // patch.pk3 #endif // don't check music.dta because people like to modify it, and it doesn't matter if they do From 76c8d30ed2c927d68511d928d6d1b6c89e3d06b7 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 30 Jun 2018 18:14:04 +0100 Subject: [PATCH 187/212] Fix special stage map end var defaults to use the correct map numbers --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 5b62875cb..7ea211141 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3204,7 +3204,7 @@ void G_LoadGameSettings(void) // defaults spstage_start = 1; sstage_start = smpstage_start = 50; - sstage_end = smpstage_end = 57; // 7 special stages in vanilla SRB2 + sstage_end = smpstage_end = 56; // 7 special stages in vanilla SRB2 sstage_end++; // plus one weirdo // initialize free sfx slots for skin sounds From daa87947a4a8fdbad8d57d45e344f9a453c61ce2 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 1 Jul 2018 19:47:26 +0100 Subject: [PATCH 188/212] huh, no wonder the two FHZ ice types looked the same in objectplace; they were using the same spawnstate it seems --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 225e47d80..59e59ace0 100644 --- a/src/info.c +++ b/src/info.c @@ -11686,7 +11686,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FHZICE2 4029, // doomednum - S_FHZICE1, // spawnstate + S_FHZICE2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound From c045e8cf8dc42a9963360ae709a19518922a965d Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 1 Jul 2018 22:01:00 +0100 Subject: [PATCH 189/212] Since there is only one type of the old spikeball that doesn't rotate, there is no point using A_RotateSpikeBall in its states anymore. Likewise, A_RotateSpikeBall no longer has to care about the object type of the actor, for the same reason. --- src/info.c | 16 ++++++++-------- src/p_enemy.c | 3 --- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/info.c b/src/info.c index 59e59ace0..d263b4876 100644 --- a/src/info.c +++ b/src/info.c @@ -1736,14 +1736,14 @@ state_t states[NUMSTATES] = {SPR_SIGN, 7, -1, {A_SignPlayer}, 0, 0, S_NULL}, // S_SIGN53 Blank // Spike Ball - {SPR_SPIK, 0, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL2}, // S_SPIKEBALL1 - {SPR_SPIK, 1, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL3}, // S_SPIKEBALL2 - {SPR_SPIK, 2, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL4}, // S_SPIKEBALL3 - {SPR_SPIK, 3, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL5}, // S_SPIKEBALL4 - {SPR_SPIK, 4, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL6}, // S_SPIKEBALL5 - {SPR_SPIK, 5, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL7}, // S_SPIKEBALL6 - {SPR_SPIK, 6, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL8}, // S_SPIKEBALL7 - {SPR_SPIK, 7, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL1}, // S_SPIKEBALL8 + {SPR_SPIK, 0, 1, {NULL}, 0, 0, S_SPIKEBALL2}, // S_SPIKEBALL1 + {SPR_SPIK, 1, 1, {NULL}, 0, 0, S_SPIKEBALL3}, // S_SPIKEBALL2 + {SPR_SPIK, 2, 1, {NULL}, 0, 0, S_SPIKEBALL4}, // S_SPIKEBALL3 + {SPR_SPIK, 3, 1, {NULL}, 0, 0, S_SPIKEBALL5}, // S_SPIKEBALL4 + {SPR_SPIK, 4, 1, {NULL}, 0, 0, S_SPIKEBALL6}, // S_SPIKEBALL5 + {SPR_SPIK, 5, 1, {NULL}, 0, 0, S_SPIKEBALL7}, // S_SPIKEBALL6 + {SPR_SPIK, 6, 1, {NULL}, 0, 0, S_SPIKEBALL8}, // S_SPIKEBALL7 + {SPR_SPIK, 7, 1, {NULL}, 0, 0, S_SPIKEBALL1}, // S_SPIKEBALL8 // Elemental Shield's Spawn {SPR_SFLM, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINFIRE2}, // S_SPINFIRE1 diff --git a/src/p_enemy.c b/src/p_enemy.c index a03cec9c2..16d022c22 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5298,9 +5298,6 @@ void A_RotateSpikeBall(mobj_t *actor) return; #endif - if (actor->type == MT_SPIKEBALL) // don't remove this, these spikeballs share the same states as the rotating spikeballs - return; - if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen. { CONS_Debug(DBG_GAMELOGIC, "A_RotateSpikeBall: Spikeball has no target\n"); From bcffe612775a247b667dc8138bda1c3f60ca8b2e Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 2 Jul 2018 20:35:39 +0100 Subject: [PATCH 190/212] remove MF_RUNSPAWNFUNC from MT_CACOLANTERN --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index d263b4876..c9313624f 100644 --- a/src/info.c +++ b/src/info.c @@ -16823,7 +16823,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_lntsit, // activesound - MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_RUNSPAWNFUNC|MF_NOGRAVITY, // flags + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY, // flags S_NULL // raisestate }, From dfb5f06d7ed6675df360de8ea9b962768c4e943b Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 2 Jul 2018 21:03:04 +0100 Subject: [PATCH 191/212] fix compiler errors (shadowed vars, comparisons between unsigned + signed, an unused function arg, and a non-static function with no prototype) --- src/g_game.c | 1 - src/p_enemy.c | 2 +- src/p_inter.c | 2 ++ src/p_user.c | 1 - src/st_stuff.c | 2 +- src/y_inter.c | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 7ea211141..52358a8b9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3021,7 +3021,6 @@ static void G_DoCompleted(void) if ((gottoken = (gametype == GT_COOP && token))) { - INT16 i; token--; for (i = 0; i < 7; i++) diff --git a/src/p_enemy.c b/src/p_enemy.c index 16d022c22..9235a1d0f 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1594,7 +1594,7 @@ void A_CheckBuddy(mobj_t *actor) // Helper function for the Robo Hood. // Don't ask me how it works. Nev3r made it with dark majyks. -void P_ParabolicMove(mobj_t *actor, fixed_t x, fixed_t y, fixed_t z, fixed_t speed) +static void P_ParabolicMove(mobj_t *actor, fixed_t x, fixed_t y, fixed_t z, fixed_t speed) { fixed_t dh; diff --git a/src/p_inter.c b/src/p_inter.c index 033d148a8..5737e2c2a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2663,6 +2663,8 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source) player_t *player = target->player; tic_t oldnightstime = player->nightstime; + (void)source; // unused + if (!player->powers[pw_flashing]) { angle_t fa; diff --git a/src/p_user.c b/src/p_user.c index 8ba1dae54..357933f14 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -306,7 +306,6 @@ void P_GiveEmerald(boolean spawnObj) if (spawnObj && playeringame[consoleplayer]) { // The Chaos Emerald begins to orbit us! - UINT8 em = P_GetNextEmerald(); // Only give it to ONE person! mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD); P_SetTarget(&emmo->target, players[consoleplayer].mo); diff --git a/src/st_stuff.c b/src/st_stuff.c index 88f2c6259..3ecd0acdf 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1667,7 +1667,7 @@ static void ST_drawNiGHTSHUD(void) else ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)&7]); } - else if (oldspecialstage && total_spherecount < ssspheres) + else if (oldspecialstage && total_spherecount < (INT32)ssspheres) { INT32 cfill, amount; const INT32 length = 88; diff --git a/src/y_inter.c b/src/y_inter.c index a26f59ce8..68dda198c 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -329,7 +329,7 @@ void Y_IntermissionDrawer(void) else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0') animatetic = intertic + TICRATE; - if (animatetic && intertic >= animatetic) + if (animatetic && (tic_t)intertic >= animatetic) { const INT32 scradjust = (vid.width/vid.dupx)>>3; // 40 for BASEVIDWIDTH INT32 animatetimer = (intertic - animatetic); From 82d953bbc219d02edd0cba6bde6ac44a591c96bf Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Wed, 4 Jul 2018 20:15:36 +0100 Subject: [PATCH 192/212] Fixed the Lua crash exploit. --- src/lua_consolelib.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 566e73748..3239b7c5e 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -77,7 +77,9 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) deny: //must be hacked/buggy client - lua_settop(gL, 0); // clear stack + if (gL) // check if Lua is actually turned on first, you dummmy -- Monster Iestyn 04/07/18 + lua_settop(gL, 0); // clear stack + CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]); if (server) { From 7da6aca4505e0f5227cb3e802b11d200bef4aec0 Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Sat, 7 Jul 2018 20:33:19 +0000 Subject: [PATCH 193/212] Update m_misc.c --- src/m_misc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/m_misc.c b/src/m_misc.c index 041899a3b..69542dc9a 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -56,7 +56,9 @@ typedef off_t off64_t; #endif #endif -#if defined (_WIN32) +#if defined(__MINGW32__) &&(__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3) +#define PRIdS "u" +#elif defined (_WIN32) #define PRIdS "Iu" #elif defined (_PSP) || defined (_arch_dreamcast) || defined (DJGPP) || defined (_WII) || defined (_NDS) || defined (_PS3) #define PRIdS "u" From a79b9a912709c0bf23e9ae99302cc6cbc23c7ce5 Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Sat, 7 Jul 2018 20:41:11 +0000 Subject: [PATCH 194/212] Update m_misc.c --- src/m_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_misc.c b/src/m_misc.c index 69542dc9a..5c4e7f2f9 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -56,7 +56,7 @@ typedef off_t off64_t; #endif #endif -#if defined(__MINGW32__) &&(__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3) +#if defined(__MINGW32__) && ((__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3)) #define PRIdS "u" #elif defined (_WIN32) #define PRIdS "Iu" From 0a931a1364a0f151eba1ff8f644dfda4558ae700 Mon Sep 17 00:00:00 2001 From: colette Date: Sat, 7 Jul 2018 20:20:46 -0400 Subject: [PATCH 195/212] Update f_finale.c --- src/f_finale.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index 958bef0f6..a8b27bb80 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -977,7 +977,6 @@ static const char *credits[] = { "\1Programming", "Alam \"GBC\" Arias", "Logan \"GBA\" Arias", - "Colette \"fickle\" Bordelon", "Callum Dickinson", "Scott \"Graue\" Feeney", "Nathan \"Jazz\" Giroux", From 1ee7eda0ad1971b5a826138368356d25468574f8 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 20 Jul 2018 17:35:18 -0400 Subject: [PATCH 196/212] Fixup PROFILEMODE --- src/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 57bd0644e..dd250b0bc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,3 +1,4 @@ + # GNU Make makefile for SRB2 ############################################################################# # Copyright (C) 1998-2000 by DooM Legacy Team. @@ -421,7 +422,8 @@ endif ifdef PROFILEMODE # build with profiling information - CFLAGS:=-pg $(CFLAGS) + CFLAGS+=-pg + LDFLAGS+=-pg endif ifdef ZDEBUG From c02ee9a50283088eb490b401999937ad99ff84be Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 28 Jul 2018 01:58:25 -0400 Subject: [PATCH 197/212] Re-did this fix. --- src/sdl/mixer_sound.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 18670649e..7ab1523c6 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -66,6 +66,7 @@ static boolean midimode; static Mix_Music *music; static UINT8 music_volume, midi_volume, sfx_volume; static float loop_point; +static boolean songpaused; #ifdef HAVE_LIBGME static Music_Emu *gme; @@ -102,6 +103,7 @@ void I_StartupSound(void) } sound_started = true; + songpaused = false; Mix_AllocateChannels(256); } @@ -450,7 +452,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len) (void)udata; // no gme? no music. - if (!gme || gme_track_ended(gme)) + if (!gme || gme_track_ended(gme) || songpaused) return; // play gme into stream @@ -475,25 +477,15 @@ void I_ShutdownMusic(void) void I_PauseSong(INT32 handle) { (void)handle; -#ifdef HAVE_LIBGME - if (gme) - { - Mix_HookMusic(NULL, NULL); - } -#endif Mix_PauseMusic(); + songpaused = true; } void I_ResumeSong(INT32 handle) { (void)handle; -#ifdef HAVE_LIBGME - if (gme) - { - Mix_HookMusic(mix_gme, gme); - } -#endif Mix_ResumeMusic(); + songpaused = false; } // From 83d87c343b194ea365b10d5f87c6f1ed8e1189cd Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Thu, 2 Aug 2018 16:15:30 +0100 Subject: [PATCH 198/212] Fix Cacolantern's preparing sound being played everywhere across the map (or, in other words, fixing this to be the same as the equivalent state in the original SOC) --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index c9313624f..f23b06971 100644 --- a/src/info.c +++ b/src/info.c @@ -3435,7 +3435,7 @@ state_t states[NUMSTATES] = {SPR_CACO, 2, 5, {A_JetChase}, 0, 0, S_CACO_CHASE_REPEAT}, // S_CACO_CHASE {SPR_CACO, 2, 0, {A_Repeat}, 5, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_CHASE_REPEAT {SPR_CACO, 2, 0, {A_RandomState}, S_CACO_PREPARE_SOUND, S_CACO_CHASE, S_CACO_RANDOM}, // S_CACO_RANDOM - {SPR_CACO, 2, 8, {A_PlaySound}, sfx_s3k95, 0, S_CACO_PREPARE1}, // S_CACO_PREPARE_SOUND + {SPR_CACO, 2, 8, {A_PlaySound}, sfx_s3k95, 1, S_CACO_PREPARE1}, // S_CACO_PREPARE_SOUND {SPR_CACO, 3, 8, {NULL}, 0, 0, S_CACO_PREPARE2}, // S_CACO_PREPARE1 {SPR_CACO, 4|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_PREPARE3}, // S_CACO_PREPARE2 {SPR_CACO, 5|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_CACO_SHOOT_SOUND}, // S_CACO_PREPARE3 From 21cb0cab3c313c788c6564360d68804324801c68 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Fri, 3 Aug 2018 23:58:11 +0200 Subject: [PATCH 199/212] Reorganized the thing type numbers --- src/info.c | 98 +++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/info.c b/src/info.c index f23b06971..1489917b7 100644 --- a/src/info.c +++ b/src/info.c @@ -4049,7 +4049,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CRUSHSTACEAN - 610, //126, // doomednum + 126, // doomednum S_CRUSHSTACEAN_ROAM1, // spawnstate 1, // spawnhealth S_NULL, // seestate @@ -6825,7 +6825,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BIGMINE - 524, // doomednum + 1012, // doomednum S_BIGMINE_IDLE, // spawnstate 1, // spawnhealth S_BIGMINE_ALERT1, // seestate @@ -6852,7 +6852,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BLASTEXECUTOR - 1505, // doomednum + 756, // doomednum S_INVISIBLE, // spawnstate 1, // spawnhealth S_NULL, // seestate @@ -6879,7 +6879,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CANNONLAUNCHER - 525, // doomednum + 1123, // doomednum S_CANNONLAUNCHER1, // spawnstate 1, // spawnhealth S_NULL, // seestate @@ -8634,7 +8634,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CANNONBALLDECOR - 526, // doomednum + 1124, // doomednum S_CANNONBALL1, // spawnstate 1, // spawnhealth S_NULL, // seestate @@ -8958,7 +8958,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CHECKERTREE - 810, // doomednum + 809, // doomednum S_CHECKERTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -8985,7 +8985,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CHECKERSUNSETTREE - 811, // doomednum + 810, // doomednum S_CHECKERSUNSETTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9012,7 +9012,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FHZTREE - 812, // doomednum + 2102, // doomednum S_FHZTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9039,7 +9039,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FHZPINKTREE - 813, // doomednum + 2103, // doomednum S_FHZPINKTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9066,7 +9066,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_POLYGONTREE - 814, // doomednum + 811, // doomednum S_POLYGONTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9093,7 +9093,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BUSHTREE - 815, // doomednum + 812, // doomednum S_BUSHTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9120,7 +9120,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BUSHREDTREE - 816, // doomednum + 813, // doomednum S_BUSHREDTREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9633,7 +9633,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_DSZ2STALAGMITE - 999, // doomednum + 1011, // doomednum S_DSZ2STALAGMITE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -9957,7 +9957,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CUSTOMMACEPOINT - 1111, // doomednum + 1110, // doomednum S_INVISIBLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10281,7 +10281,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CEZPOLE - 1113, // doomednum + 1117, // doomednum S_CEZPOLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10335,7 +10335,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_PINETREE - 1041, // doomednum + 1114, // doomednum S_PINETREE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10362,7 +10362,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CEZBUSH1 - 1042, // doomednum + 1115, // doomednum S_CEZBUSH1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10389,7 +10389,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CEZBUSH2 - 1043, // doomednum + 1116, // doomednum S_CEZBUSH2, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10416,7 +10416,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CANDLE - 3330, // doomednum + 1119, // doomednum S_CANDLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10443,7 +10443,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CANDLEPRICKET - 3332, // doomednum + 1120, // doomednum S_CANDLEPRICKET, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10470,7 +10470,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FLAMEHOLDER - 3335, // doomednum + 1121, // doomednum S_FLAMEHOLDER, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10497,7 +10497,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FIRETORCH - 3336, // doomednum + 1122, // doomednum S_FIRETORCH, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10524,7 +10524,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_WAVINGFLAG - 1329, // doomednum + 1118, // doomednum S_WAVINGFLAG, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10578,7 +10578,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CRAWLASTATUE - 1120, // doomednum + 1111, // doomednum S_CRAWLASTATUE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10605,7 +10605,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FACESTABBERSTATUE - 1331, // doomednum + 1112, // doomednum S_FACESTABBERSTATUE, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10632,7 +10632,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SUSPICIOUSFACESTABBERSTATUE - 1332, // doomednum + 1113, // doomednum S_SUSPICIOUSFACESTABBERSTATUE_WAIT, // spawnstate 1000, // spawnhealth S_SUSPICIOUSFACESTABBERSTATUE_BURST1, // seestate @@ -10902,7 +10902,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FJSPINAXISA - 3575, // doomednum + 1302, // doomednum S_FJSPINAXISA1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -10929,7 +10929,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FJSPINAXISB - 3576, // doomednum + 1303, // doomednum S_FJSPINAXISB1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11658,7 +11658,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FHZICE1 - 4028, // doomednum + 2100, // doomednum S_FHZICE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11685,7 +11685,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_FHZICE2 - 4029, // doomednum + 2101, // doomednum S_FHZICE2, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11712,7 +11712,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_JACKO1 - 3520, // doomednum + 2006, // doomednum S_JACKO1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11739,7 +11739,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_JACKO2 - 3521, // doomednum + 2007, // doomednum S_JACKO2, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11766,7 +11766,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_JACKO3 - 3522, // doomednum + 2008, // doomednum S_JACKO3, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11793,7 +11793,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HHZTREE_TOP - 3540, // doomednum + 2010, // doomednum S_HHZTREE_TOP, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11847,7 +11847,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HHZSHROOM - 3530, // doomednum + 2009, // doomednum S_HHZSHROOM_1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11874,7 +11874,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HHZGRASS - 3513, // doomednum + 2001, // doomednum S_HHZGRASS, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11901,7 +11901,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HHZTENTACLE1 - 3515, // doomednum + 2002, // doomednum S_HHZTENT1, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11928,7 +11928,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HHZTENTACLE2 - 3516, // doomednum + 2003, // doomednum S_HHZTENT2, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11955,7 +11955,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HHZSTALAGMITE_TALL - 3517, // doomednum + 2004, // doomednum S_HHZSTALAGMITE_TALL, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11982,7 +11982,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HHZSTALAGMITE_SHORT - 3518, // doomednum + 2005, // doomednum S_HHZSTALAGMITE_SHORT, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -14964,7 +14964,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_MACHINEAMBIENCE - 3405, // doomednum + 710, // doomednum S_INVISIBLE, // spawnstate 24, // spawnhealth: repeat speed S_NULL, // seestate @@ -16612,7 +16612,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_PENGUINATOR - 2017, // doomednum + 129, // doomednum S_PENGUINATOR_LOOK, // spawnstate 1, // spawnhealth S_PENGUINATOR_WADDLE1, // seestate @@ -16639,7 +16639,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_POPHAT - 2018, // doomednum -- happy anniversary! + 130, // doomednum -- happy anniversary! S_POPHAT_LOOK, // spawnstate 1, // spawnhealth S_POPHAT_SHOOT1, // seestate @@ -16693,7 +16693,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HIVEELEMENTAL - 3190, // doomednum + 127, // doomednum S_HIVEELEMENTAL_LOOK, // spawnstate 2, // spawnhealth S_HIVEELEMENTAL_PREPARE1, // seestate @@ -16720,7 +16720,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BUMBLEBORE - 3191, // doomednum + 128, // doomednum S_BUMBLEBORE_SPAWN, // spawnstate 0, // spawnhealth -- this is how you do drones... S_BUMBLEBORE_FLY1, // seestate @@ -16774,7 +16774,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SMASHINGSPIKEBALL - 3001, // doomednum + 2000, // doomednum S_SMASHSPIKE_FLOAT, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -16801,7 +16801,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_CACOLANTERN - 3102, // doomednum + 132, // doomednum S_CACO_LOOK, // spawnstate 1, // spawnhealth S_CACO_WAKE1, // seestate @@ -16882,7 +16882,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SPINBOBERT - 3100, // doomednum + 131, // doomednum S_SPINBOBERT_MOVE_FLIPUP, // spawnstate 1, // spawnhealth S_NULL, // seestate @@ -16963,7 +16963,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HANGSTER - 3195, // doomednum + 133, // doomednum S_HANGSTER_LOOK, // spawnstate 1, // spawnhealth S_HANGSTER_SWOOP1, // seestate From 8d622ff6f8d428fd848c473566240402b748a487 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 5 Aug 2018 20:17:30 +0100 Subject: [PATCH 200/212] Quick fix for LJ's password fix: don't check if password is set until we've confirmed that the receiving player is the server! --- src/d_netcmd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 727d5eff4..bf26ca61a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2730,15 +2730,15 @@ static void Got_Login(UINT8 **cp, INT32 playernum) READMEM(*cp, sentmd5, 16); + if (client) + return; + if (!adminpasswordset) { CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[playernum]); return; } - if (client) - return; - // Do the final pass to compare with the sent md5 D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", playernum), &finalmd5); From 2738f3a537fc57aba5e40d529bc11222b0cf9e72 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 5 Aug 2018 22:02:20 +0100 Subject: [PATCH 201/212] Rewrite archiving/unarchiving of Lua strings for netgames. This now means: * Lua strings longer than 1024 chars can now be read properly without awful crashes * Lua strings with embedded zeros can be written/read without truncating anything (hopefully) --- src/lua_script.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/lua_script.c b/src/lua_script.c index 67ce77c53..5561094ad 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -526,9 +526,23 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) break; } case LUA_TSTRING: + { + UINT16 len = (UINT16)lua_objlen(gL, myindex); // get length of string, including embedded zeros + const char *s = lua_tostring(gL, myindex); + UINT16 i = 0; WRITEUINT8(save_p, ARCH_STRING); - WRITESTRING(save_p, lua_tostring(gL, myindex)); + // if you're wondering why we're writing a string to save_p this way, + // it turns out that Lua can have embedded zeros ('\0') in the strings, + // so we can't use WRITESTRING as that cuts off when it finds a '\0'. + // Saving the size of the string also allows us to get the size of the string on the other end, + // fixing the awful crashes previously encountered for reading strings longer than 1024 + // (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?) + // -- Monster Iestyn 05/08/18 + WRITEUINT16(save_p, len); // save size of string + while (i < len) + WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros break; + } case LUA_TTABLE: { boolean found = false; @@ -809,9 +823,19 @@ static UINT8 UnArchiveValue(int TABLESINDEX) break; case ARCH_STRING: { - char value[1024]; - READSTRING(save_p, value); - lua_pushstring(gL, value); + UINT16 len = READUINT16(save_p); // length of string, including embedded zeros + char *value; + UINT16 i = 0; + // See my comments in the ArchiveValue function; + // it's much the same for reading strings as writing them! + // (i.e. we can't use READSTRING either) + // -- Monster Iestyn 05/08/18 + value = malloc(len); // make temp buffer of size len + // now read the actual string + while (i < len) + value[i++] = READCHAR(save_p); // read chars individually, including the embedded zeros + lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros) + free(value); // free the buffer break; } case ARCH_TABLE: From ecc9ebe8c1f88da4b67a546fc2f4eab8089d6573 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 7 Aug 2018 19:12:10 +0100 Subject: [PATCH 202/212] Change the order of operations when applying transparency and colormap such that colormap isn't applied to the screen pixel twice (or, in the case of R_DrawTranslatedTranslucentColumn_8, thrice). Please note I haven't touched the ASM equivalent, given as it's not actually used. --- src/r_draw8.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/r_draw8.c b/src/r_draw8.c index 39585f587..9240cc3f1 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -297,7 +297,7 @@ void R_DrawTranslucentColumn_8(void) // Re-map color indices from wall texture column // using a lighting/special effects LUT. // heightmask is the Tutti-Frutti fix - *dest = colormap[*(transmap + (source[frac>>FRACBITS]<<8) + (*dest))]; + *dest = *(transmap + (colormap[source[frac>>FRACBITS]]<<8) + (*dest)); dest += vid.width; if ((frac += fracstep) >= heightmask) frac -= heightmask; @@ -308,15 +308,15 @@ void R_DrawTranslucentColumn_8(void) { while ((count -= 2) >= 0) // texture height is a power of 2 { - *dest = colormap[*(transmap + ((source[(frac>>FRACBITS)&heightmask]<<8)) + (*dest))]; + *dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest)); dest += vid.width; frac += fracstep; - *dest = colormap[*(transmap + ((source[(frac>>FRACBITS)&heightmask]<<8)) + (*dest))]; + *dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest)); dest += vid.width; frac += fracstep; } if (count & 1) - *dest = colormap[*(transmap + ((source[(frac>>FRACBITS)&heightmask]<<8)) + (*dest))]; + *dest = *(transmap + (colormap[source[(frac>>FRACBITS)&heightmask]]<<8) + (*dest)); } } } @@ -367,8 +367,7 @@ void R_DrawTranslatedTranslucentColumn_8(void) // using a lighting/special effects LUT. // heightmask is the Tutti-Frutti fix - *dest = dc_colormap[*(dc_transmap - + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest))]; + *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest)); dest += vid.width; if ((frac += fracstep) >= heightmask) @@ -380,17 +379,15 @@ void R_DrawTranslatedTranslucentColumn_8(void) { while ((count -= 2) >= 0) // texture height is a power of 2 { - *dest = dc_colormap[*(dc_transmap - + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest))]; + *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest)); dest += vid.width; frac += fracstep; - *dest = dc_colormap[*(dc_transmap - + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8) + (*dest))]; + *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest)); dest += vid.width; frac += fracstep; } if (count & 1) - *dest = dc_colormap[*(dc_transmap + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]] <<8) + (*dest))]; + *dest = *(dc_transmap + (dc_colormap[dc_translation[dc_source[(frac>>FRACBITS)&heightmask]]]<<8) + (*dest)); } } } @@ -1220,35 +1217,35 @@ void R_DrawTranslucentSpan_8 (void) // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't // have the uber complicated math to calculate it now, so that was a memory write we didn't // need! - dest[0] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[0])]; + dest[0] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[0]); xposition += xstep; yposition += ystep; - dest[1] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[1])]; + dest[1] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[1]); xposition += xstep; yposition += ystep; - dest[2] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[2])]; + dest[2] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[2]); xposition += xstep; yposition += ystep; - dest[3] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[3])]; + dest[3] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[3]); xposition += xstep; yposition += ystep; - dest[4] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[4])]; + dest[4] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[4]); xposition += xstep; yposition += ystep; - dest[5] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[5])]; + dest[5] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[5]); xposition += xstep; yposition += ystep; - dest[6] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[6])]; + dest[6] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[6]); xposition += xstep; yposition += ystep; - dest[7] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[7])]; + dest[7] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[7]); xposition += xstep; yposition += ystep; @@ -1257,7 +1254,7 @@ void R_DrawTranslucentSpan_8 (void) } while (count--) { - *dest = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dest)]; + *dest = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + *dest); dest++; xposition += xstep; yposition += ystep; From 5daeaf529fc26fac71e36fb821bbd9eea3c99bd7 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 9 Aug 2018 16:56:43 +0100 Subject: [PATCH 203/212] Apply the double-colormap ordering fix to R_DrawTiltedTranslucentSpan_8 as well. --- src/r_draw8.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/r_draw8.c b/src/r_draw8.c index 9240cc3f1..d4aaf5cf9 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -735,8 +735,7 @@ void R_DrawTiltedTranslucentSpan_8(void) v = (INT64)(vz*z) + viewy; colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - - *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); dest++; iz += ds_sz.x; uz += ds_su.x; @@ -773,7 +772,7 @@ void R_DrawTiltedTranslucentSpan_8(void) for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); dest++; u += stepu; v += stepv; @@ -789,7 +788,7 @@ void R_DrawTiltedTranslucentSpan_8(void) u = (INT64)(startu); v = (INT64)(startv); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); } else { @@ -810,7 +809,7 @@ void R_DrawTiltedTranslucentSpan_8(void) for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])]; + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); dest++; u += stepu; v += stepv; From 145c050e14e55f1053d8a33b92e1b7792398944d Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 9 Aug 2018 17:08:20 +0100 Subject: [PATCH 204/212] ...and R_DrawTranslucentSplat_8, even though it isn't used! --- src/r_draw8.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/r_draw8.c b/src/r_draw8.c index d4aaf5cf9..800f28b6b 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -1120,49 +1120,49 @@ void R_DrawTranslucentSplat_8 (void) // need! val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[0] = colormap[*(ds_transmap + (val << 8) + dest[0])]; + dest[0] = *(ds_transmap + (colormap[val] << 8) + dest[0]); xposition += xstep; yposition += ystep; val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[1] = colormap[*(ds_transmap + (val << 8) + dest[1])]; + dest[1] = *(ds_transmap + (colormap[val] << 8) + dest[1]); xposition += xstep; yposition += ystep; val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[2] = colormap[*(ds_transmap + (val << 8) + dest[2])]; + dest[2] = *(ds_transmap + (colormap[val] << 8) + dest[2]); xposition += xstep; yposition += ystep; val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[3] = colormap[*(ds_transmap + (val << 8) + dest[3])]; + dest[3] = *(ds_transmap + (colormap[val] << 8) + dest[3]); xposition += xstep; yposition += ystep; val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[4] = colormap[*(ds_transmap + (val << 8) + dest[4])]; + dest[4] = *(ds_transmap + (colormap[val] << 8) + dest[4]); xposition += xstep; yposition += ystep; val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[5] = colormap[*(ds_transmap + (val << 8) + dest[5])]; + dest[5] = *(ds_transmap + (colormap[val] << 8) + dest[5]); xposition += xstep; yposition += ystep; val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[6] = colormap[*(ds_transmap + (val << 8) + dest[6])]; + dest[6] = *(ds_transmap + (colormap[val] << 8) + dest[6]); xposition += xstep; yposition += ystep; val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - dest[7] = colormap[*(ds_transmap + (val << 8) + dest[7])]; + dest[7] = *(ds_transmap + (colormap[val] << 8) + dest[7]); xposition += xstep; yposition += ystep; @@ -1173,7 +1173,7 @@ void R_DrawTranslucentSplat_8 (void) { val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; if (val != TRANSPARENTPIXEL) - *dest = colormap[*(ds_transmap + (val << 8) + *dest)]; + *dest = *(ds_transmap + (colormap[val] << 8) + *dest); dest++; xposition += xstep; From fe616784375f41dea4b420f95cd788c293f5b2d3 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 00:19:56 -0400 Subject: [PATCH 205/212] MT_FLINGBLUESPHERE and MT_FLINGNIGHTSCHIP entries --- src/dehacked.c | 2 ++ src/info.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/info.h | 2 ++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index c4d0bc104..fb0f958c3 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6369,6 +6369,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_RING", "MT_FLINGRING", // Lost ring "MT_BLUESPHERE", // Blue sphere for special stages + "MT_FLINGBLUESPHERE", // Lost blue sphere "MT_BOMBSPHERE", "MT_REDTEAMRING", //Rings collectable by red team. "MT_BLUETEAMRING", //Rings collectable by blue team. @@ -6833,6 +6834,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_HOOPCENTER", // Center of a hoop "MT_NIGHTSCORE", "MT_NIGHTSCHIP", // NiGHTS Chip + "MT_FLINGNIGHTSCHIP", // Lost NiGHTS Chip "MT_NIGHTSSTAR", // NiGHTS Star "MT_NIGHTSSUPERLOOP", "MT_NIGHTSDRILLREFILL", diff --git a/src/info.c b/src/info.c index 1489917b7..782ab6381 100644 --- a/src/info.c +++ b/src/info.c @@ -5783,7 +5783,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound - MT_NULL, // reactiontime + MT_FLINGBLUESPHERE, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -5804,6 +5804,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_BLUESPHEREBONUS // raisestate }, + { // MT_FLINGBLUESPHERE + -1, // doomednum + S_BLUESPHERE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + MT_FLINGBLUESPHERE, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + MT_BLUESPHERE, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BLUESPHERESPARK, // deathstate + S_NULL, // xdeathstate + sfx_s3k65, // deathsound + 38*FRACUNIT, // speed + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SPECIAL, // flags + S_BLUESPHEREBONUS // raisestate + }, + { // MT_BOMBSPHERE 520, // doomednum S_BOMBSPHERE1, // spawnstate @@ -16320,7 +16347,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + MT_FLINGNIGHTSCHIP, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -16341,6 +16368,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NIGHTSCHIPBONUS // raisestate }, + { // MT_FLINGNIGHTSCHIP + -1, // doomednum + S_NIGHTSCHIP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + MT_FLINGNIGHTSCHIP, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + MT_NIGHTSCHIP, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_SPRK1, // deathstate + S_NULL, // xdeathstate + sfx_ncchip, // deathsound + 38*FRACUNIT, // speed + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SPECIAL, // flags + S_NIGHTSCHIPBONUS // raisestate + }, + { // MT_NIGHTSSTAR -1, // doomednum S_NIGHTSSTAR, // spawnstate diff --git a/src/info.h b/src/info.h index c9f7299d8..dfd30bc5b 100644 --- a/src/info.h +++ b/src/info.h @@ -3742,6 +3742,7 @@ typedef enum mobj_type MT_RING, MT_FLINGRING, // Lost ring MT_BLUESPHERE, // Blue sphere for special stages + MT_FLINGBLUESPHERE, // Lost blue sphere MT_BOMBSPHERE, MT_REDTEAMRING, //Rings collectable by red team. MT_BLUETEAMRING, //Rings collectable by blue team. @@ -4206,6 +4207,7 @@ typedef enum mobj_type MT_HOOPCENTER, // Center of a hoop MT_NIGHTSCORE, MT_NIGHTSCHIP, // NiGHTS Chip + MT_FLINGNIGHTSCHIP, // Lost NiGHTS Chip MT_NIGHTSSTAR, // NiGHTS Star MT_NIGHTSSUPERLOOP, MT_NIGHTSDRILLREFILL, From e0f6dee8bef1e67f17c315676530ef785c892a22 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 00:20:30 -0400 Subject: [PATCH 206/212] MT_FLINGBLUESPHERE and MT_FLINGNIGHTSCHIP implementation --- src/p_inter.c | 7 +++++++ src/p_mobj.c | 10 ++++++++++ src/p_setup.c | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index 5737e2c2a..f908601bb 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -490,7 +490,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_DoNightsScore(player); break; case MT_BLUESPHERE: + case MT_FLINGBLUESPHERE: case MT_NIGHTSCHIP: + case MT_FLINGNIGHTSCHIP: if (!(P_CanPickupItem(player, false)) && !(special->flags2 & MF2_NIGHTSPULL)) return; @@ -3373,6 +3375,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) angle_t fa; fixed_t ns; fixed_t z; + boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); // Better safe than sorry. if (!player) @@ -3396,6 +3399,8 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) INT32 objType = mobjinfo[MT_RING].reactiontime; if (mariomode) objType = mobjinfo[MT_COIN].reactiontime; + else if (player->powers[pw_carry] == CR_NIGHTSFALL) + objType = mobjinfo[(nightsreplace ? MT_NIGHTSCHIP : MT_BLUESPHERE)].reactiontime; z = player->mo->z; if (player->mo->eflags & MFE_VERTICALFLIP) @@ -3424,6 +3429,8 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) P_SetObjectMomZ(mo, 8*FRACUNIT, false); mo->fuse = 20*TICRATE; // Adjust fuse for NiGHTS + + P_SetMobjState(mo, (player->bonustime ? mo->info->raisestate : mo->info->spawnstate)); } else { diff --git a/src/p_mobj.c b/src/p_mobj.c index be373fbf4..4353e67c3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1539,6 +1539,8 @@ fixed_t P_GetMobjGravity(mobj_t *mo) { case MT_FLINGRING: case MT_FLINGCOIN: + case MT_FLINGBLUESPHERE: + case MT_FLINGNIGHTSCHIP: case MT_FLINGEMERALD: case MT_BOUNCERING: case MT_RAILRING: @@ -2523,6 +2525,8 @@ static boolean P_ZMovement(mobj_t *mo) case MT_BLUETEAMRING: case MT_FLINGRING: case MT_FLINGCOIN: + case MT_FLINGBLUESPHERE: + case MT_FLINGNIGHTSCHIP: case MT_FLINGEMERALD: // Remove flinged stuff from death pits. if (P_CheckDeathPitCollide(mo)) @@ -2709,6 +2713,8 @@ static boolean P_ZMovement(mobj_t *mo) // Flingrings bounce if (mo->type == MT_FLINGRING || mo->type == MT_FLINGCOIN + || mo->type == MT_FLINGBLUESPHERE + || mo->type == MT_FLINGNIGHTSCHIP || P_WeaponOrPanel(mo->type) || mo->type == MT_FLINGEMERALD || mo->type == MT_BIGTUMBLEWEED @@ -7941,6 +7947,8 @@ void P_MobjThinker(mobj_t *mobj) // Flung items case MT_FLINGRING: case MT_FLINGCOIN: + case MT_FLINGBLUESPHERE: + case MT_FLINGNIGHTSCHIP: if (mobj->flags2 & MF2_NIGHTSPULL) P_NightsItemChase(mobj); else @@ -8278,6 +8286,8 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s #ifdef ESLOPE // Sliding physics for slidey mobjs! if (mobj->type == MT_FLINGRING || mobj->type == MT_FLINGCOIN + || mobj->type == MT_FLINGBLUESPHERE + || mobj->type == MT_FLINGNIGHTSCHIP || P_WeaponOrPanel(mobj->type) || mobj->type == MT_FLINGEMERALD || mobj->type == MT_BIGTUMBLEWEED diff --git a/src/p_setup.c b/src/p_setup.c index 1a0736cc2..7597b7d87 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -885,7 +885,8 @@ void P_SwitchSpheresBonusMode(boolean bonustime) mo = (mobj_t *)th; - if (mo->type != MT_BLUESPHERE && mo->type != MT_NIGHTSCHIP) + if (mo->type != MT_BLUESPHERE && mo->type != MT_NIGHTSCHIP + && mo->type != MT_FLINGBLUESPHERE && mo->type != MT_FLINGNIGHTSCHIP) continue; if (!mo->health) From 62e288a664038a36a1a8fdb5b28ad27533584ad7 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 00:51:20 -0400 Subject: [PATCH 207/212] Correct player->spheres deduction upon losing spheres player->rings appears to be used for ring/star pickups. Player never loses stars, so it seems player->rings should not be deducted in-level. Therefore, just deduct player->spheres. --- src/p_inter.c | 48 ++++++++++++++++++++++++++++++++++++++---------- src/p_user.c | 2 +- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index f908601bb..87d780f7a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2772,18 +2772,26 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return true; } - if (player->rings > 0) // Ring loss + if (player->powers[pw_carry] == CR_NIGHTSFALL) + { + if (player->spheres > 0) + { + P_PlayRinglossSound(target); + P_PlayerRingBurst(player, player->spheres); + player->spheres = 0; + } + } + else if (player->rings > 0) // Ring loss { P_PlayRinglossSound(target); - P_PlayerRingBurst(player, player->rings); + P_PlayerRingBurst(player, max(player->spheres, player->rings)); + player->rings = 0; } else // Death { P_PlayDeathSound(target); P_PlayVictorySound(source); // Killer laughs at you! LAUGHS! BWAHAHAHHAHAA!! } - - player->rings = 0; return true; } @@ -2998,7 +3006,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, } } -static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) +static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype, boolean dospheres) { P_DoPlayerPain(player, source, inflictor); @@ -3028,9 +3036,19 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN // Ring loss sound plays despite hitting spikes P_PlayRinglossSound(player->mo); // Ringledingle! P_PlayerRingBurst(player, damage); - player->rings -= damage; - if (player->rings < 0) - player->rings = 0; + + if (dospheres) + { + player->spheres -= damage; + if (player->spheres < 0) + player->spheres = 0; + } + else + { + player->rings -= damage; + if (player->rings < 0) + player->rings = 0; + } } // @@ -3247,7 +3265,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (damagetype & DMG_DEATHMASK) { P_KillPlayer(player, source, damage); - player->rings = 0; + player->rings = player->spheres = 0; } else if (metalrecording) { @@ -3291,10 +3309,19 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da P_ShieldDamage(player, inflictor, source, damage, damagetype); damage = 0; } + else if (player->powers[pw_carry] == CR_NIGHTSFALL) + { + if (player->spheres > 0) + { + damage = player->spheres; + P_RingDamage(player, inflictor, source, damage, damagetype, true); + damage = 0; + } + } else if (player->rings > 0) // No shield but have rings. { damage = player->rings; - P_RingDamage(player, inflictor, source, damage, damagetype); + P_RingDamage(player, inflictor, source, damage, damagetype, false); damage = 0; } // To reduce griefing potential, don't allow players to be killed @@ -3430,6 +3457,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) P_SetObjectMomZ(mo, 8*FRACUNIT, false); mo->fuse = 20*TICRATE; // Adjust fuse for NiGHTS + // Toggle bonus time colors P_SetMobjState(mo, (player->bonustime ? mo->info->raisestate : mo->info->spawnstate)); } else diff --git a/src/p_user.c b/src/p_user.c index 357933f14..449f95db2 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -7023,7 +7023,7 @@ static void P_MovePlayer(player_t *player) if (playeringame[i]) players[i].exiting = (14*TICRATE)/5 + 1; } - else if (player->rings > 0) + else if (player->spheres > 0) P_DamageMobj(player->mo, NULL, NULL, 1, 0); player->powers[pw_carry] = CR_NONE; } From 14c17cf012e70ae50bc5b011310f92d02ddbd7a2 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 02:34:21 -0400 Subject: [PATCH 208/212] Tag damage fix error --- src/p_inter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index 87d780f7a..e740b62d1 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2784,7 +2784,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou else if (player->rings > 0) // Ring loss { P_PlayRinglossSound(target); - P_PlayerRingBurst(player, max(player->spheres, player->rings)); + P_PlayerRingBurst(player, player->rings); player->rings = 0; } else // Death From b05960431d21e14d0ac9c233d2572330cd5a9689 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 03:05:10 -0400 Subject: [PATCH 209/212] Reset player->rings on denightserize and on new mare --- src/p_user.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 449f95db2..52b4cd88a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -590,8 +590,9 @@ static void P_DeNightserizePlayer(player_t *player) else if (player == &players[secondarydisplayplayer]) localaiming2 = 0; - // If you screwed up, kiss your score goodbye. + // If you screwed up, kiss your score and ring bonus goodbye. player->marescore = 0; + player->rings = 0; P_SetPlayerMobjState(player->mo, S_PLAY_FALL); @@ -721,7 +722,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) players[i].lastmarescore = players[i].marescore; players[i].marescore = 0; - players[i].spheres = 0; + players[i].spheres = players[i].rings = 0; P_DoPlayerExit(&players[i]); } } @@ -745,7 +746,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->marescore = 0; player->marebegunat = leveltime; - player->spheres = 0; + player->spheres = player->rings = 0; } else { From bd8316f49b5b2c2f61bb519a469085e28b6ac6d1 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 04:05:20 -0400 Subject: [PATCH 210/212] Track player's previous mare rings with player->finishedrings. There may not be a point to this, other than to be consistent with how spheres are tracked. If non-special stage NiGHTS should tally a ring bonus, this may be useful. --- src/d_player.h | 1 + src/lua_playerlib.c | 4 ++++ src/p_saveg.c | 2 ++ src/p_setup.c | 13 +++++++------ src/p_user.c | 6 ++++++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 24c4f9252..7bee5f337 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -462,6 +462,7 @@ typedef struct player_s tic_t startedtime; // Time which you started this mare with. tic_t finishedtime; // Time it took you to finish the mare (used for display) INT16 finishedspheres; // The spheres you had left upon finishing the mare + INT16 finishedrings; // The rings/stars you had left upon finishing the mare UINT32 marescore; // score for this nights stage UINT32 lastmarescore; // score for the last mare UINT8 lastmare; // previous mare diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 8a1079c36..ff62f2459 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -298,6 +298,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->finishedtime); else if (fastcmp(field,"finishedspheres")) lua_pushinteger(L, plr->finishedspheres); + else if (fastcmp(field,"finishedrings")) + lua_pushinteger(L, plr->finishedrings); else if (fastcmp(field,"marescore")) lua_pushinteger(L, plr->marescore); else if (fastcmp(field,"lastmarescore")) @@ -576,6 +578,8 @@ static int player_set(lua_State *L) plr->finishedtime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"finishedspheres")) plr->finishedspheres = (INT16)luaL_checkinteger(L, 3); + else if (fastcmp(field,"finishedrings")) + plr->finishedrings = (INT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"marescore")) plr->marescore = (UINT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"lastmarescore")) diff --git a/src/p_saveg.c b/src/p_saveg.c index 2e47f2077..7cf437384 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -203,6 +203,7 @@ static void P_NetArchivePlayers(void) WRITEUINT32(save_p, players[i].startedtime); WRITEUINT32(save_p, players[i].finishedtime); WRITEINT16(save_p, players[i].finishedspheres); + WRITEINT16(save_p, players[i].finishedrings); WRITEUINT32(save_p, players[i].marescore); WRITEUINT32(save_p, players[i].lastmarescore); WRITEUINT8(save_p, players[i].lastmare); @@ -391,6 +392,7 @@ static void P_NetUnArchivePlayers(void) players[i].startedtime = READUINT32(save_p); players[i].finishedtime = READUINT32(save_p); players[i].finishedspheres = READINT16(save_p); + players[i].finishedrings = READINT16(save_p); players[i].marescore = READUINT32(save_p); players[i].lastmarescore = READUINT32(save_p); players[i].lastmare = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 7597b7d87..b8db575b5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2380,12 +2380,13 @@ static void P_LevelInitStuff(void) players[i].marescore = players[i].lastmarescore =\ players[i].maxlink = players[i].startedtime =\ players[i].finishedtime = players[i].finishedspheres =\ - players[i].lastmare = players[i].marebegunat =\ - players[i].textvar = players[i].texttimer =\ - players[i].linkcount = players[i].linktimer =\ - players[i].flyangle = players[i].anotherflyangle =\ - players[i].nightstime = players[i].mare =\ - players[i].realtime = players[i].exiting = 0; + players[i].finishedrings = players[i].lastmare =\ + players[i].marebegunat = players[i].textvar =\ + players[i].texttimer = players[i].linkcount =\ + players[i].linktimer = players[i].flyangle =\ + players[i].anotherflyangle = players[i].nightstime =\ + players[i].mare = players[i].realtime =\ + players[i].exiting = 0; // i guess this could be part of the above but i feel mildly uncomfortable implicitly casting players[i].gotcontinue = false; diff --git a/src/p_user.c b/src/p_user.c index 52b4cd88a..fd09b0847 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -685,6 +685,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) { INT32 i; INT32 total_spheres = 0; + INT32 total_rings = 0; P_SetTarget(&player->mo->target, NULL); @@ -692,7 +693,10 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) { for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]/* && players[i].powers[pw_carry] == CR_NIGHTSMODE*/) + { total_spheres += players[i].spheres; + total_rings += players[i].rings; + } } for (i = 0; i < MAXPLAYERS; i++) @@ -706,11 +710,13 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) if (G_IsSpecialStage(gamemap)) { players[i].finishedspheres = (INT16)total_spheres; + players[i].finishedrings = (INT16)total_rings; P_AddPlayerScore(player, total_spheres * 50); } else { players[i].finishedspheres = (INT16)(players[i].spheres); + players[i].finishedrings = (INT16)(players[i].rings); P_AddPlayerScore(&players[i], (players[i].spheres) * 50); } From 4cb7036f513ea9a0c1c743a1de69c40294597c27 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 12:47:44 -0400 Subject: [PATCH 211/212] SETSPHERES console command for debugging/cheating Fixed sphere spill bug where no spheres spill if player->rings is 0 --- src/d_netcmd.c | 1 + src/m_cheat.c | 17 +++++++++++++++++ src/m_cheat.h | 1 + src/p_inter.c | 2 +- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f3fb1f6ae..dbb0b0ff5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -822,6 +822,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("getallemeralds", Command_Getallemeralds_f); COM_AddCommand("resetemeralds", Command_Resetemeralds_f); COM_AddCommand("setrings", Command_Setrings_f); + COM_AddCommand("setspheres", Command_Setspheres_f); COM_AddCommand("setlives", Command_Setlives_f); COM_AddCommand("setcontinues", Command_Setcontinues_f); COM_AddCommand("devmode", Command_Devmode_f); diff --git a/src/m_cheat.c b/src/m_cheat.c index 5ac742270..b572b84eb 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -890,6 +890,23 @@ void Command_Setrings_f(void) } } +void Command_Setspheres_f(void) +{ + REQUIRE_INLEVEL; + REQUIRE_SINGLEPLAYER; + REQUIRE_NOULTIMATE; + REQUIRE_PANDORA; + + if (COM_Argc() > 1) + { + // P_GivePlayerRings does value clamping + players[consoleplayer].spheres = 0; + P_GivePlayerSpheres(&players[consoleplayer], atoi(COM_Argv(1))); + + G_SetGameModified(multiplayer); + } +} + void Command_Setlives_f(void) { REQUIRE_INLEVEL; diff --git a/src/m_cheat.h b/src/m_cheat.h index 951c7a16a..31f650b3f 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -51,6 +51,7 @@ void Command_Savecheckpoint_f(void); void Command_Getallemeralds_f(void); void Command_Resetemeralds_f(void); void Command_Setrings_f(void); +void Command_Setspheres_f(void); void Command_Setlives_f(void); void Command_Setcontinues_f(void); void Command_Devmode_f(void); diff --git a/src/p_inter.c b/src/p_inter.c index e740b62d1..ce8bba6b6 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3409,7 +3409,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) return; // If no health, don't spawn ring! - if (player->rings <= 0) + if (((maptol & TOL_NIGHTS) && player->spheres <= 0) || (!(maptol & TOL_NIGHTS) && player->rings <= 0)) num_rings = 0; if (num_rings > 32 && player->powers[pw_carry] != CR_NIGHTSFALL) From 672e196aa492cbd9013decc2d41d2e646e6f22f8 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 10 Aug 2018 13:15:54 -0400 Subject: [PATCH 212/212] Pandora's Box support for player->spheres Opting to handle this transparently via the Rings menu option. Doesn't seem worth making a separate entry for Spheres. --- src/m_menu.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index b11873adb..f99f5d860 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5273,7 +5273,10 @@ static void M_HandleAddons(INT32 choice) static void M_PandorasBox(INT32 choice) { (void)choice; - CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0)); + if (maptol & TOL_NIGHTS) + CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].spheres, 0)); + else + CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0)); if (players[consoleplayer].lives == 0x7f) CV_StealthSetValue(&cv_dummylives, -1); else @@ -5291,7 +5294,12 @@ static void M_PandorasBox(INT32 choice) static boolean M_ExitPandorasBox(void) { if (cv_dummyrings.value != max(players[consoleplayer].rings, 0)) - COM_ImmedExecute(va("setrings %d", cv_dummyrings.value)); + { + if (maptol & TOL_NIGHTS) + COM_ImmedExecute(va("setspheres %d", cv_dummyrings.value)); + else + COM_ImmedExecute(va("setrings %d", cv_dummyrings.value)); + } if (cv_dummylives.value != players[consoleplayer].lives) COM_ImmedExecute(va("setlives %d", cv_dummylives.value)); if (cv_dummycontinues.value != players[consoleplayer].continues)