diff --git a/src/p_polyobj.c b/src/p_polyobj.c index eaa8d7449..c4b2630c0 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -28,6 +28,10 @@ #include "r_state.h" #include "r_defs.h" + +#define POLYOBJECTS + + #ifdef POLYOBJECTS /* @@ -2265,7 +2269,7 @@ void T_PolyDoorSwing(polyswingdoor_t *th) } } -// T_PolyObjDisplace: shift a polyobject based on a control sector's heights. -Red +// T_PolyObjDisplace: shift a polyobject based on a control sector's heights. void T_PolyObjDisplace(polydisplace_t *th) { polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); @@ -2274,10 +2278,10 @@ void T_PolyObjDisplace(polydisplace_t *th) if (!po) #ifdef RANGECHECK - I_Error("T_PolyDoorSwing: thinker has invalid id %d\n", th->polyObjNum); + I_Error("T_PolyObjDisplace: thinker has invalid id %d\n", th->polyObjNum); #else { - CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSwing: thinker with invalid id %d removed.\n", th->polyObjNum); + CONS_Debug(DBG_POLYOBJ, "T_PolyObjDisplace: thinker with invalid id %d removed.\n", th->polyObjNum); P_RemoveThinkerDelayed(&th->thinker); return; } @@ -2305,6 +2309,45 @@ void T_PolyObjDisplace(polydisplace_t *th) th->oldHeights = newheights; } +// T_PolyObjRotDisplace: rotate a polyobject based on a control sector's heights. +void T_PolyObjRotDisplace(polyrotdisplace_t *th) +{ + polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); + fixed_t newheights, delta; + fixed_t rotangle; + + if (!po) +#ifdef RANGECHECK + I_Error("T_PolyObjRotDisplace: thinker has invalid id %d\n", th->polyObjNum); +#else + { + CONS_Debug(DBG_POLYOBJ, "T_PolyObjRotDisplace: thinker with invalid id %d removed.\n", th->polyObjNum); + P_RemoveThinkerDelayed(&th->thinker); + return; + } +#endif + + // check for displacement due to override and reattach when possible + if (po->thinker == NULL) + { + po->thinker = &th->thinker; + + // reset polyobject's thrust + po->thrust = FRACUNIT; + } + + newheights = th->controlSector->floorheight+th->controlSector->ceilingheight; + delta = newheights-th->oldHeights; + + if (!delta) + return; + + rotangle = FixedMul(th->rotscale, delta); + + if (Polyobj_rotate(po, FixedAngle(rotangle), th->turnobjs)) + th->oldHeights = newheights; +} + static inline INT32 Polyobj_AngSpeed(INT32 speed) { return (speed*ANG1)>>3; // no FixedAngle() @@ -2764,6 +2807,52 @@ INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata) return 1; } +INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata) +{ + polyobj_t *po; + polyobj_t *oldpo; + polyrotdisplace_t *th; + INT32 start; + + if (!(po = Polyobj_GetForNum(prdata->polyObjNum))) + { + CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjRotate: bad polyobj %d\n", prdata->polyObjNum); + return 0; + } + + // don't allow line actions to affect bad polyobjects + if (po->isBad) + return 0; + + // create a new thinker + th = Z_Malloc(sizeof(polyrotdisplace_t), PU_LEVSPEC, NULL); + th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotDisplace; + PolyObj_AddThinker(&th->thinker); + po->thinker = &th->thinker; + + // set fields + th->polyObjNum = prdata->polyObjNum; + + th->controlSector = prdata->controlSector; + th->oldHeights = th->controlSector->floorheight+th->controlSector->ceilingheight; + + th->rotscale = prdata->rotscale; + th->turnobjs = prdata->turnobjs; + + oldpo = po; + + // apply action to mirroring polyobjects as well + start = 0; + while ((po = Polyobj_GetChild(oldpo, &start))) + { + prdata->polyObjNum = po->id; // change id to match child polyobject's + EV_DoPolyObjRotDisplace(prdata); + } + + // action was successful + return 1; +} + void T_PolyObjFlag(polymove_t *th) { polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); diff --git a/src/p_polyobj.h b/src/p_polyobj.h index b871ec837..73a11d237 100644 --- a/src/p_polyobj.h +++ b/src/p_polyobj.h @@ -207,6 +207,17 @@ typedef struct polydisplace_s fixed_t oldHeights; } polydisplace_t; +typedef struct polyrotdisplace_s +{ + thinker_t thinker; // must be first + + INT32 polyObjNum; + struct sector_s *controlSector; + fixed_t rotscale; + UINT8 turnobjs; + fixed_t oldHeights; +} polyrotdisplace_t; + typedef struct polyfade_s { thinker_t thinker; // must be first @@ -280,6 +291,14 @@ typedef struct polydisplacedata_s fixed_t dy; } polydisplacedata_t; +typedef struct polyrotdisplacedata_s +{ + INT32 polyObjNum; + struct sector_s *controlSector; + fixed_t rotscale; + UINT8 turnobjs; +} polyrotdisplacedata_t; + typedef struct polyfadedata_s { INT32 polyObjNum; @@ -310,6 +329,7 @@ void T_PolyObjWaypoint (polywaypoint_t *); void T_PolyDoorSlide(polyslidedoor_t *); void T_PolyDoorSwing(polyswingdoor_t *); void T_PolyObjDisplace (polydisplace_t *); +void T_PolyObjRotDisplace (polyrotdisplace_t *); void T_PolyObjFlag (polymove_t *); void T_PolyObjFade (polyfade_t *); @@ -318,6 +338,7 @@ INT32 EV_DoPolyObjMove(polymovedata_t *); INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *); INT32 EV_DoPolyObjRotate(polyrotdata_t *); INT32 EV_DoPolyObjDisplace(polydisplacedata_t *); +INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *); INT32 EV_DoPolyObjFlag(struct line_s *); INT32 EV_DoPolyObjFade(polyfadedata_t *); diff --git a/src/p_saveg.c b/src/p_saveg.c index 7a31fecfc..0d58387b9 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1312,6 +1312,7 @@ typedef enum tc_polyswingdoor, tc_polyflag, tc_polydisplace, + tc_polyrotdisplace, tc_polyfade, #endif tc_end @@ -2088,6 +2089,17 @@ static void SavePolydisplaceThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->oldHeights); } +static void SavePolyrotdisplaceThinker(const thinker_t *th, const UINT8 type) +{ + const polyrotdisplace_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEINT32(save_p, ht->polyObjNum); + WRITEUINT32(save_p, SaveSector(ht->controlSector)); + WRITEFIXED(save_p, ht->rotscale); + WRITEUINT8(save_p, ht->turnobjs); + WRITEFIXED(save_p, ht->oldHeights); +} + static void SavePolyfadeThinker(const thinker_t *th, const UINT8 type) { const polyfade_t *ht = (const void *)th; @@ -2333,6 +2345,11 @@ static void P_NetArchiveThinkers(void) SavePolydisplaceThinker(th, tc_polydisplace); continue; } + else if (th->function.acp1 == (actionf_p1)T_PolyObjRotDisplace) + { + SavePolyrotdisplaceThinker(th, tc_polyrotdisplace); + continue; + } else if (th->function.acp1 == (actionf_p1)T_PolyObjFade) { SavePolyfadeThinker(th, tc_polyfade); @@ -3217,6 +3234,18 @@ static inline void LoadPolydisplaceThinker(actionf_p1 thinker) P_AddThinker(&ht->thinker); } +static inline void LoadPolyrotdisplaceThinker(actionf_p1 thinker) +{ + polyrotdisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->polyObjNum = READINT32(save_p); + ht->controlSector = LoadSector(READUINT32(save_p)); + ht->rotscale = READFIXED(save_p); + ht->turnobjs = READUINT8(save_p); + ht->oldHeights = READFIXED(save_p); + P_AddThinker(&ht->thinker); +} + // // LoadPolyfadeThinker // @@ -3446,6 +3475,10 @@ static void P_NetUnArchiveThinkers(void) LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace); break; + case tc_polyrotdisplace: + LoadPolyrotdisplaceThinker((actionf_p1)T_PolyObjRotDisplace); + break; + case tc_polyfade: LoadPolyfadeThinker((actionf_p1)T_PolyObjFade); break; diff --git a/src/p_spec.c b/src/p_spec.c index 0f5a502af..f8ce313ea 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1412,6 +1412,34 @@ static boolean PolyDisplace(line_t *line) return EV_DoPolyObjDisplace(&pdd); } + +/** Similar to PolyDisplace(). + */ +static boolean PolyRotDisplace(line_t *line) +{ + polyrotdisplacedata_t pdd; + fixed_t anginter, distinter; + + pdd.polyObjNum = line->tag; + pdd.controlSector = line->frontsector; + + // Rotate 'anginter' interval for each 'distinter' interval from the control sector. + // Use default values if not provided as fallback. + anginter = sides[line->sidenum[0]].rowoffset ? sides[line->sidenum[0]].rowoffset : 90*FRACUNIT; + distinter = sides[line->sidenum[0]].textureoffset ? sides[line->sidenum[0]].textureoffset : 128*FRACUNIT; + pdd.rotscale = FixedDiv(anginter, distinter); + + // Same behavior as other rotators when carrying things. + if (line->flags & ML_NOCLIMB) + pdd.turnobjs = 0; + else if (line->flags & ML_EFFECT4) + pdd.turnobjs = 2; + else + pdd.turnobjs = 1; + + return EV_DoPolyObjRotDisplace(&pdd); +} + #endif // ifdef POLYOBJECTS /** Changes a sector's tag. @@ -7363,6 +7391,10 @@ void P_SpawnSpecials(INT32 fromnetsave) case 31: // Polyobj_Displace PolyDisplace(&lines[i]); break; + + case 32: // Polyobj_RotDisplace + PolyRotDisplace(&lines[i]); + break; } } #endif