DPillar::DPillar (sector_t *sector, EPillar type, double speed, double floordist, double ceilingdist, int crush, bool hexencrush) : DMover (sector) { double newheight; vertex_t *spot; sector->floordata = sector->ceilingdata = this; m_Interp_Floor = sector->SetInterpolation(sector_t::FloorMove, true); m_Interp_Ceiling = sector->SetInterpolation(sector_t::CeilingMove, true); m_Type = type; m_Crush = crush; m_Hexencrush = hexencrush; if (type == pillarBuild) { // If the pillar height is 0, have the floor and ceiling meet halfway if (floordist == 0) { newheight = (sector->CenterFloor () + sector->CenterCeiling ()) / 2; m_FloorTarget = sector->floorplane.PointToDist (sector->centerspot, newheight); m_CeilingTarget = sector->ceilingplane.PointToDist (sector->centerspot, newheight); floordist = newheight - sector->CenterFloor (); } else { newheight = sector->CenterFloor () + floordist; m_FloorTarget = sector->floorplane.PointToDist (sector->centerspot, newheight); m_CeilingTarget = sector->ceilingplane.PointToDist (sector->centerspot, newheight); } ceilingdist = sector->CenterCeiling () - newheight; } else { // If one of the heights is 0, figure it out based on the // surrounding sectors if (floordist == 0) { newheight = sector->FindLowestFloorSurrounding (&spot); m_FloorTarget = sector->floorplane.PointToDist (spot, newheight); floordist = sector->floorplane.ZatPoint (spot) - newheight; } else { newheight = sector->CenterFloor() - floordist; m_FloorTarget = sector->floorplane.PointToDist (sector->centerspot, newheight); } if (ceilingdist == 0) { newheight = sector->FindHighestCeilingSurrounding (&spot); m_CeilingTarget = sector->ceilingplane.PointToDist (spot, newheight); ceilingdist = newheight - sector->ceilingplane.ZatPoint (spot); } else { newheight = sector->CenterCeiling() + ceilingdist; m_CeilingTarget = sector->ceilingplane.PointToDist (sector->centerspot, newheight); } } // The speed parameter applies to whichever part of the pillar // travels the farthest. The other part's speed is then set so // that it arrives at its destination at the same time. if (floordist > ceilingdist) { m_FloorSpeed = speed; m_CeilingSpeed = speed * ceilingdist / floordist; } else { m_CeilingSpeed = speed; m_FloorSpeed = speed * floordist / ceilingdist; } if (!(m_Sector->Flags & SECF_SILENTMOVE)) { if (sector->seqType >= 0) { SN_StartSequence(sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0); } else if (sector->SeqName != NAME_None) { SN_StartSequence(sector, CHAN_FLOOR, sector->SeqName, 0); } else { SN_StartSequence(sector, CHAN_FLOOR, "Floor", 0); } } }
//================================================================== // // T_VerticalDoor // //================================================================== void T_VerticalDoor(vldoor_t * door) { result_e res; switch (door->direction) { case 0: // WAITING if (!--door->topcountdown) switch (door->type) { case DREV_NORMAL: door->direction = -1; // time to go back down SN_StartSequence((mobj_t *) & door->sector->soundorg, SEQ_DOOR_STONE + door->sector->seqType); break; case DREV_CLOSE30THENOPEN: door->direction = 1; break; default: break; } break; case 2: // INITIAL WAIT if (!--door->topcountdown) { switch (door->type) { case DREV_RAISEIN5MINS: door->direction = 1; door->type = DREV_NORMAL; break; default: break; } } break; case -1: // DOWN res = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction); if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *) & door->sector->soundorg); switch (door->type) { case DREV_NORMAL: case DREV_CLOSE: door->sector->specialdata = NULL; P_TagFinished(door->sector->tag); P_RemoveThinker(&door->thinker); // unlink and free break; case DREV_CLOSE30THENOPEN: door->direction = 0; door->topcountdown = 35 * 30; break; default: break; } } else if (res == RES_CRUSHED) { switch (door->type) { case DREV_CLOSE: // DON'T GO BACK UP! break; default: door->direction = 1; break; } } break; case 1: // UP res = T_MovePlane(door->sector, door->speed, door->topheight, false, 1, door->direction); if (res == RES_PASTDEST) { SN_StopSequence((mobj_t *) & door->sector->soundorg); switch (door->type) { case DREV_NORMAL: door->direction = 0; // wait at top door->topcountdown = door->topwait; break; case DREV_CLOSE30THENOPEN: case DREV_OPEN: door->sector->specialdata = NULL; P_TagFinished(door->sector->tag); P_RemoveThinker(&door->thinker); // unlink and free break; default: break; } } break; } }
void DDoor::DoorSound(bool raise, DSeqNode *curseq) const { int choice; // For multiple-selection sound sequences, the following choices are used: // 0 Opening // 1 Closing // 2 Opening fast // 3 Closing fast choice = !raise; if (m_Speed >= FRACUNIT*8) { choice += 2; } if (m_Sector->seqType >= 0) { if (curseq == NULL || !SN_AreModesSame(m_Sector->seqType, SEQ_DOOR, choice, curseq->GetModeNum())) { SN_StartSequence(m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_DOOR, choice); } } else if (m_Sector->SeqName != NAME_None) { if (curseq == NULL || !SN_AreModesSame(m_Sector->SeqName, choice, curseq->GetModeNum())) { SN_StartSequence(m_Sector, CHAN_CEILING, m_Sector->SeqName, choice); } } else { const char *snd; switch (gameinfo.gametype) { default: /* Doom and Hexen */ snd = "DoorNormal"; break; case GAME_Heretic: snd = "HereticDoor"; break; case GAME_Strife: snd = "DoorSmallMetal"; // Search the front top textures of 2-sided lines on the door sector // for a door sound to use. for (int i = 0; i < m_Sector->linecount; ++i) { const char *texname; line_t *line = m_Sector->lines[i]; if (line->backsector == NULL) continue; FTexture *tex = TexMan[line->sidedef[0]->GetTexture(side_t::top)]; texname = tex ? tex->Name.GetChars() : NULL; if (texname != NULL && texname[0] == 'D' && texname[1] == 'O' && texname[2] == 'R') { switch (texname[3]) { case 'S': snd = "DoorStone"; break; case 'M': if (texname[4] == 'L') { snd = "DoorLargeMetal"; } break; case 'W': if (texname[4] == 'L') { snd = "DoorLargeWood"; } else { snd = "DoorSmallWood"; } break; } } } break; } if (curseq == NULL || !SN_AreModesSame(snd, choice, curseq->GetModeNum())) { SN_StartSequence(m_Sector, CHAN_CEILING, snd, choice); } } }
//================================================================== // // EV_VerticalDoor : open a door manually, no tag value // //================================================================== boolean EV_VerticalDoor(line_t * line, mobj_t * thing) { sector_t *sec; vldoor_t *door; int side; side = 0; // only front sides can be used // if the sector has an active thinker, use it sec = sides[line->sidenum[side ^ 1]].sector; if (sec->specialdata) { return false; /* door = sec->specialdata; switch(line->special) { // only for raise doors case 12: if(door->direction == -1) { door->direction = 1; // go back up } else { if(!thing->player) { // Monsters don't close doors return; } door->direction = -1; // start going down immediately } return; } */ } // // new door thinker // door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 1; switch (line->special) { case 11: door->type = DREV_OPEN; line->special = 0; break; case 12: case 13: door->type = DREV_NORMAL; break; default: door->type = DREV_NORMAL; break; } door->speed = line->arg2 * (FRACUNIT / 8); door->topwait = line->arg3; // // find the top and bottom of the movement range // door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; SN_StartSequence((mobj_t *) & door->sector->soundorg, SEQ_DOOR_STONE + door->sector->seqType); return true; }
void DPlat::Tick () { EMoveResult res; switch (m_Status) { case up: res = m_Sector->MoveFloor (m_Speed, m_High, m_Crush, 1, false); if (res == EMoveResult::crushed && (m_Crush == -1)) { m_Count = m_Wait; m_Status = down; PlayPlatSound ("Platform"); } else if (res == EMoveResult::pastdest) { SN_StopSequence (m_Sector, CHAN_FLOOR); if (m_Type != platToggle) { m_Count = m_Wait; m_Status = waiting; switch (m_Type) { case platRaiseAndStayLockout: // Instead of keeping the dead thinker like Heretic did let's // better use a flag to avoid problems elsewhere. For example, // keeping the thinker would make tagwait wait indefinitely. m_Sector->planes[sector_t::floor].Flags |= PLANEF_BLOCKED; case platRaiseAndStay: case platDownByValue: case platDownWaitUpStay: case platDownWaitUpStayStone: case platUpByValueStay: case platDownToNearestFloor: case platDownToLowestCeiling: Destroy (); break; default: break; } } else { m_OldStatus = m_Status; //jff 3/14/98 after action wait m_Status = in_stasis; //for reactivation of toggle } } break; case down: res = m_Sector->MoveFloor (m_Speed, m_Low, -1, -1, false); if (res == EMoveResult::pastdest) { SN_StopSequence (m_Sector, CHAN_FLOOR); // if not an instant toggle, start waiting if (m_Type != platToggle) //jff 3/14/98 toggle up down { // is silent, instant, no waiting m_Count = m_Wait; m_Status = waiting; switch (m_Type) { case platUpWaitDownStay: case platUpNearestWaitDownStay: case platUpByValue: Destroy (); break; default: break; } } else { // instant toggles go into stasis awaiting next activation m_OldStatus = m_Status; //jff 3/14/98 after action wait m_Status = in_stasis; //for reactivation of toggle } } else if (res == EMoveResult::crushed && m_Crush < 0 && m_Type != platToggle) { m_Status = up; m_Count = m_Wait; PlayPlatSound ("Platform"); } //jff 1/26/98 remove the plat if it bounced so it can be tried again //only affects plats that raise and bounce // remove the plat if it's a pure raise type switch (m_Type) { case platUpByValueStay: case platRaiseAndStay: case platRaiseAndStayLockout: Destroy (); default: break; } break; case waiting: if (m_Count > 0 && !--m_Count) { if (m_Sector->floorplane.fD() == m_Low) m_Status = up; else m_Status = down; if (m_Type == platToggle) SN_StartSequence (m_Sector, CHAN_FLOOR, "Silence", 0); else PlayPlatSound ("Platform"); } break; case in_stasis: break; } }
bool FLevelLocals::EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height, double speed, int delay, int lip, int change) { DPlat *plat; int secnum; sector_t *sec; bool rtn = false; bool manual = false; double newheight = 0; vertex_t *spot; if (tag != 0) { // Activate all <type> plats that are in_stasis switch (type) { case DPlat::platToggle: rtn = true; case DPlat::platPerpetualRaise: ActivateInStasisPlat (tag); break; default: break; } } // [RH] If tag is zero, use the sector on the back side // of the activating line (if any). auto itr = GetSectorTagIterator(tag, line); while ((secnum = itr.Next()) >= 0) { sec = §ors[secnum]; if (sec->PlaneMoving(sector_t::floor)) { continue; } // Find lowest & highest floors around sector rtn = true; plat = CreateThinker<DPlat> (sec); plat->m_Type = type; plat->m_Crush = -1; plat->m_Tag = tag; plat->m_Speed = speed; plat->m_Wait = delay; //jff 1/26/98 Avoid raise plat bouncing a head off a ceiling and then //going down forever -- default lower to plat height when triggered plat->m_Low = sec->floorplane.fD(); if (change) { if (line) sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor)); if (change == 1) sec->ClearSpecial(); } switch (type) { case DPlat::platRaiseAndStay: case DPlat::platRaiseAndStayLockout: newheight = FindNextHighestFloor (sec, &spot); plat->m_High = sec->floorplane.PointToDist (spot, newheight); plat->m_Low = sec->floorplane.fD(); plat->m_Status = DPlat::up; plat->PlayPlatSound ("Floor"); sec->ClearSpecial(); break; case DPlat::platUpByValue: case DPlat::platUpByValueStay: newheight = sec->floorplane.ZatPoint (sec->centerspot) + height; plat->m_High = sec->floorplane.PointToDist (sec->centerspot, newheight); plat->m_Low = sec->floorplane.fD(); plat->m_Status = DPlat::up; plat->PlayPlatSound ("Floor"); break; case DPlat::platDownByValue: newheight = sec->floorplane.ZatPoint (sec->centerspot) - height; plat->m_Low = sec->floorplane.PointToDist (sec->centerspot, newheight); plat->m_High = sec->floorplane.fD(); plat->m_Status = DPlat::down; plat->PlayPlatSound ("Floor"); break; case DPlat::platDownWaitUpStay: case DPlat::platDownWaitUpStayStone: newheight = FindLowestFloorSurrounding (sec, &spot) + lip; plat->m_Low = sec->floorplane.PointToDist (spot, newheight); if (plat->m_Low < sec->floorplane.fD()) plat->m_Low = sec->floorplane.fD(); plat->m_High = sec->floorplane.fD(); plat->m_Status = DPlat::down; plat->PlayPlatSound (type == DPlat::platDownWaitUpStay ? "Platform" : "Floor"); break; case DPlat::platUpNearestWaitDownStay: newheight = FindNextHighestFloor (sec, &spot); // Intentional fall-through case DPlat::platUpWaitDownStay: if (type == DPlat::platUpWaitDownStay) { newheight = FindHighestFloorSurrounding (sec, &spot); } plat->m_High = sec->floorplane.PointToDist (spot, newheight); plat->m_Low = sec->floorplane.fD(); if (plat->m_High > sec->floorplane.fD()) plat->m_High = sec->floorplane.fD(); plat->m_Status = DPlat::up; plat->PlayPlatSound ("Platform"); break; case DPlat::platPerpetualRaise: newheight = FindLowestFloorSurrounding (sec, &spot) + lip; plat->m_Low = sec->floorplane.PointToDist (spot, newheight); if (plat->m_Low < sec->floorplane.fD()) plat->m_Low = sec->floorplane.fD(); newheight = FindHighestFloorSurrounding (sec, &spot); plat->m_High = sec->floorplane.PointToDist (spot, newheight); if (plat->m_High > sec->floorplane.fD()) plat->m_High = sec->floorplane.fD(); plat->m_Status = pr_doplat() & 1 ? DPlat::up : DPlat::down; plat->PlayPlatSound ("Platform"); break; case DPlat::platToggle: //jff 3/14/98 add new type to support instant toggle plat->m_Crush = 10; //jff 3/14/98 crush anything in the way // set up toggling between ceiling, floor inclusive newheight = FindLowestCeilingPoint(sec, &spot); plat->m_Low = sec->floorplane.PointToDist (spot, newheight); plat->m_High = sec->floorplane.fD(); plat->m_Status = DPlat::down; SN_StartSequence (sec, CHAN_FLOOR, "Silence", 0); break; case DPlat::platDownToNearestFloor: newheight = FindNextLowestFloor (sec, &spot) + lip; plat->m_Low = sec->floorplane.PointToDist (spot, newheight); plat->m_Status = DPlat::down; plat->m_High = sec->floorplane.fD(); plat->PlayPlatSound ("Platform"); break; case DPlat::platDownToLowestCeiling: newheight = FindLowestCeilingSurrounding (sec, &spot); plat->m_Low = sec->floorplane.PointToDist (spot, newheight); plat->m_High = sec->floorplane.fD(); if (plat->m_Low < sec->floorplane.fD()) plat->m_Low = sec->floorplane.fD(); plat->m_Status = DPlat::down; plat->PlayPlatSound ("Platform"); break; default: break; } } return rtn; }
//================================================================== // // EV_DoCeiling // Move a ceiling up/down and all around! // //================================================================== int EV_DoCeiling(line_t *line, byte *arg, ceiling_e type) { int secnum, rtn; sector_t *sec; ceiling_t *ceiling; secnum = -1; rtn = 0; /* Old Ceiling stasis code // // Reactivate in-stasis ceilings...for certain types. // switch(type) { case CLEV_CRUSHANDRAISE: P_ActivateInStasisCeiling(line); default: break; } */ while((secnum = P_FindSectorFromTag(arg[0], secnum)) >= 0) { sec = §ors[secnum]; if(sec->specialdata) continue; // // new door thinker // rtn = 1; ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVSPEC, 0); P_AddThinker(&ceiling->thinker); sec->specialdata = ceiling; ceiling->thinker.function = T_MoveCeiling; ceiling->sector = sec; ceiling->crush = 0; ceiling->speed = arg[1] * (FRACUNIT / 8); switch (type) { case CLEV_CRUSHRAISEANDSTAY: ceiling->crush = arg[2]; // arg[2] = crushing value ceiling->topheight = sec->ceilingheight; ceiling->bottomheight = sec->floorheight + (8 * FRACUNIT); ceiling->direction = -1; break; case CLEV_CRUSHANDRAISE: ceiling->topheight = sec->ceilingheight; case CLEV_LOWERANDCRUSH: ceiling->crush = arg[2]; // arg[2] = crushing value case CLEV_LOWERTOFLOOR: ceiling->bottomheight = sec->floorheight; if(type != CLEV_LOWERTOFLOOR) { ceiling->bottomheight += 8 * FRACUNIT; } ceiling->direction = -1; break; case CLEV_RAISETOHIGHEST: ceiling->topheight = P_FindHighestCeilingSurrounding(sec); ceiling->direction = 1; break; case CLEV_LOWERBYVALUE: ceiling->bottomheight = sec->ceilingheight - arg[2] * FRACUNIT; ceiling->direction = -1; break; case CLEV_RAISEBYVALUE: ceiling->topheight = sec->ceilingheight + arg[2] * FRACUNIT; ceiling->direction = 1; break; case CLEV_MOVETOVALUETIMES8: { int destHeight = arg[2] * FRACUNIT * 8; if(arg[3]) { destHeight = -destHeight; } if(sec->ceilingheight <= destHeight) { ceiling->direction = 1; ceiling->topheight = destHeight; if(sec->ceilingheight == destHeight) { rtn = 0; } } else if(sec->ceilingheight > destHeight) { ceiling->direction = -1; ceiling->bottomheight = destHeight; } break; } default: rtn = 0; break; } ceiling->tag = sec->tag; ceiling->type = type; P_AddActiveCeiling(ceiling); if(rtn) { SN_StartSequence((mobj_t *) &ceiling->sector->soundorg, SEQ_PLATFORM + ceiling->sector->seqType); } } return rtn; }
void ASoundSequence::Activate (AActor *activator) { SN_StartSequence (this, args[0], SEQ_ENVIRONMENT, args[1]); }