/* * ===================== * = * = P_CheckSight * = * = Returns true if a straight line between t1 and t2 is unobstructed * = look from eyes of t1 to any part of t2 * = * ===================== */ public static bool P_CheckSight(DoomDef.mobj_t t1, DoomDef.mobj_t t2) { int s1, s2; int pnum, bytenum, bitnum; // // check for trivial rejection // s1 = Array.IndexOf(p_setup.sectors, t1.subsector.sector); s2 = Array.IndexOf(p_setup.sectors, t2.subsector.sector); pnum = s1 * p_setup.numsectors + s2; bytenum = pnum >> 3; bitnum = 1 << (pnum & 7); if ((p_setup.rejectmatrix[bytenum] & bitnum) != 0) { sightcounts[0]++; return(false); // can't possibly be connected } // // check precisely // sightzstart = t1.z + t1.height - (t1.height >> 2); topslope = (t2.z + t2.height) - sightzstart; bottomslope = (t2.z) - sightzstart; return(P_SightPathTraverse(t1.x, t1.y, t2.x, t2.y)); }
public void reset() { mo = null; sound_id = 0; handle = 0; pitch = 0; priority = 0; }
/* * =================== * = * = P_SetThingPosition * = * = Links a thing into both a block and a subsector based on it's x y * = Sets thing.subsector properly * = * =================== */ public static void P_SetThingPosition(DoomDef.mobj_t thing) { r_local.subsector_t ss; r_local.sector_t sec; int blockx, blocky; DoomDef.mobj_t link; int linki; // // link into subsector // ss = r_main.R_PointInSubsector(thing.x, thing.y); thing.subsector = ss; if ((thing.flags & DoomDef.MF_NOSECTOR) == 0) { // invisible things don't go into the sector links sec = ss.sector; thing.sprev = null; thing.snext = sec.thinglist; if (sec.thinglist != null) { sec.thinglist.sprev = thing; } sec.thinglist = thing; } // // link into blockmap // if ((thing.flags & DoomDef.MF_NOBLOCKMAP) == 0) { // inert things don't need to be in blockmap blockx = (thing.x - p_setup.bmaporgx) >> p_local.MAPBLOCKSHIFT; blocky = (thing.y - p_setup.bmaporgy) >> p_local.MAPBLOCKSHIFT; if (blockx >= 0 && blockx < p_setup.bmapwidth && blocky >= 0 && blocky < p_setup.bmapheight) { linki = blocky * p_setup.bmapwidth + blockx; link = p_setup.blocklinks[linki]; thing.bprev = null; thing.bnext = link; if (link != null) { link.bprev = thing; } p_setup.blocklinks[linki] = thing; } else { // thing is off the map thing.bnext = thing.bprev = null; } } }
public override bool func(DoomDef.mobj_t thing) { int x1, y1, x2, y2; int s1, s2; bool tracepositive; p_local.divline_t dl = new p_local.divline_t(); int frac; tracepositive = (trace.dx ^ trace.dy) > 0; // check a corner to corner crossection for hit if (tracepositive) { x1 = thing.x - thing.radius; y1 = thing.y + thing.radius; x2 = thing.x + thing.radius; y2 = thing.y - thing.radius; } else { x1 = thing.x - thing.radius; y1 = thing.y - thing.radius; x2 = thing.x + thing.radius; y2 = thing.y + thing.radius; } s1 = p_maputl.P_PointOnDivlineSide(x1, y1, trace); s2 = p_maputl.P_PointOnDivlineSide(x2, y2, trace); if (s1 == s2) { return(true); // line isn't crossed } dl.x = x1; dl.y = y1; dl.dx = x2 - x1; dl.dy = y2 - y1; frac = P_InterceptVector(trace, dl); if (frac < 0) { return(true); // behind source } intercepts[intercept_p].frac = frac; intercepts[intercept_p].isaline = false; intercepts[intercept_p].thing = thing; intercept_p++; return(true); // keep going }
private void chkCastShadow_CheckedChanged(object sender, EventArgs e) { info.mobjinfo_t mobT = getMoType(); if (mobT == null) { return; } if (mobT.light == null) { return; } mobT.light.castShadow = chkCastShadow.Checked; mobT.light.makeColor(); Game1.instance.NeedSave = true; DoomDef.mobj_t selectedMo = Game1.instance.selectedMob.Target as DoomDef.mobj_t; if (selectedMo == null) { return; } for (DoomDef.thinker_t think = p_tick.thinkercap.next; think != p_tick.thinkercap; think = think.next) { if (think == null) { break; } if (think.function == null) { continue; } DoomDef.mobj_t mo = think.function.obj as DoomDef.mobj_t; if (mo == null) { continue; } if (mo.shadowInfo == null) { continue; } if (mo.type != selectedMo.type) { continue; } if (!mobT.light.castShadow) { mo.shadowInfo.Dispose(); mo.shadowInfo = null; } } }
private void sldRadius_Scroll(object sender, EventArgs e) { info.mobjinfo_t mobT = getMoType(); if (mobT == null) { return; } if (mobT.light == null) { return; } mobT.light.radius = (float)sldRadius.Value; mobT.light.makeColor(); Game1.instance.NeedSave = true; DoomDef.mobj_t selectedMo = Game1.instance.selectedMob.Target as DoomDef.mobj_t; if (selectedMo == null) { return; } for (DoomDef.thinker_t think = p_tick.thinkercap.next; think != p_tick.thinkercap; think = think.next) { if (think == null) { break; } if (think.function == null) { continue; } DoomDef.mobj_t mo = think.function.obj as DoomDef.mobj_t; if (mo == null) { continue; } if (mo.shadowInfo == null) { continue; } if (mo.type != selectedMo.type) { continue; } mo.shadowInfo.needUpdate = true; } }
//---------------------------------------------------------------------------- // // FUNC EV_Teleport // //---------------------------------------------------------------------------- public static bool EV_Teleport(r_local.line_t line, int side, DoomDef.mobj_t thing) { int i; int tag; DoomDef.mobj_t m; DoomDef.thinker_t thinker; r_local.sector_t sector; if ((thing.flags2 & DoomDef.MF2_NOTELEPORT) != 0) { return(false); } if (side == 1) { // Don't teleport when crossing back side return(false); } tag = line.tag; for (i = 0; i < p_setup.numsectors; i++) { if (p_setup.sectors[i].tag == tag) { thinker = p_tick.thinkercap.next; for (thinker = p_tick.thinkercap.next; thinker != p_tick.thinkercap; thinker = thinker.next) { if (!(thinker.function is p_mobj.P_MobjThinker)) { // Not a mobj continue; } m = thinker.function.obj as DoomDef.mobj_t; if (m.type != info.mobjtype_t.MT_TELEPORTMAN) { // Not a teleportman continue; } sector = m.subsector.sector; if (Array.IndexOf(p_setup.sectors, sector) != i) { // Wrong sector continue; } return(P_Teleport(thing, m.x, m.y, m.angle)); } } } return(false); }
internal void fillUIWithMob(DoomDef.mobj_t mo) { lblMobType.Text = mo.type.ToString(); int lump; r_local.spritedef_t sprdef; r_local.spriteframe_t sprframe; info.mobjinfo_t mobT = info.mobjinfo[(int)mo.type]; sprdef = r_thing.sprites[(int)mo.sprite]; sprframe = sprdef.spriteframes[mo.frame & DoomDef.FF_FRAMEMASK]; lump = sprframe.lump[0]; Microsoft.Xna.Framework.Graphics.Texture2D texture = w_wad.W_CacheLumpNum(lump + r_data.firstspritelump, DoomDef.PU_CACHE).cache as Microsoft.Xna.Framework.Graphics.Texture2D; byte[] pixels = new byte[texture.Width * texture.Height * 4]; texture.GetData <byte>(pixels); for (int i = 0; i < texture.Width * texture.Height; ++i) { byte tmp = pixels[i * 4 + 0]; pixels[i * 4 + 0] = pixels[i * 4 + 2]; pixels[i * 4 + 2] = tmp; } Bitmap bmp = new Bitmap(texture.Width, texture.Height, texture.Width * 4, PixelFormat.Format32bppArgb, GCHandle.Alloc(pixels, GCHandleType.Pinned).AddrOfPinnedObject()); picMobSprite.Image = bmp; if (mobT.light == null) { btnRemoveColor.Text = "Add Light"; } else { btnRemoveColor.Text = "Remove Light"; sldRadius.Value = (int)mobT.light.radius; sldHue.Value = mobT.light.hue; sldSaturation.Value = mobT.light.saturation; txtMultiplier.Text = mobT.light.brightness.ToString(); chkCastShadow.Checked = mobT.light.castShadow; cboLightType.SelectedIndex = mobT.light.type; } sldBottomIllumination.Value = (int)(mobT.selfIllumB * 100.0f); sldTopIllumination.Value = (int)(mobT.selfIllumT * 100.0f); }
/* * =============================================================================== * * THING POSITION SETTING * * =============================================================================== */ /* * =================== * = * = P_UnsetThingPosition * = * = Unlinks a thing from block map and sectors * = * =================== */ public static void P_UnsetThingPosition(DoomDef.mobj_t thing) { int blockx, blocky; if ((thing.flags & DoomDef.MF_NOSECTOR) == 0) { // inert things don't need to be in blockmap // unlink from subsector if (thing.snext != null) { thing.snext.sprev = thing.sprev; } if (thing.sprev != null) { thing.sprev.snext = thing.snext; } else { thing.subsector.sector.thinglist = thing.snext; } } if ((thing.flags & DoomDef.MF_NOBLOCKMAP) == 0) { // inert things don't need to be in blockmap // unlink from block map if (thing.bnext != null) { thing.bnext.bprev = thing.bprev; } if (thing.bprev != null) { thing.bprev.bnext = thing.bnext; } else { blockx = (thing.x - p_setup.bmaporgx) >> p_local.MAPBLOCKSHIFT; blocky = (thing.y - p_setup.bmaporgy) >> p_local.MAPBLOCKSHIFT; if (blockx >= 0 && blockx < p_setup.bmapwidth && blocky >= 0 && blocky < p_setup.bmapheight) { p_setup.blocklinks[blocky * p_setup.bmapwidth + blockx] = thing.bnext; } } } }
public virtual bool func(DoomDef.mobj_t mob) { return(false); }
public void invalidate(bool doNeighbors) { needUpdateAmbientMap = true; if (floorBatch != null) { floorBatch.vb.Dispose(); floorBatch = null; } if (ceilingBatch != null) { ceilingBatch.vb.Dispose(); ceilingBatch = null; } if (sectorBatches != null) { foreach (SectorBatch batch in sectorBatches) { if (batch.vb != null) { batch.vb.Dispose(); } } sectorBatches = null; } // Invalidate also neiborgh sectors if (doNeighbors) { if (segs != null) { foreach (seg_t seg in segs) { if (seg.backsector != null) { seg.backsector.invalidate(false); } } } // Check for lights that touch that sector, and invalidate their shadow for (DoomDef.thinker_t think = p_tick.thinkercap.next; think != p_tick.thinkercap; think = think.next) { if (think == null) { break; } if (think.function == null) { continue; } DoomDef.mobj_t mo = think.function.obj as DoomDef.mobj_t; if (mo == null) { continue; } if (mo.shadowInfo == null) { continue; } if (mo.sectorsInRadius.Contains(this)) { mo.shadowInfo.needUpdate = true; } } } justInvalidated = true; }
//---------------------------------------------------------------------------- // // FUNC P_Teleport // //---------------------------------------------------------------------------- public static bool P_Teleport(DoomDef.mobj_t thing, int x, int y, uint angle) { int oldx; int oldy; int oldz; int aboveFloor; int fogDelta; DoomDef.player_t player; uint an; DoomDef.mobj_t fog; oldx = thing.x; oldy = thing.y; oldz = thing.z; aboveFloor = thing.z - thing.floorz; if (!p_map.P_TeleportMove(thing, x, y)) { return(false); } if (thing.player != null) { player = thing.player; if (player.powers[(int)DoomDef.powertype_t.pw_flight] != 0 && aboveFloor != 0) { thing.z = thing.floorz + aboveFloor; if (thing.z + thing.height > thing.ceilingz) { thing.z = thing.ceilingz - thing.height; } player.viewz = thing.z + player.viewheight; } else { thing.z = thing.floorz; player.viewz = thing.z + player.viewheight; player.lookdir = 0; } } else if ((thing.flags & DoomDef.MF_MISSILE) != 0) { thing.z = thing.floorz + aboveFloor; if (thing.z + thing.height > thing.ceilingz) { thing.z = thing.ceilingz - thing.height; } } else { thing.z = thing.floorz; } // Spawn teleport fog at source and destination fogDelta = (thing.flags & DoomDef.MF_MISSILE) != 0 ? 0 : DoomDef.TELEFOGHEIGHT; fog = p_mobj.P_SpawnMobj(oldx, oldy, oldz + fogDelta, info.mobjtype_t.MT_TFOG); i_ibm.S_StartSound(fog, (int)sounds.sfxenum_t.sfx_telept); an = angle >> (int)DoomDef.ANGLETOFINESHIFT; fog = p_mobj.P_SpawnMobj(x + 20 * r_main.finecosine(an), y + 20 * tables.finesine[an], thing.z + fogDelta, info.mobjtype_t.MT_TFOG); i_ibm.S_StartSound(fog, (int)sounds.sfxenum_t.sfx_telept); if (thing.player != null && thing.player.powers[(int)DoomDef.powertype_t.pw_weaponlevel2] == 0) { // Freeze player for about .5 sec thing.reactiontime = 18; } thing.angle = angle; if ((thing.flags2 & DoomDef.MF2_FOOTCLIP) != 0 && p_mobj.P_GetThingFloorType(thing) != p_local.FLOOR_SOLID) { thing.flags2 |= DoomDef.MF2_FEETARECLIPPED; } else if ((thing.flags2 & DoomDef.MF2_FEETARECLIPPED) != 0) { thing.flags2 &= ~DoomDef.MF2_FEETARECLIPPED; } if ((thing.flags & DoomDef.MF_MISSILE) != 0) { angle >>= (int)DoomDef.ANGLETOFINESHIFT; thing.momx = DoomDef.FixedMul(thing.infol.speed, r_main.finecosine(angle)); thing.momy = DoomDef.FixedMul(thing.infol.speed, tables.finesine[angle]); } else { thing.momx = thing.momy = thing.momz = 0; } return(true); }
/* * ============================================================================== * = * = P_UseSpecialLine * = * = Called when a thing uses a special line * = Only the front sides of lines are usable * =============================================================================== */ public static bool P_UseSpecialLine(DoomDef.mobj_t thing, r_local.line_t line) { // // Switches that other things can activate // if (thing.player == null) { if ((line.flags & DoomData.ML_SECRET) != 0) { return(false); // never open secret doors } switch (line.special) { case 1: // MANUAL DOOR RAISE case 32: // MANUAL BLUE case 33: // MANUAL RED case 34: // MANUAL YELLOW break; default: return(false); } } // // do something // switch (line.special) { //=============================================== // MANUALS //=============================================== case 1: // Vertical Door case 26: // Blue Door/Locked case 27: // Yellow Door /Locked case 28: // Red Door /Locked case 31: // Manual door open case 32: // Blue locked door open case 33: // Red locked door open case 34: // Yellow locked door open p_doors.EV_VerticalDoor(line, thing); break; //=============================================== // SWITCHES //=============================================== case 7: // Switch_Build_Stairs (8 pixel steps) if (p_floor.EV_BuildStairs(line, 8 * DoomDef.FRACUNIT) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 107: // Switch_Build_Stairs_16 (16 pixel steps) if (p_floor.EV_BuildStairs(line, 16 * DoomDef.FRACUNIT) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 9: // Change Donut //if (EV_DoDonut(line)) // P_ChangeSwitchTexture(line, 0); break; case 11: // Exit level g_game.G_ExitLevel(); P_ChangeSwitchTexture(line, 0); break; case 14: // Raise Floor 32 and change texture if (p_plats.EV_DoPlat(line, p_spec.plattype_e.raiseAndChange, 32) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 15: // Raise Floor 24 and change texture if (p_plats.EV_DoPlat(line, p_spec.plattype_e.raiseAndChange, 24) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 18: // Raise Floor to next highest floor if (p_floor.EV_DoFloor(line, p_spec.floor_e.raiseFloorToNearest) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 20: // Raise Plat next highest floor and change texture if (p_plats.EV_DoPlat(line, p_spec.plattype_e.raiseToNearestAndChange, 0) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 21: // PlatDownWaitUpStay if (p_plats.EV_DoPlat(line, p_spec.plattype_e.downWaitUpStay, 0) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 23: // Lower Floor to Lowest if (p_floor.EV_DoFloor(line, p_spec.floor_e.lowerFloorToLowest) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 29: // Raise Door if (p_doors.EV_DoDoor(line, p_spec.vldoor_e.normal, p_spec.VDOORSPEED) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 41: // Lower Ceiling to Floor if (p_ceilng.EV_DoCeiling(line, p_spec.ceiling_e.lowerToFloor) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 71: // Turbo Lower Floor if (p_floor.EV_DoFloor(line, p_spec.floor_e.turboLower) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 49: // Lower Ceiling And Crush if (p_ceilng.EV_DoCeiling(line, p_spec.ceiling_e.lowerAndCrush) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 50: // Close Door if (p_doors.EV_DoDoor(line, p_spec.vldoor_e.close, p_spec.VDOORSPEED) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 51: // Secret EXIT //G_SecretExitLevel(); //P_ChangeSwitchTexture(line, 0); break; case 55: // Raise Floor Crush if (p_floor.EV_DoFloor(line, p_spec.floor_e.raiseFloorCrush) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 101: // Raise Floor if (p_floor.EV_DoFloor(line, p_spec.floor_e.raiseFloor) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 102: // Lower Floor to Surrounding floor height if (p_floor.EV_DoFloor(line, p_spec.floor_e.lowerFloor) != 0) { P_ChangeSwitchTexture(line, 0); } break; case 103: // Open Door if (p_doors.EV_DoDoor(line, p_spec.vldoor_e.open, p_spec.VDOORSPEED) != 0) { P_ChangeSwitchTexture(line, 0); } break; //=============================================== // BUTTONS //=============================================== case 42: // Close Door if (p_doors.EV_DoDoor(line, p_spec.vldoor_e.close, p_spec.VDOORSPEED) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 43: // Lower Ceiling to Floor if (p_ceilng.EV_DoCeiling(line, p_spec.ceiling_e.lowerToFloor) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 45: // Lower Floor to Surrounding floor height if (p_floor.EV_DoFloor(line, p_spec.floor_e.lowerFloor) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 60: // Lower Floor to Lowest if (p_floor.EV_DoFloor(line, p_spec.floor_e.lowerFloorToLowest) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 61: // Open Door if (p_doors.EV_DoDoor(line, p_spec.vldoor_e.open, p_spec.VDOORSPEED) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 62: // PlatDownWaitUpStay if (p_plats.EV_DoPlat(line, p_spec.plattype_e.downWaitUpStay, 1) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 63: // Raise Door if (p_doors.EV_DoDoor(line, p_spec.vldoor_e.normal, p_spec.VDOORSPEED) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 64: // Raise Floor to ceiling if (p_floor.EV_DoFloor(line, p_spec.floor_e.raiseFloor) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 66: // Raise Floor 24 and change texture if (p_plats.EV_DoPlat(line, p_spec.plattype_e.raiseAndChange, 24) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 67: // Raise Floor 32 and change texture if (p_plats.EV_DoPlat(line, p_spec.plattype_e.raiseAndChange, 32) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 65: // Raise Floor Crush if (p_floor.EV_DoFloor(line, p_spec.floor_e.raiseFloorCrush) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 68: // Raise Plat to next highest floor and change texture if (p_plats.EV_DoPlat(line, p_spec.plattype_e.raiseToNearestAndChange, 0) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 69: // Raise Floor to next highest floor if (p_floor.EV_DoFloor(line, p_spec.floor_e.raiseFloorToNearest) != 0) { P_ChangeSwitchTexture(line, 1); } break; case 70: // Turbo Lower Floor if (p_floor.EV_DoFloor(line, p_spec.floor_e.turboLower) != 0) { P_ChangeSwitchTexture(line, 1); } break; } return(true); }
//================================================================== // // EV_VerticalDoor : open a door manually, no tag value // //================================================================== public static void EV_VerticalDoor(r_local.line_t line, DoomDef.mobj_t thing) { DoomDef.player_t player; int secnum; r_local.sector_t sec; p_spec.vldoor_t door; int side; side = 0; // only front sides can be used // // Check for locks // player = thing.player; switch (line.special) { case 26: // Blue Lock case 32: if (player == null) { return; } if (!player.keys[(int)DoomDef.keytype_t.key_blue]) { p_inter.P_SetMessage(player, dstring.TXT_NEEDBLUEKEY, false); i_ibm.S_StartSound(null, (int)sounds.sfxenum_t.sfx_plroof); return; } break; case 27: // Yellow Lock case 34: if (player == null) { return; } if (!player.keys[(int)DoomDef.keytype_t.key_yellow]) { p_inter.P_SetMessage(player, dstring.TXT_NEEDYELLOWKEY, false); i_ibm.S_StartSound(null, (int)sounds.sfxenum_t.sfx_plroof); return; } break; case 28: // Green Lock case 33: if (player == null) { return; } if (!player.keys[(int)DoomDef.keytype_t.key_green]) { p_inter.P_SetMessage(player, dstring.TXT_NEEDGREENKEY, false); i_ibm.S_StartSound(null, (int)sounds.sfxenum_t.sfx_plroof); return; } break; } // if the sector has an active thinker, use it sec = p_setup.sides[line.sidenum[side ^ 1]].sector; secnum = Array.IndexOf(p_setup.sectors, sec); if (sec.specialdata != null) { door = sec.specialdata as p_spec.vldoor_t; switch (line.special) { case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s case 26: case 27: case 28: if (door.direction == -1) { door.direction = 1; // go back up } else { if (thing.player == null) { // Monsters don't close doors return; } door.direction = -1; // start going down immediately } return; } } // for proper sound switch (line.special) { case 1: // NORMAL DOOR SOUND case 31: i_ibm.S_StartSound( sec.soundorg.x, sec.soundorg.y, sec.soundorg.z, (int)sounds.sfxenum_t.sfx_doropn); break; default: // LOCKED DOOR SOUND i_ibm.S_StartSound( sec.soundorg.x, sec.soundorg.y, sec.soundorg.z, (int)sounds.sfxenum_t.sfx_doropn); break; } // // new door thinker // door = new p_spec.vldoor_t(); p_tick.P_AddThinker(door.thinker); sec.specialdata = door; door.thinker.function = new T_VerticalDoor(door); door.sector = sec; door.direction = 1; switch (line.special) { case 1: case 26: case 27: case 28: door.type = p_spec.vldoor_e.normal; break; case 31: case 32: case 33: case 34: door.type = p_spec.vldoor_e.open; line.special = 0; break; } door.speed = p_spec.VDOORSPEED; door.topwait = p_spec.VDOORWAIT; // // find the top and bottom of the movement range // door.topheight = p_spec.P_FindLowestCeilingSurrounding(sec); door.topheight -= 4 * DoomDef.FRACUNIT; }