diff --git a/extras/conf/RingRacers_ACS.cfg b/extras/conf/RingRacers_ACS.cfg index 3bd5afa62..fd498de96 100644 --- a/extras/conf/RingRacers_ACS.cfg +++ b/extras/conf/RingRacers_ACS.cfg @@ -25,7 +25,7 @@ terminator = ";"; extrawordchars = "#"; // Extra characters to be treated as a part of a word by the Script Editor //keywordhelp = "http://www.zdoom.org/wiki/index.php?title=%K"; snippetsdir = "acs"; -scripttype = 1; //0 = unknown script, 1 = acc, 2 = modeldef, 3 = decorate +scripttype = "ACS"; keywords { @@ -71,78 +71,6 @@ keywords Ends a collaspable text region. See also: #region\n Ignored by the compiler."; - // Keywords - if = "if ()"; - else = "else"; - for = "for (; ; )"; - do = "do"; - while = "while ()"; - until = "until ()"; - break = "break"; - continue = "continue"; - switch = "switch ()"; - case = "case :"; - default = "default:"; - const = "const"; - function = "function ([arg], [...])"; - script = "script ([arg], [...])"; - - return = "return \n - Return value for functions.\n - Does not work in scripts."; - - restart = "restart\n - Restarts the current script from the beginning.\n - Does not work in functions."; - - suspend = "suspend\n - Pauses the current script. It can be resumed by\n - activating the same script again.\n - Does not work in functions."; - - terminate = "terminate\n - Ends the current script early.\n - Does not work in functions."; - - special = "special \n - Defines special actions for the ACS compiler.\n - Serves little to no purpose for level scripts."; - - world = "world :\n - Sets a wrapper for a hub scope variable.\n - Unimplemented in Ring Racers."; - - global = "global :\n - Sets a wrapper for a global scope variable.\n - Unimplemented in Ring Racers."; - - // Types - void = "void"; - bool = "bool"; - int = "int"; - str = "str"; - fixed = "fixed"; - - // Script modifiers - OPEN = "script OPEN\n - Makes a script automatically run when the level is initially loaded."; - - ENTER = "script ENTER\n - Makes a script automatically run when a player enters the game.\n - The activator is set to said player for this script."; - - RESPAWN = "script RESPAWN\n - Makes a script automatically run when a player respawns.\n - The activator is set to said player for this script."; - - DEATH = "script DEATH\n - Makes a script automatically run when a player dies.\n - The activator is set to said player for this script."; - - LAP = "script LAP\n - Makes a script automatically run whenever a player crosses the finish line.\n - The activator is set to said player for this script."; - // Specials Sector_CopyHeights = "void Sector_CopyHeights(int tag1, int tag2, int plane, [bool texture])\n Sets the plane heights of the tagged sectors to match another sector.\n @@ -666,6 +594,17 @@ keywords - tag: The sector tag to search for waypoints in.\n - enable: If true, enable the waypoints. Otherwise, disable the waypoints."; + Player_FinishLine = "void Player_FinishLine([bool flip])\n + Makes the activating player gain or lose a lap, depending on the activating side.\n + Runs the LAP script type when incrementing.\n + - flip: Flip which side of the activating line is used to increment laps.\n + If there was no activating line, then this will increment when false, and decrement when true."; + + Player_Respawn = "void Player_Respawn([bool frontonly])\n + Makes the activating player respawn.\n + - frontonly: If true, then only respawn when crossing the front side.\n + Has no effect if this was not activated from a line."; + // Functions Delay = "void Delay(int tics)\n Pauses the current script.\n @@ -836,6 +775,46 @@ keywords For logging to only the activator, use Log."; } +properties +{ + // Keywords + if; + else; + for; + do; + while; + until; + break; + continue; + switch; + case; + default; + const; + function; + script; + return; + restart; + suspend; + terminate; + world; + global; + special; + + // Types + void; + bool; + int; + str; + fixed; + + // Script modifiers + OPEN; + ENTER; + RESPAWN; + DEATH; + LAP; +} + constants { TRUE; diff --git a/extras/conf/udb/Includes/RingRacers_misc.cfg b/extras/conf/udb/Includes/RingRacers_misc.cfg index 8484dea68..df17459f7 100644 --- a/extras/conf/udb/Includes/RingRacers_misc.cfg +++ b/extras/conf/udb/Includes/RingRacers_misc.cfg @@ -63,6 +63,31 @@ linedefflags_udmf transfer = "FOF Transfer"; } +linedefactivations +{ + 1 = "When player crosses"; + 2 = "When enemy crosses"; + 4 = "When projectile crosses"; + 8 = "When player bumps"; + 16 = "When enemy bumps"; + 32 = "On projectile impact"; +} + +linedefactivations_udmf +{ + repeatspecial + { + name = "Repeatable action"; + istrigger = false; + } + playercross = "When player crosses"; + playerpush = "When player bumps"; + monstercross = "When enemy crosses"; + monsterpush = "When enemy bumps"; + missilecross = "When projectile crosses"; + impact = "On projectile impact"; +} + linedefrenderstyles { translucent = "Translucent"; diff --git a/extras/gdcc/inc/ACS/rrspecial.acs b/extras/gdcc/inc/ACS/rrspecial.acs index d325a92d9..2ffc348f1 100644 --- a/extras/gdcc/inc/ACS/rrspecial.acs +++ b/extras/gdcc/inc/ACS/rrspecial.acs @@ -152,6 +152,9 @@ special int 499:Sector_ToggleWaypoints(2), + int 2001:Player_FinishLine(0, 1), + int 2003:Player_RespawnLine(0, 1), + // Internal functions have negative values // [type] [ID]:[function name]([required args], [type of each arg, including optional ones]) /* diff --git a/src/doomdata.h b/src/doomdata.h index 5767da5ec..eab695ca7 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -120,35 +120,59 @@ enum // top and bottom textures (use next to windows). // upper texture unpegged - ML_DONTPEGTOP = 0x00000008, + ML_DONTPEGTOP = 0x00000008, // lower texture unpegged - ML_DONTPEGBOTTOM = 0x00000010, + ML_DONTPEGBOTTOM = 0x00000010, - ML_SKEWTD = 0x00000020, + ML_SKEWTD = 0x00000020, // Don't let Knuckles climb on this line - ML_NOCLIMB = 0x00000040, + ML_NOCLIMB = 0x00000040, - ML_NOSKEW = 0x00000080, - ML_MIDPEG = 0x00000100, - ML_MIDSOLID = 0x00000200, - ML_WRAPMIDTEX = 0x00000400, + ML_NOSKEW = 0x00000080, + ML_MIDPEG = 0x00000100, + ML_MIDSOLID = 0x00000200, + ML_WRAPMIDTEX = 0x00000400, // Apply effect only in netgames - ML_NETONLY = 0x00000800, + ML_NETONLY = 0x00000800, // Apply effect only in single player games - ML_NONET = 0x00001000, + ML_NONET = 0x00001000, // Blocks enemies only - ML_BLOCKMONSTERS = 0x00002000, + ML_BLOCKMONSTERS = 0x00002000, // Don't bounce off this wall! - ML_NOTBOUNCY = 0x00004000, + ML_NOTBOUNCY = 0x00004000, // Transfers FOF properties. - ML_TFERLINE = 0x00008000, + ML_TFERLINE = 0x00008000, + + // Special action is repeatable. + ML_REPEATSPECIAL = 0x00010000, +}; + +enum +{ + // Activates when crossed by a player. + SPAC_CROSS = 0x00000001, + + // Activates when crossed by an enemy. + SPAC_CROSSMONSTER = 0x00000002, + + // Activates when crossed by a projectile. + SPAC_CROSSMISSILE = 0x00000004, + + // Activates when bumped by a player. + SPAC_PUSH = 0x00000008, + + // Activates when bumped by an enemy. + SPAC_PUSHMONSTER = 0x00000010, + + // Activates when bumped by a missile. + SPAC_IMPACT = 0x00000020, }; // Sector definition, from editing. diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 472321df1..d7492c466 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -112,6 +112,7 @@ enum line_e { line_dy, line_angle, line_flags, + line_activation, line_special, line_tag, line_taglist, @@ -138,6 +139,7 @@ static const char *const line_opt[] = { "dy", "angle", "flags", + "activation", "special", "tag", "taglist", @@ -950,6 +952,9 @@ static int line_get(lua_State *L) case line_flags: lua_pushinteger(L, line->flags); return 1; + case line_activation: + lua_pushinteger(L, line->activation); + return 1; case line_special: lua_pushinteger(L, line->special); return 1; diff --git a/src/p_map.c b/src/p_map.c index ef4819118..4b81e8c14 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -249,20 +249,11 @@ static boolean P_SpecialIsLinedefCrossType(line_t *ld) { boolean linedefcrossspecial = false; - switch (ld->special) + // Take anything with any cross type for now, + // we'll have to filter it down later... + if (ld->activation & (SPAC_CROSS | SPAC_CROSSMONSTER | SPAC_CROSSMISSILE)) { - case 2001: // Finish line - case 2003: // Respawn line - { - linedefcrossspecial = true; - } - break; - - default: - { - linedefcrossspecial = false; - } - break; + linedefcrossspecial = P_CanActivateSpecial(ld->special); } return linedefcrossspecial; diff --git a/src/p_mobj.c b/src/p_mobj.c index 26b38d631..0ad0a8478 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1618,6 +1618,8 @@ void P_XYMovement(mobj_t *mo) else if (P_MobjWasRemoved(mo)) return; + P_PushSpecialLine(tm.blockingline, mo); + if (mo->flags & MF_MISSILE) { // explode a missile @@ -5215,6 +5217,23 @@ boolean P_IsKartItem(INT32 type) } } +boolean K_IsMissileOrKartItem(mobj_t *mo) +{ + if (mo->flags & MF_MISSILE) + { + // It's already a missile! + return true; + } + + if (mo->type == MT_SPB) + { + // Not considered a field item, so manually include. + return true; + } + + return P_IsKartFieldItem(mo->type); +} + // This item can die in death sectors. There may be some // special conditions for items that don't switch types... // TODO: just make a general function for things that should diff --git a/src/p_mobj.h b/src/p_mobj.h index 8e2686900..8b569f069 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -506,6 +506,7 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum); // kartitem stuff: Returns true if the specified 'type' is one of the kart item constants we want in the kitemcap list boolean P_IsKartFieldItem(INT32 type); boolean P_IsKartItem(INT32 type); +boolean K_IsMissileOrKartItem(mobj_t *mo); boolean P_CanDeleteKartItem(INT32 type); void P_AddKartItem(mobj_t *thing); // needs to be called in k_kart.c void P_RunKartItems(void); diff --git a/src/p_saveg.c b/src/p_saveg.c index 7e8934468..b4bd2da71 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1147,6 +1147,10 @@ static void P_NetUnArchiveTubeWaypoints(savebuffer_t *save) #define LD_ARGS 0x10 #define LD_STRINGARGS 0x20 #define LD_EXECUTORDELAY 0x40 +#define LD_DIFF3 0x80 + +// diff3 flags +#define LD_ACTIVATION 0x01 static boolean P_AreArgsEqual(const line_t *li, const line_t *spawnli) { @@ -1540,11 +1544,14 @@ static void ArchiveLines(savebuffer_t *save) const line_t *spawnli = spawnlines; const side_t *si; const side_t *spawnsi; - UINT8 diff, diff2; // no diff3 + UINT8 diff, diff2, diff3; for (i = 0; i < numlines; i++, spawnli++, li++) { - diff = diff2 = 0; + diff = diff2 = diff3 = 0; + + if (li->flags != spawnli->flags) + diff |= LD_FLAG; if (li->special != spawnli->special) diff |= LD_SPECIAL; @@ -1561,6 +1568,9 @@ static void ArchiveLines(savebuffer_t *save) if (li->executordelay != spawnli->executordelay) diff2 |= LD_EXECUTORDELAY; + if (li->activation != spawnli->activation) + diff3 |= LD_ACTIVATION; + if (li->sidenum[0] != 0xffff) { si = &sides[li->sidenum[0]]; @@ -1589,6 +1599,9 @@ static void ArchiveLines(savebuffer_t *save) diff2 |= LD_S2MIDTEX; } + if (diff3) + diff2 |= LD_DIFF3; + if (diff2) diff |= LD_DIFF2; @@ -1598,6 +1611,8 @@ static void ArchiveLines(savebuffer_t *save) WRITEUINT8(save->p, diff); if (diff & LD_DIFF2) WRITEUINT8(save->p, diff2); + if (diff2 & LD_DIFF3) + WRITEUINT8(save->p, diff3); if (diff & LD_FLAG) WRITEUINT32(save->p, li->flags); if (diff & LD_SPECIAL) @@ -1651,6 +1666,8 @@ static void ArchiveLines(savebuffer_t *save) } if (diff2 & LD_EXECUTORDELAY) WRITEINT32(save->p, li->executordelay); + if (diff3 & LD_ACTIVATION) + WRITEUINT32(save->p, li->activation); } } WRITEUINT16(save->p, 0xffff); @@ -1661,7 +1678,7 @@ static void UnArchiveLines(savebuffer_t *save) UINT16 i; line_t *li; side_t *si; - UINT8 diff, diff2; // no diff3 + UINT8 diff, diff2, diff3; for (;;) { @@ -1680,6 +1697,11 @@ static void UnArchiveLines(savebuffer_t *save) else diff2 = 0; + if (diff2 & LD_DIFF3) + diff3 = READUINT8(save->p); + else + diff3 = 0; + if (diff & LD_FLAG) li->flags = READUINT32(save->p); if (diff & LD_SPECIAL) @@ -1735,6 +1757,8 @@ static void UnArchiveLines(savebuffer_t *save) } if (diff2 & LD_EXECUTORDELAY) li->executordelay = READINT32(save->p); + if (diff3 & LD_ACTIVATION) + li->activation = READUINT32(save->p); } } diff --git a/src/p_setup.c b/src/p_setup.c index 73b10a0e9..af2b2e901 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1646,6 +1646,21 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char lines[i].flags |= ML_NOTBOUNCY; else if (fastcmp(param, "transfer") && fastcmp("true", val)) lines[i].flags |= ML_TFERLINE; + else if (fastcmp(param, "repeatspecial") && fastcmp("true", val)) + lines[i].flags |= ML_REPEATSPECIAL; + // Activation flags + else if (fastcmp(param, "playercross") && fastcmp("true", val)) + lines[i].activation |= SPAC_CROSS; + else if (fastcmp(param, "monstercross") && fastcmp("true", val)) + lines[i].activation |= SPAC_CROSSMONSTER; + else if (fastcmp(param, "missilecross") && fastcmp("true", val)) + lines[i].activation |= SPAC_CROSSMISSILE; + else if (fastcmp(param, "playerpush") && fastcmp("true", val)) + lines[i].activation |= SPAC_PUSH; + else if (fastcmp(param, "monsterpush") && fastcmp("true", val)) + lines[i].activation |= SPAC_PUSHMONSTER; + else if (fastcmp(param, "impact") && fastcmp("true", val)) + lines[i].activation |= SPAC_IMPACT; } static void ParseTextmapThingParameter(UINT32 i, const char *param, const char *val) @@ -5814,10 +5829,14 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].blendmode = AST_FOG; break; case 2001: //Finish line + lines[i].activation |= SPAC_CROSS; + lines[i].flags |= ML_REPEATSPECIAL; if (lines[i].flags & ML_NOCLIMB) lines[i].args[0] |= TMCFF_FLIP; break; case 2003: //Respawn line + lines[i].activation |= SPAC_CROSS; + lines[i].flags |= ML_REPEATSPECIAL; if (lines[i].flags & ML_NOCLIMB) lines[i].args[0] |= TMCRF_FRONTONLY; break; diff --git a/src/p_spec.c b/src/p_spec.c index 85c9fb58f..47d8b0727 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1376,9 +1376,26 @@ static boolean P_CheckPushables(line_t *triggerline, sector_t *caller) } } +boolean P_CanActivateSpecial(INT16 special) +{ + switch (special) + { + case 2001: // Finish line + case 2003: // Respawn line + { + return true; + } + default: + { + // Linedef executors + return (special >= 400 && special < 500); + } + } +} + static void P_ActivateLinedefExecutor(line_t *line, mobj_t *actor, sector_t *caller) { - if (line->special < 400 || line->special >= 500) + if (P_CanActivateSpecial(line->special) == false) return; if (line->executordelay) @@ -2073,68 +2090,183 @@ static void K_HandleLapDecrement(player_t *player) } } +static void P_LineSpecialWasActivated(line_t *line) +{ + if (!(line->flags & ML_REPEATSPECIAL)) + { + line->special = 0; + } +} + +static boolean P_AllowSpecialCross(line_t *line, mobj_t *thing) +{ + if (P_CanActivateSpecial(line->special) == false) + { + // No special to even activate. + return false; + } + + if (thing->player != NULL) + { + return !!(line->activation & SPAC_CROSS); + } + else if ((thing->flags & (MF_ENEMY|MF_BOSS)) != 0) + { + return !!(line->activation & SPAC_CROSSMONSTER); + } + else if (K_IsMissileOrKartItem(thing) == true) + { + return !!(line->activation & SPAC_CROSSMISSILE); + } + + // No activation flags for you. + return false; +} + // // P_CrossSpecialLine - TRIGGER // Called every time a thing origin is about // to cross a line with specific specials -// Kart - Only used for the finish line currently // void P_CrossSpecialLine(line_t *line, INT32 side, mobj_t *thing) { - // only used for the players currently - if (!(thing && thing->player && !thing->player->spectator && !(thing->player->pflags & PF_NOCONTEST))) - return; - { - player_t *player = thing->player; + player_t *player = NULL; + activator_t *activator = NULL; + boolean result = false; + if (thing == NULL || P_MobjWasRemoved(thing) == true || thing->health <= 0) + { + // Invalid mobj. + return; + } + + player = thing->player; + + if (player != NULL) + { + if (player->spectator == true) + { + // Ignore spectators. + return; + } + + if (player->pflags & PF_NOCONTEST) + { + // Ignore NO CONTEST. + return; + } + + // Tripwire effect if (P_IsLineTripWire(line)) { K_ApplyTripWire(player, TRIPSTATE_PASSED); } + } - switch (line->special) + if (P_AllowSpecialCross(line, thing) == false) + { + // This special can't be activated this way. + return; + } + + activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); + I_Assert(activator != NULL); + + P_SetTarget(&activator->mo, thing); + activator->line = line; + activator->side = side; + activator->sector = (side != 0) ? line->backsector : line->frontsector; + activator->fromLineSpecial = true; + + result = P_ProcessSpecial(activator, line->special, line->args, line->stringargs); + Z_Free(activator); + + if (result == true) + { + P_LineSpecialWasActivated(line); + } +} + +static boolean P_AllowSpecialPush(line_t *line, mobj_t *thing) +{ + if (P_CanActivateSpecial(line->special) == false) + { + // No special to even activate. + return false; + } + + if (thing->player != NULL) + { + return !!(line->activation & SPAC_PUSH); + } + else if ((thing->flags & (MF_ENEMY|MF_BOSS)) != 0) + { + return !!(line->activation & SPAC_PUSHMONSTER); + } + else if (K_IsMissileOrKartItem(thing) == true) + { + return !!(line->activation & SPAC_IMPACT); + } + + // No activation flags for you. + return false; +} + +// +// P_PushSpecialLine - TRIGGER +// Called every time a thing origin is blocked +// by a line with specific specials +// +void P_PushSpecialLine(line_t *line, mobj_t *thing) +{ + player_t *player = NULL; + activator_t *activator = NULL; + boolean result = false; + + if (thing == NULL || P_MobjWasRemoved(thing) == true || thing->health <= 0) + { + // Invalid mobj. + return; + } + + player = thing->player; + + if (player != NULL) + { + if (player->spectator == true) { - case 2001: // Finish Line - { - if ((gametyperules & GTR_CIRCUIT) && !(player->exiting) && !(player->pflags & PF_HITFINISHLINE)) - { - if (((line->args[0] & TMCFF_FLIP) && (side == 0)) - || (!(line->args[0] & TMCFF_FLIP) && (side == 1))) // crossed from behind to infront - { - K_HandleLapIncrement(player); - - ACS_RunLapScript(thing, line); - } - else - { - K_HandleLapDecrement(player); - } - - player->pflags |= PF_HITFINISHLINE; - } - } - break; - - case 2003: // Respawn Line - { - /* No Climb: only trigger from front side */ - if - ( - player->respawn.state == RESPAWNST_NONE && - (!(line->args[0] & TMCRF_FRONTONLY) || side == 0) - ) - { - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT); - } - } - break; - - default: - { - // Do nothing - } - break; + // Ignore spectators. + return; } + + if (player->pflags & PF_NOCONTEST) + { + // Ignore NO CONTEST. + return; + } + } + + if (P_AllowSpecialPush(line, thing) == false) + { + // This special can't be activated this way. + return; + } + + activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); + I_Assert(activator != NULL); + + P_SetTarget(&activator->mo, thing); + activator->line = line; + activator->side = P_PointOnLineSide(thing->x, thing->y, line); + activator->sector = (activator->side != 0) ? line->backsector : line->frontsector; + activator->fromLineSpecial = true; + + result = P_ProcessSpecial(activator, line->special, line->args, line->stringargs); + Z_Free(activator); + + if (result == true) + { + P_LineSpecialWasActivated(line); } } @@ -2221,6 +2353,9 @@ static mobj_t* P_FindObjectTypeFromTag(mobjtype_t type, mtag_t tag) */ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { + // This is an old function purely for linedef executor + // backwards compatibility. + activator_t *activator = NULL; if (line == NULL) @@ -2239,26 +2374,23 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) P_ProcessSpecial(activator, line->special, line->args, line->stringargs); Z_Free(activator); + + // Intentionally no P_LineSpecialWasActivated call. } -void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char **stringargs) +boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char **stringargs) { - line_t *line = activator->line; // If called from a linedef executor, this is the control sector linedef. If from a script, then it's the actual activator. - mobj_t *mo = activator->mo; - sector_t *callsec = activator->sector; + line_t *const line = activator->line; // If called from a linedef executor, this is the control sector linedef. If from a script, then it's the actual activator. + UINT8 const side = activator->side; + mobj_t *const mo = activator->mo; + sector_t *const callsec = activator->sector; // All of these conditions being met means this is a binary map using a linedef executor. - const boolean backwardsCompat = (!udmf && activator->fromLineSpecial && line != NULL); + boolean const backwardsCompat = (!udmf && activator->fromLineSpecial && line != NULL); INT32 secnum = -1; - // - // TODO: Too many specials are tied to a linedef existing, - // even after UDMF cleanups. We'll need to remove all of the - // (line == NULL) guards if we want these to be useful for ACS. - // - - // note: only commands with linedef types >= 400 && < 500 can be used + // note: only specials that P_CanActivateSpecial returns true on can be used switch (special) { case 400: // Copy tagged sector's heights/flats @@ -2270,7 +2402,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 400 Executor: No frontsector to copy planes from!\n"); - return; + return false; } copySector = line->frontsector; } @@ -2280,7 +2412,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (destsec == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 400 Executor: No sector to copy planes from (tag %d)!\n", args[0]); - return; + return false; } copySector = §ors[destsec]; } @@ -2319,7 +2451,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 402 Executor: No frontsector to copy light level from!\n"); - return; + return false; } copySector = line->frontsector; } @@ -2329,7 +2461,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (destsec == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 402 Executor: No sector to copy light level from (tag %d)!\n", args[0]); - return; + return false; } copySector = §ors[destsec]; } @@ -2380,7 +2512,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 403 Executor: No frontsector to copy planes from!\n"); - return; + return false; } copySector = line->frontsector; } @@ -2390,7 +2522,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (destsec == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 403 Executor: No sector to copy planes from (tag %d)!\n", args[0]); - return; + return false; } copySector = §ors[destsec]; } @@ -2450,7 +2582,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 408 Executor: No frontsector to copy flats from!\n"); - return; + return false; } copySector = line->frontsector; } @@ -2460,7 +2592,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (destsec == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 408 Executor: No sector to copy flats from (tag %d)!\n", args[0]); - return; + return false; } copySector = §ors[destsec]; } @@ -2509,7 +2641,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 410 Executor: No linedef to change frontsector tag of!\n"); - return; + return false; } editLine = line; } @@ -2519,7 +2651,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (destline == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 408 Executor: No linedef to change frontsector tag of (tag %d)!\n", args[0]); - return; + return false; } editLine = &lines[destline]; } @@ -2576,7 +2708,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * mobj_t *dest; if (!mo) // nothing to teleport - return; + return false; if (args[1] & TMT_RELATIVE) // Relative silent teleport { @@ -2617,7 +2749,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * dest = P_FindObjectTypeFromTag(MT_TELEPORTMAN, args[0]); if (!dest) - return; + return false; angle = (args[1] & TMT_KEEPANGLE) ? mo->angle : dest->angle; silent = !!(args[1] & TMT_SILENT); @@ -2764,11 +2896,11 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * INT32 aim; if ((!mo || !mo->player) && !titlemapinaction) // only players have views, and title screens - return; + return false; altview = P_FindObjectTypeFromTag(MT_ALTVIEWMAN, args[0]); if (!altview || !altview->spawnpoint) - return; + return false; // If titlemap, set the camera ref for title's thinker // This is not revoked until overwritten; awayviewtics is ignored @@ -2818,7 +2950,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * case 426: // Moves the mobj to its sector's soundorg and on the floor, and stops it if (!mo) - return; + return false; if (args[0]) { @@ -2882,7 +3014,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * case 433: // Flip/flop gravity. Works on pushables, too! if (!mo) - return; + return false; if (args[0]) mo->flags2 &= ~MF2_OBJECTFLIP; @@ -2935,7 +3067,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!sec->ffloors) { CONS_Debug(DBG_GAMELOGIC, "Special type 436: Target sector #%d has no FOFs.\n", secnum); - return; + return false; } for (rover = sec->ffloors; rover; rover = rover->next) @@ -2951,7 +3083,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Special type 436: Can't find a FOF control sector with tag %d\n", foftag); - return; + return false; } } } @@ -2988,7 +3120,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 439 Executor: No activating line to copy textures from!\n"); - return; + return false; } copyLine = line; } @@ -2998,7 +3130,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (origline == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 439 Executor: No tagged line to copy textures from (tag %d)!\n", args[0]); - return; + return false; } copyLine = &lines[origline]; } @@ -3149,7 +3281,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!sec->ffloors) { CONS_Debug(DBG_GAMELOGIC, "Special type 445 Executor: Target sector #%d has no FOFs.\n", secnum); - return; + return false; } for (rover = sec->ffloors; rover; rover = rover->next) @@ -3178,7 +3310,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Special type 445 Executor: Can't find a FOF control sector with tag %d\n", foftag); - return; + return false; } } } @@ -3207,7 +3339,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!sec->ffloors) { CONS_Debug(DBG_GAMELOGIC, "Special type 446 Executor: Target sector #%d has no FOFs.\n", secnum); - return; + return false; } for (rover = sec->ffloors; rover; rover = rover->next) @@ -3226,7 +3358,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Special type 446 Executor: Can't find a FOF control sector with tag %d\n", foftag); - return; + return false; } } } @@ -3251,7 +3383,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 447 Executor: Can't find frontsector with source colormap!\n"); - return; + return false; } source = line->frontsector->extra_colormap; } @@ -3261,7 +3393,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (sourcesec == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 447 Executor: Can't find sector with source colormap (tag %d)!\n", args[1]); - return; + return false; } source = sectors[sourcesec].extra_colormap; } @@ -3416,7 +3548,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!sec->ffloors) { CONS_Debug(DBG_GAMELOGIC, "Line type 452 Executor: Target sector #%d has no FOFs.\n", secnum); - return; + return false; } for (rover = sec->ffloors; rover; rover = rover->next) @@ -3454,7 +3586,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Special type 452 Executor: Can't find a FOF control sector with tag %d\n", foftag); - return; + return false; } } break; @@ -3478,7 +3610,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!sec->ffloors) { CONS_Debug(DBG_GAMELOGIC, "Special type 453 Executor: Target sector #%d has no FOFs.\n", secnum); - return; + return false; } for (rover = sec->ffloors; rover; rover = rover->next) @@ -3542,7 +3674,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Special type 453 Executor: Can't find a FOF control sector with tag %d\n", foftag); - return; + return false; } } break; @@ -3563,7 +3695,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!sec->ffloors) { CONS_Debug(DBG_GAMELOGIC, "Special type 454 Executor: Target sector #%d has no FOFs.\n", secnum); - return; + return false; } for (rover = sec->ffloors; rover; rover = rover->next) @@ -3580,7 +3712,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!foundrover) { CONS_Debug(DBG_GAMELOGIC, "Special type 454 Executor: Can't find a FOF control sector with tag %d\n", foftag); - return; + return false; } } break; @@ -3601,7 +3733,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (line == NULL) { CONS_Debug(DBG_GAMELOGIC, "Special type 455 Executor: Can't find frontsector with destination colormap!\n"); - return; + return false; } dest = line->frontsector->extra_colormap; } @@ -3611,7 +3743,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (destsec == -1) { CONS_Debug(DBG_GAMELOGIC, "Special type 455 Executor: Can't find sector with destination colormap (tag %d)!\n", args[1]); - return; + return false; } dest = sectors[destsec].extra_colormap; } @@ -3718,7 +3850,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * anchormo = P_FindObjectTypeFromTag(MT_ANGLEMAN, args[0]); if (!anchormo) - return; + return false; mo->eflags |= MFE_TRACERANGLE; P_SetTarget(&mo->tracer, anchormo); @@ -3773,7 +3905,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * { // Don't award rings while SPB is targetting you if (mo->player->pflags & PF_RINGLOCK) - return; + return false; if (delay <= 0 || !(leveltime % delay)) { @@ -3837,7 +3969,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * INT32 color = stringargs[0] ? get_number(stringargs[0]) : SKINCOLOR_NONE; if (color < 0 || color >= numskincolors) - return; + return false; var1 = 0; var2 = color; @@ -4005,7 +4137,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!stringargs[0]) { CONS_Debug(DBG_GAMELOGIC, "Linedef type 475: No script name given\n"); - return; + return false; } ACS_Execute(stringargs[0], args, NUMLINEARGS, activator); @@ -4014,7 +4146,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!stringargs[0]) { CONS_Debug(DBG_GAMELOGIC, "Linedef type 476: No script name given\n"); - return; + return false; } ACS_ExecuteAlways(stringargs[0], args, NUMLINEARGS, activator); @@ -4023,7 +4155,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!stringargs[0]) { CONS_Debug(DBG_GAMELOGIC, "Linedef type 477: No script name given\n"); - return; + return false; } ACS_Suspend(stringargs[0]); @@ -4032,7 +4164,7 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * if (!stringargs[0]) { CONS_Debug(DBG_GAMELOGIC, "Linedef type 478: No script name given\n"); - return; + return false; } ACS_Terminate(stringargs[0]); @@ -4097,9 +4229,56 @@ void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char * } break; + case 2001: // Finish Line + { + if (mo->player == NULL) + { + return false; + } + + if ((gametyperules & GTR_CIRCUIT) && (mo->player->exiting == 0) && !(mo->player->pflags & PF_HITFINISHLINE)) + { + if (((line->args[0] & TMCFF_FLIP) && (side == 0)) + || (!(line->args[0] & TMCFF_FLIP) && (side == 1))) // crossed from behind to infront + { + K_HandleLapIncrement(mo->player); + + ACS_RunLapScript(mo, line); + } + else + { + K_HandleLapDecrement(mo->player); + } + + mo->player->pflags |= PF_HITFINISHLINE; + } + } + break; + + case 2003: // Respawn Line + { + if (mo->player == NULL) + { + return false; + } + + /* No Climb: only trigger from front side */ + if + ( + mo->player->respawn.state == RESPAWNST_NONE && + (!(line->args[0] & TMCRF_FRONTONLY) || side == 0) + ) + { + P_DamageMobj(mo, NULL, NULL, 1, DMG_DEATHPIT); + } + } + break; + default: break; } + + return true; } static void P_SetupSignObject(mobj_t *sign, mobj_t *pmo, boolean error) diff --git a/src/p_spec.h b/src/p_spec.h index 240aa42ec..7aa0f5185 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -557,7 +557,8 @@ fixed_t P_FindHighestCeilingSurrounding(sector_t *sec); INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max); -void P_CrossSpecialLine(line_t *ld, INT32 side, mobj_t *thing); +void P_CrossSpecialLine(line_t *line, INT32 side, mobj_t *thing); +void P_PushSpecialLine(line_t *line, mobj_t *thing); // // Special activation info @@ -572,7 +573,8 @@ struct activator_t boolean fromLineSpecial; // Backwards compat for ACS }; -void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char **stringargs); +boolean P_CanActivateSpecial(INT16 special); +boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char **stringargs); void P_SetupSignExit(player_t *player); diff --git a/src/r_defs.h b/src/r_defs.h index 9216603ed..9853f8593 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -525,6 +525,7 @@ struct line_t // Animation related. UINT32 flags; + UINT32 activation; INT16 special; taglist_t tags; INT32 args[NUMLINEARGS];