boolean P_ActivateLine(line_t *line, mobj_t *mo, int side, int activationType) { int lineActivation; boolean repeat; boolean buttonSuccess; lineActivation = GET_SPAC(line->flags); if(lineActivation != activationType) { return false; } if(!mo->player && !(mo->flags & MF_MISSILE)) { if(lineActivation != SPAC_MCROSS) { // currently, monsters can only activate the MCROSS activation type return false; } if(line->flags & ML_SECRET) return false; // never open secret doors } repeat = line->flags & ML_REPEAT_SPECIAL; buttonSuccess = false; buttonSuccess = P_ExecuteLineSpecial(line->special, &line->arg1, line, side, mo); if(!repeat && buttonSuccess) { // clear the special on non-retriggerable lines line->special = 0; } if((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT) && buttonSuccess) { P_ChangeSwitchTexture(line, repeat); } return true; }
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld) { unsigned short special = (unsigned short) LittleShort(mld->special); short tag = LittleShort(mld->tag); DWORD flags = LittleShort(mld->flags); INTBOOL passthrough = 0; DWORD flags1 = flags; DWORD newflags = 0; for(int i=0;i<16;i++) { if ((flags & (1<<i)) && LineFlagTranslations[i].ismask) { flags1 &= LineFlagTranslations[i].newvalue; } } for(int i=0;i<16;i++) { if ((flags1 & (1<<i)) && !LineFlagTranslations[i].ismask) { switch (LineFlagTranslations[i].newvalue) { case -1: passthrough = true; break; case -2: ld->Alpha = FRACUNIT*3/4; break; default: newflags |= LineFlagTranslations[i].newvalue; break; } } } flags = newflags; // For purposes of maintaining BOOM compatibility, each // line also needs to have its ID set to the same as its tag. // An external conversion program would need to do this more // intelligently. ld->id = tag; // 0 specials are never translated. if (special == 0) { ld->special = 0; ld->flags = flags; ld->args[0] = mld->tag; memset (ld->args+1, 0, sizeof(ld->args)-sizeof(ld->args[0])); return; } FLineTrans *linetrans = NULL; if (special < SimpleLineTranslations.Size()) linetrans = &SimpleLineTranslations[special]; if (linetrans != NULL && linetrans->special != 0) { ld->special = linetrans->special; ld->flags = flags | ((linetrans->flags & 0x1f) << 9); if (linetrans->flags & 0x20) ld->flags |= ML_FIRSTSIDEONLY; ld->activation = 1 << GET_SPAC(ld->flags); if (ld->activation == SPAC_AnyCross) { // this is really PTouch ld->activation = SPAC_Impact|SPAC_PCross; } else if (ld->activation == SPAC_Impact) { // In non-UMDF maps, Impact implies PCross ld->activation = SPAC_Impact | SPAC_PCross; } ld->flags &= ~ML_SPAC_MASK; if (passthrough && ld->activation == SPAC_Use) { ld->activation = SPAC_UseThrough; } // Set special arguments. FXlatExprState state; state.tag = tag; state.linetype = special; for (int t = 0; t < LINETRANS_MAXARGS; ++t) { int arg = linetrans->args[t]; int argop = (linetrans->flags >> (LINETRANS_TAGSHIFT + t*TAGOP_NUMBITS)) & TAGOP_MASK; switch (argop) { case ARGOP_Const: ld->args[t] = arg; break; case ARGOP_Tag: ld->args[t] = tag; break; case ARGOP_Expr: { int *xnode = &XlatExpressions[arg]; state.bIsConstant = true; XlatExprEval[*xnode](&ld->args[t], xnode, &state); } break; default: assert(0); ld->args[t] = 0; break; } } if ((ld->flags & ML_SECRET) && ld->activation & (SPAC_Use|SPAC_UseThrough)) { ld->flags &= ~ML_MONSTERSCANACTIVATE; } return; }
BOOL EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, int tag, int speed, int delay, card_t lock) { BOOL rtn = false; int secnum; sector_t* sec; DDoor *door; if (lock && thing && !P_CheckKeys (thing->player, lock, tag)) return false; if (tag == 0) { // [RH] manual door if (!line) return false; // if the wrong side of door is pushed, give oof sound if (line->sidenum[1]==R_NOSIDE) // killough { UV_SoundAvoidPlayer (thing, CHAN_VOICE, "player/male/grunt1", ATTN_NORM); return false; } // get the sector on the second side of activating linedef sec = sides[line->sidenum[1]].sector; secnum = sec-sectors; if (sec->ceilingdata && P_MovingCeilingCompleted(sec)) { sec->ceilingdata->Destroy(); sec->ceilingdata = NULL; } // if door already has a thinker, use it door = static_cast<DDoor *>(sec->ceilingdata); // cph 2001/04/05 - // Original Doom didn't distinguish floor/lighting/ceiling // actions, so we need to do the same in demo compatibility mode. // [SL] 2011-06-20 - Credit to PrBoom for the fix if (!door) door = static_cast<DDoor *>(sec->floordata); if (!door) door = static_cast<DDoor *>(sec->lightingdata); if (door) { // ONLY FOR "RAISE" DOORS, NOT "OPEN"s if (door->m_Type == DDoor::doorRaise && type == DDoor::doorRaise) { if (sec->ceilingdata && sec->ceilingdata->IsKindOf (RUNTIME_CLASS(DDoor))) { if (door->m_Status == DDoor::closing) { // go back up door->m_Status = DDoor::reopening; return true; } else if (GET_SPAC(line->flags) == SPAC_PUSH) { // [RH] activate push doors don't go back down when you // run into them (otherwise opening them would be // a real pain). door->m_Line = line; return true; } else if (thing && thing->player) { // go back down door->m_Status = DDoor::closing; return true; } } return false; } } else { door = new DDoor(sec, line, type, speed, delay); P_AddMovingCeiling(sec); } if (door) { rtn = true; } } else { // [RH] Remote door secnum = -1; while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0) { sec = §ors[secnum]; // if the ceiling already moving, don't start the door action if (sec->ceilingdata) continue; door = new DDoor(sec, line, type, speed, delay); P_AddMovingCeiling(sec); if (door) rtn = true; } } return rtn; }
BOOL EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, int tag, int speed, int delay, card_t lock) { BOOL rtn = false; int secnum; sector_t* sec; DDoor *door; if (lock && thing && !P_CheckKeys (thing->player, lock, tag)) return false; if (tag == 0) { // [RH] manual door if (!line) return false; // if the wrong side of door is pushed, give oof sound if (line->sidenum[1]==-1) // killough { UV_SoundAvoidPlayer (thing, CHAN_VOICE, "player/male/grunt1", ATTN_NORM); return false; } // get the sector on the second side of activating linedef sec = sides[line->sidenum[1]].sector; secnum = sec-sectors; // if door already has a thinker, use it if (sec->ceilingdata && sec->ceilingdata->IsKindOf (RUNTIME_CLASS(DDoor))) { door = static_cast<DDoor *>(sec->ceilingdata); door->m_Line = line; // ONLY FOR "RAISE" DOORS, NOT "OPEN"s if (door->m_Type == DDoor::doorRaise && type == DDoor::doorRaise) { if (door->m_Direction == -1) { door->m_Direction = 1; // go back up } else if (GET_SPAC(line->flags) != SPAC_PUSH) // [RH] activate push doors don't go back down when you // run into them (otherwise opening them would be // a real pain). { if (thing && !thing->player) return false; // JDC: bad guys never close doors // From Chocolate Doom: // When is a door not a door? // In Vanilla, door->direction is set, even though // "specialdata" might not actually point at a door. else if (sec->floordata && sec->floordata->IsKindOf (RUNTIME_CLASS(DPlat))) { // Erm, this is a plat, not a door. // This notably causes a problem in ep1-0500.lmp where // a plat and a door are cross-referenced; the door // doesn't open on 64-bit. // The direction field in vldoor_t corresponds to the wait // field in plat_t. Let's set that to -1 instead. DPlat *plat = static_cast<DPlat *>(sec->floordata); byte state; int count; plat->GetState(state, count); if (count >= 16) // ep1-0500 always returns a count of 16. return false; // We may be able to always return false? } else { door->m_Direction = -1; // try going back down anyway? } } return true; } } else { door = new DDoor(sec, line, type, speed, delay); } if (door) { rtn = true; } } else { // [RH] Remote door secnum = -1; while ((secnum = P_FindSectorFromTag (tag,secnum)) >= 0) { sec = §ors[secnum]; // if the ceiling already moving, don't start the door action if (sec->ceilingdata) continue; if (new DDoor (sec, line, type, speed, delay)) rtn = true; } } return rtn; }
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld) { short special = LESHORT(mld->special); short tag = LESHORT(mld->tag); short flags = LESHORT(mld->flags); bool passthrough = (flags & ML_PASSUSE_BOOM); int i; flags &= 0x01ff; // Ignore flags unknown to DOOM if (special <= NUM_SPECIALS) { // This is a regular special; translate thru LUT flags = flags | (SpecialTranslation[special].flags << 8); if (passthrough) { if (GET_SPAC(flags) == SPAC_USE) { flags &= ~ML_SPAC_MASK; flags |= SPAC_USETHROUGH << ML_SPAC_SHIFT; } if (GET_SPAC(flags) == SPAC_CROSS) { flags &= ~ML_SPAC_MASK; flags |= SPAC_CROSSTHROUGH << ML_SPAC_SHIFT; } // TODO: what to do with gun-activated lines with passthrough? } ld->special = SpecialTranslation[special].newspecial; for (i = 0; i < 5; i++) ld->args[i] = SpecialTranslation[special].args[i] == TAG ? tag : SpecialTranslation[special].args[i]; } else if (special == 337) { ld->special = Line_Horizon; ld->flags = flags; ld->id = tag; memset(ld->args, 0, sizeof(ld->args)); } else if (special >= 340 && special <= 347) { // [SL] 2012-01-30 - convert to ZDoom Plane_Align special for // sloping sectors ld->special = Plane_Align; ld->flags = flags; ld->id = tag; memset(ld->args, 0, sizeof(ld->args)); switch (special) { case 340: // Slope the Floor in front of the line ld->args[0] = 1; break; case 341: // Slope the Ceiling in front of the line ld->args[1] = 1; break; case 342: // Slope the Floor+Ceiling in front of the line ld->args[0] = ld->args[1] = 1; break; case 343: // Slope the Floor behind the line ld->args[0] = 2; break; case 344: // Slope the Ceiling behind the line ld->args[1] = 2; break; case 345: // Slope the Floor+Ceiling behind the line ld->args[0] = ld->args[1] = 2; break; case 346: // Slope the Floor behind+Ceiling in front of the line ld->args[0] = 2; ld->args[1] = 1; break; case 347: // Slope the Floor in front+Ceiling behind the line ld->args[0] = 1; ld->args[1] = 2; } } else if (special <= GenCrusherBase) { if (special >= OdamexStaticInits && special < OdamexStaticInits + NUM_STATIC_INITS) { // An Odamex Static_Init special ld->special = Static_Init; ld->args[0] = tag; ld->args[1] = special - OdamexStaticInits; } else { // This is an unknown special. Just zero it. ld->special = 0; memset (ld->args, 0, sizeof(ld->args)); } } else { // Anything else is a BOOM generalized linedef type switch (special & 0x0007) { case WalkMany: flags |= ML_REPEAT_SPECIAL; case WalkOnce: if (passthrough) flags |= SPAC_CROSSTHROUGH << ML_SPAC_SHIFT; else flags |= SPAC_CROSS << ML_SPAC_SHIFT; break; case SwitchMany: case PushMany: flags |= ML_REPEAT_SPECIAL; case SwitchOnce: case PushOnce: if (passthrough) flags |= SPAC_USETHROUGH << ML_SPAC_SHIFT; else flags |= SPAC_USE << ML_SPAC_SHIFT; break; case GunMany: flags |= ML_REPEAT_SPECIAL; case GunOnce: flags |= SPAC_IMPACT << ML_SPAC_SHIFT; break; } // We treat push triggers like switch triggers with zero tags. if ((special & 0x0007) == PushMany || (special & 0x0007) == PushOnce) ld->args[0] = 0; else ld->args[0] = tag; if (special <= GenStairsBase) { // Generalized crusher (tag, dnspeed, upspeed, silent, damage) ld->special = Generic_Crusher; if (special & 0x0020) flags |= ML_MONSTERSCANACTIVATE; switch (special & 0x0018) { case 0x0000: ld->args[1] = C_SLOW; break; case 0x0008: ld->args[1] = C_NORMAL; break; case 0x0010: ld->args[1] = C_FAST; break; case 0x0018: ld->args[1] = C_TURBO; break; } ld->args[2] = ld->args[1]; ld->args[3] = (special & 0x0040) >> 6; ld->args[4] = 10; } else if (special <= GenLiftBase)