diff --git a/src/actionspecials.h b/src/actionspecials.h index 6d9d2feb8..4ab222b2c 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -176,7 +176,7 @@ DEFINE_SPECIAL(Sector_SetCeilingScale, 188, 5, 5, 5) DEFINE_SPECIAL(Sector_SetFloorScale, 189, 5, 5, 5) DEFINE_SPECIAL(Static_Init, 190, -1, -1, 4) DEFINE_SPECIAL(SetPlayerProperty, 191, 3, 3, 3) -DEFINE_SPECIAL(Ceiling_LowerToHighestFloor, 192, 2, 4, 4) +DEFINE_SPECIAL(Ceiling_LowerToHighestFloor, 192, 2, 4, 5) DEFINE_SPECIAL(Ceiling_LowerInstant, 193, 3, 5, 5) DEFINE_SPECIAL(Ceiling_RaiseInstant, 194, 3, 4, 4) DEFINE_SPECIAL(Ceiling_CrushRaiseAndStayA, 195, 4, 5, 5) @@ -222,7 +222,7 @@ DEFINE_SPECIAL(Light_MaxNeighbor, 234, 1, 1, 1) DEFINE_SPECIAL(Floor_TransferTrigger, 235, 1, 1, 1) DEFINE_SPECIAL(Floor_TransferNumeric, 236, 1, 1, 1) DEFINE_SPECIAL(ChangeCamera, 237, 3, 3, 3) -DEFINE_SPECIAL(Floor_RaiseToLowestCeiling, 238, 2, 4, 4) +DEFINE_SPECIAL(Floor_RaiseToLowestCeiling, 238, 2, 4, 5) DEFINE_SPECIAL(Floor_RaiseByValueTxTy, 239, 3, 3, 3) DEFINE_SPECIAL(Floor_RaiseByTexture, 240, 2, 4, 4) DEFINE_SPECIAL(Floor_LowerToLowestTxTy, 241, 2, 2, 2) @@ -238,21 +238,21 @@ DEFINE_SPECIAL(Floor_Donut, 250, 3, 3, 3) DEFINE_SPECIAL(FloorAndCeiling_LowerRaise, 251, 3, 4, 4) DEFINE_SPECIAL(Ceiling_RaiseToNearest, 252, 2, 3, 3) DEFINE_SPECIAL(Ceiling_LowerToLowest, 253, 2, 4, 4) -DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 4, 4) +DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 4, 5) DEFINE_SPECIAL(Ceiling_CrushRaiseAndStaySilA, 255, 4, 5, 5) DEFINE_SPECIAL(Floor_LowerToHighestEE, 256, 2, 3, 3) DEFINE_SPECIAL(Floor_RaiseToLowest, 257, 1, 3, 3) DEFINE_SPECIAL(Floor_LowerToLowestCeiling, 258, 2, 3, 3) -DEFINE_SPECIAL(Floor_RaiseToCeiling, 259, 2, 4, 4) -DEFINE_SPECIAL(Floor_ToCeilingInstant, 260, 1, 3, 3) +DEFINE_SPECIAL(Floor_RaiseToCeiling, 259, 2, 4, 5) +DEFINE_SPECIAL(Floor_ToCeilingInstant, 260, 1, 3, 4) DEFINE_SPECIAL(Floor_LowerByTexture, 261, 2, 3, 3) DEFINE_SPECIAL(Ceiling_RaiseToHighest, 262, 2, 3, 3) DEFINE_SPECIAL(Ceiling_ToHighestInstant, 263, 1, 3, 3) DEFINE_SPECIAL(Ceiling_LowerToNearest, 264, 2, 4, 4) DEFINE_SPECIAL(Ceiling_RaiseToLowest, 265, 2, 3, 3) DEFINE_SPECIAL(Ceiling_RaiseToHighestFloor, 266, 2, 3, 3) -DEFINE_SPECIAL(Ceiling_ToFloorInstant, 267, 1, 3, 3) +DEFINE_SPECIAL(Ceiling_ToFloorInstant, 267, 1, 3, 4) DEFINE_SPECIAL(Ceiling_RaiseByTexture, 268, 2, 3, 3) DEFINE_SPECIAL(Ceiling_LowerByTexture, 269, 2, 4, 4) DEFINE_SPECIAL(Stairs_BuildDownDoom, 270, 5, 5, 5) diff --git a/src/actor.h b/src/actor.h index a9ce18a57..154d14289 100644 --- a/src/actor.h +++ b/src/actor.h @@ -382,6 +382,7 @@ enum ActorFlag7 MF7_ALLOWTHRUFLAGS = 0x00400000, // [MC] Allow THRUACTORS and the likes on puffs to prevent mod breakage. MF7_USEKILLSCRIPTS = 0x00800000, // [JM] Use "KILL" Script on death if not forced by GameInfo. MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo. + MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. }; // --- mobj.renderflags --- @@ -978,6 +979,8 @@ public: DVector3 __Pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions. DVector3 OldRenderPos; + DAngle SpriteAngle; + DAngle SpriteRotation; DRotator Angles; DVector3 Vel; double Speed; diff --git a/src/am_map.cpp b/src/am_map.cpp index 3a4e0aaa1..7e346843b 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1897,6 +1897,7 @@ void AM_drawSubsectors() FDynamicColormap *colormap; mpoint_t originpt; + screen->StartSimplePolys(); for (int i = 0; i < numsubsectors; ++i) { if (subsectors[i].flags & SSECF_POLYORG) @@ -2049,6 +2050,7 @@ void AM_drawSubsectors() ); } } + screen->FinishSimplePolys(); } //============================================================================= diff --git a/src/c_console.cpp b/src/c_console.cpp index 2f221e319..9a9274aa1 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -162,7 +162,7 @@ CVAR (Bool, con_centernotify, false, CVAR_ARCHIVE) CUSTOM_CVAR (Int, con_scaletext, 0, CVAR_ARCHIVE) // Scale notify text at high resolutions? { if (self < 0) self = 0; - if (self > 2) self = 2; + if (self > 3) self = 3; } CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE) @@ -493,7 +493,14 @@ void C_AddNotifyString (int printlevel, const char *source) return; } - width = con_scaletext > 1 ? DisplayWidth/2 : con_scaletext == 1 ? DisplayWidth / CleanXfac : DisplayWidth; + switch (con_scaletext) + { + default: + case 0: width = DisplayWidth; break; + case 1: width = DisplayWidth / CleanXfac; break; + case 2: width = DisplayWidth / 2; break; + case 3: width = DisplayWidth / 4; break; + } if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].PrintLevel == printlevel) { @@ -770,6 +777,23 @@ static void C_DrawNotifyText () line, NotifyStrings[i].Text, DTA_AlphaF, alpha, TAG_DONE); } + else if (con_scaletext == 3) + { + if (!center) + screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, + DTA_VirtualWidth, screen->GetWidth() / 4, + DTA_VirtualHeight, screen->GetHeight() / 4, + DTA_KeepRatio, true, + DTA_AlphaF, alpha, TAG_DONE); + else + screen->DrawText (SmallFont, color, (screen->GetWidth() / 4 - + SmallFont->StringWidth (NotifyStrings[i].Text))/4, + line, NotifyStrings[i].Text, + DTA_VirtualWidth, screen->GetWidth() / 4, + DTA_VirtualHeight, screen->GetHeight() / 4, + DTA_KeepRatio, true, + DTA_AlphaF, alpha, TAG_DONE); + } else { if (!center) diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index d814717c9..b053d8bd8 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -234,9 +234,27 @@ void CT_Drawer (void) scalex = 1; } - int screen_width = con_scaletext > 1? SCREENWIDTH/2 : SCREENWIDTH; - int screen_height = con_scaletext > 1? SCREENHEIGHT/2 : SCREENHEIGHT; - int st_y = con_scaletext > 1? ST_Y/2 : ST_Y; + int screen_width, screen_height, st_y; + switch (con_scaletext) + { + default: + case 0: + case 1: + screen_width = SCREENWIDTH; + screen_height = SCREENHEIGHT; + st_y = ST_Y; + break; + case 2: + screen_width = SCREENWIDTH / 2; + screen_height = SCREENHEIGHT / 2; + st_y = ST_Y / 2; + break; + case 3: + screen_width = SCREENWIDTH / 4; + screen_height = SCREENHEIGHT / 4; + st_y = ST_Y / 4; + break; + } y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y; diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 0ee61f942..9f13d3d9e 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -260,7 +260,14 @@ void DHUDMessage::ResetText (const char *text) } else { - width = con_scaletext >= 2 ? SCREENWIDTH/2 : (con_scaletext ? SCREENWIDTH / CleanXfac : SCREENWIDTH); + switch (con_scaletext) + { + default: + case 0: width = SCREENWIDTH; break; + case 1: width = SCREENWIDTH / CleanXfac; break; + case 2: width = SCREENWIDTH / 2; break; + case 3: width = SCREENWIDTH / 4; break; + } } if (Lines != NULL) @@ -334,12 +341,18 @@ void DHUDMessage::Draw (int bottom, int visibility) else { xscale = yscale = 1; - if (HUDWidth==0 && con_scaletext>1) + if (HUDWidth==0 && con_scaletext==2) { screen_width/=2; screen_height/=2; bottom/=2; } + else if (HUDWidth==0 && con_scaletext==3) + { + screen_width/=4; + screen_height/=4; + bottom/=4; + } } if (HUDWidth == 0) @@ -448,6 +461,16 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_AlphaF, Alpha, + DTA_RenderStyle, Style, + DTA_KeepRatio, true, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, @@ -551,6 +574,16 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_AlphaF, trans, + DTA_RenderStyle, Style, + DTA_KeepRatio, true, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, @@ -651,6 +684,16 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_AlphaF, trans, + DTA_RenderStyle, Style, + DTA_KeepRatio, true, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, @@ -830,6 +873,17 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_KeepRatio, true, + DTA_TextLen, LineVisible, + DTA_AlphaF, Alpha, + DTA_RenderStyle, Style, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 3a8dc388c..c9e87d642 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -885,8 +885,25 @@ static void DrawCoordinates(player_t * CPlayer) pos = DVector3(apos, z); } - int vwidth = con_scaletext==0? SCREENWIDTH : SCREENWIDTH/2; - int vheight = con_scaletext==0? SCREENHEIGHT : SCREENHEIGHT/2; + int vwidth, vheight; + switch (con_scaletext) + { + default: + case 0: + vwidth = SCREENWIDTH; + vheight = SCREENWIDTH; + break; + case 1: + case 2: + vwidth = SCREENWIDTH/2; + vheight = SCREENWIDTH/2; + break; + case 3: + vwidth = SCREENWIDTH/4; + vheight = SCREENWIDTH/4; + break; + } + int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; int ypos = 18; @@ -1073,7 +1090,12 @@ void DrawHUD() if (hud_althudscale && SCREENWIDTH>640) { hudwidth=SCREENWIDTH/2; - if (hud_althudscale == 2) + if (hud_althudscale == 3) + { + hudwidth = SCREENWIDTH / 4; + hudheight = SCREENHEIGHT / 4; + } + else if (hud_althudscale == 2) { // Optionally just double the pixels to reduce scaling artifacts. hudheight=SCREENHEIGHT/2; diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index b48c04893..c3b1fd262 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -108,7 +108,7 @@ CVAR (Int, crosshair, 0, CVAR_ARCHIVE) CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE) CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE); CVAR (Bool, crosshairhealth, true, CVAR_ARCHIVE); -CVAR (Bool, crosshairscale, false, CVAR_ARCHIVE); +CVAR (Float, crosshairscale, 1.0, CVAR_ARCHIVE); CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE); CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE) { @@ -1106,9 +1106,9 @@ void DBaseStatusBar::DrawCrosshair () return; } - if (crosshairscale) + if (crosshairscale > 0.0f) { - size = SCREENHEIGHT / 200.; + size = SCREENHEIGHT * crosshairscale / 200.; } else { @@ -1247,6 +1247,13 @@ void DBaseStatusBar::Draw (EHudState state) xpos = vwidth - 80; y = ::ST_Y - height; } + else if (con_scaletext == 3) + { + vwidth = SCREENWIDTH/4; + vheight = SCREENHEIGHT/4; + xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; + y = ::ST_Y/4 - height; + } else { vwidth = SCREENWIDTH/2; @@ -1259,6 +1266,8 @@ void DBaseStatusBar::Draw (EHudState state) { if (con_scaletext == 0) y -= height * 4; + else if (con_scaletext == 3) + y -= height; else y -= height * 2; } @@ -1407,6 +1416,11 @@ void DBaseStatusBar::DrawLog () hudwidth = SCREENWIDTH / 2; hudheight = SCREENHEIGHT / 2; break; + + case 3: + hudwidth = SCREENWIDTH / 4; + hudheight = SCREENHEIGHT / 4; + break; } int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560; diff --git a/src/namedef.h b/src/namedef.h index 17fa9e291..cd0d5615b 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -214,6 +214,7 @@ xx(Brainexplode) // Weapon animator names. xx(Select) xx(Deselect) +xx(DeadLowered) xx(Ready) xx(Fire) xx(Hold) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 5e2117b9b..d27ebe4d1 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -514,6 +514,17 @@ void P_Recalculate3DFloors(sector_t * sector) clipped_bottom = pick_bottom; } } + else if (pick_bottom > height) // do not allow inverted planes + { + F3DFloor * dyn = new F3DFloor; + *dyn = *pick; + pick->flags |= FF_CLIPPED; + pick->flags &= ~FF_EXISTS; + dyn->flags |= FF_DYNAMIC; + dyn->bottom.copyPlane(&pick->top); + ffloors.Push(pick); + ffloors.Push(dyn); + } else { clipped = pick; diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 8a0c8f9ef..c635d9743 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -309,7 +309,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t break; case DCeiling::ceilLowerToHighestFloor: - targheight = sec->FindHighestFloorSurrounding (&spot); + targheight = sec->FindHighestFloorSurrounding (&spot) + height; ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); ceiling->m_Direction = -1; break; @@ -359,13 +359,13 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t break; case DCeiling::ceilLowerToFloor: - targheight = sec->FindHighestFloorPoint (&spot); + targheight = sec->FindHighestFloorPoint (&spot) + height; ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); ceiling->m_Direction = -1; break; case DCeiling::ceilRaiseToFloor: // [RH] What's this for? - targheight = sec->FindHighestFloorPoint (&spot); + targheight = sec->FindHighestFloorPoint (&spot) + height; ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); ceiling->m_Direction = 1; break; diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 3f2b06f95..ccb1c82e9 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -349,16 +349,14 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, break; case DFloor::floorRaiseAndCrushDoom: + height = 8; case DFloor::floorRaiseToLowestCeiling: floor->m_Direction = 1; - newheight = sec->FindLowestCeilingSurrounding(&spot); - if (floortype == DFloor::floorRaiseAndCrushDoom) - newheight -= 8; + newheight = sec->FindLowestCeilingSurrounding(&spot) - height; ceilingheight = sec->FindLowestCeilingPoint(&spot2); floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); if (sec->floorplane.ZatPointDist(spot2, floor->m_FloorDestDist) > ceilingheight) - floor->m_FloorDestDist = sec->floorplane.PointToDist(spot2, - floortype == DFloor::floorRaiseAndCrushDoom ? ceilingheight - 8 : ceilingheight); + floor->m_FloorDestDist = sec->floorplane.PointToDist(spot2, floortype == ceilingheight - height); break; case DFloor::floorRaiseToHighest: @@ -387,7 +385,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, case DFloor::floorRaiseToCeiling: floor->m_Direction = 1; - newheight = sec->FindLowestCeilingPoint(&spot); + newheight = sec->FindLowestCeilingPoint(&spot) - height; floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); break; @@ -406,7 +404,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, case DFloor::floorLowerToCeiling: // [RH] Essentially instantly raises the floor to the ceiling floor->m_Direction = -1; - newheight = sec->FindLowestCeilingPoint(&spot); + newheight = sec->FindLowestCeilingPoint(&spot) - height; floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); break; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 307529636..d0a56ee87 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -260,7 +260,13 @@ FUNC(LS_Door_Raise) FUNC(LS_Door_LockedRaise) // Door_LockedRaise (tag, speed, delay, lock, lighttag) { +#if 0 + // In Hexen this originally created a thinker running for nearly 4 years. + // Let's not do this unless it becomes necessary because this can hang tagwait. + return EV_DoDoor (arg2 || (level.flags2 & LEVEL2_HEXENHACK) ? DDoor::doorRaise : DDoor::doorOpen, ln, it, +#else return EV_DoDoor (arg2 ? DDoor::doorRaise : DDoor::doorOpen, ln, it, +#endif arg0, SPEED(arg1), TICS(arg2), arg3, arg4); } @@ -420,9 +426,9 @@ FUNC(LS_Floor_RaiseInstant) } FUNC(LS_Floor_ToCeilingInstant) -// Floor_ToCeilingInstant (tag, change, crush) +// Floor_ToCeilingInstant (tag, change, crush, gap) { - return EV_DoFloor (DFloor::floorLowerToCeiling, ln, arg0, 0, 0, CRUSH(arg2), CHANGE(arg1), true); + return EV_DoFloor (DFloor::floorLowerToCeiling, ln, arg0, 0, arg3, CRUSH(arg2), CHANGE(arg1), true); } FUNC(LS_Floor_MoveToValueTimes8) @@ -448,7 +454,7 @@ FUNC(LS_Floor_RaiseToLowestCeiling) FUNC(LS_Floor_LowerToLowestCeiling) // Floor_LowerToLowestCeiling (tag, speed, change) { - return EV_DoFloor (DFloor::floorLowerToLowestCeiling, ln, arg0, SPEED(arg1), 0, -1, CHANGE(arg2), true); + return EV_DoFloor (DFloor::floorLowerToLowestCeiling, ln, arg0, SPEED(arg1), arg4, -1, CHANGE(arg2), true); } FUNC(LS_Floor_RaiseByTexture) @@ -464,9 +470,9 @@ FUNC(LS_Floor_LowerByTexture) } FUNC(LS_Floor_RaiseToCeiling) -// Floor_RaiseToCeiling (tag, speed, change, crush) +// Floor_RaiseToCeiling (tag, speed, change, crush, gap) { - return EV_DoFloor (DFloor::floorRaiseToCeiling, ln, arg0, SPEED(arg1), 0, CRUSH(arg3), CHANGE(arg2), true); + return EV_DoFloor (DFloor::floorRaiseToCeiling, ln, arg0, SPEED(arg1), arg4, CRUSH(arg3), CHANGE(arg2), true); } FUNC(LS_Floor_RaiseByValueTxTy) @@ -706,9 +712,9 @@ FUNC(LS_Ceiling_MoveToValue) } FUNC(LS_Ceiling_LowerToHighestFloor) -// Ceiling_LowerToHighestFloor (tag, speed, change, crush) +// Ceiling_LowerToHighestFloor (tag, speed, change, crush, gap) { - return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg2)); + return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, arg4, CRUSH(arg3), 0, CHANGE(arg2)); } FUNC(LS_Ceiling_LowerInstant) @@ -808,15 +814,15 @@ FUNC(LS_Ceiling_ToHighestInstant) } FUNC(LS_Ceiling_ToFloorInstant) -// Ceiling_ToFloorInstant (tag, change, crush) +// Ceiling_ToFloorInstant (tag, change, crush, gap) { - return EV_DoCeiling (DCeiling::ceilRaiseToFloor, ln, arg0, 2, 0, 0, CRUSH(arg2), 0, CHANGE(arg1)); + return EV_DoCeiling (DCeiling::ceilRaiseToFloor, ln, arg0, 2, 0, arg3, CRUSH(arg2), 0, CHANGE(arg1)); } FUNC(LS_Ceiling_LowerToFloor) -// Ceiling_LowerToFloor (tag, speed, change, crush) +// Ceiling_LowerToFloor (tag, speed, change, crush, gap) { - return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg4)); + return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, arg4, CRUSH(arg3), 0, CHANGE(arg4)); } FUNC(LS_Ceiling_LowerByTexture) diff --git a/src/p_local.h b/src/p_local.h index 4b8b40a85..ebbaeace5 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -161,7 +161,7 @@ PClassActor *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); int P_Thing_CheckInputNum(player_t *p, int inputnum); int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch); -bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr); +int P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting = false); enum { diff --git a/src/p_map.cpp b/src/p_map.cpp index 106c93152..110ae5235 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1566,7 +1566,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo tm.floorpic = *rover->top.texture; tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling); } - if (ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2)) + if (ff_bottom < tm.ceilingz && fabs(delta1) >= fabs(delta2)) { tm.ceilingz = ff_bottom; tm.ceilingpic = *rover->bottom.texture; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index be875b951..8971efe25 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -383,6 +383,11 @@ void AActor::Serialize(FArchive &arc) << RipLevelMin << RipLevelMax; arc << DefThreshold; + if (SaveVersion >= 4549) + { + arc << SpriteAngle; + arc << SpriteRotation; + } { FString tagstr; @@ -6399,6 +6404,7 @@ void AActor::Revive() flags5 = info->flags5; flags6 = info->flags6; flags7 = info->flags7; + if (SpawnFlags & MTF_FRIENDLY) flags |= MF_FRIENDLY; DamageType = info->DamageType; health = SpawnHealth(); target = NULL; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 350acc3fd..9f1233609 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -237,8 +237,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) pspr->y = WEAPONTOP; } - pspr->oldx = pspr->x; - pspr->oldy = pspr->y; + pspr->firstTic = true; } return pspr; @@ -1087,7 +1086,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) { // Player is dead, so don't bring up a pending weapon // Player is dead, so keep the weapon off screen P_SetPsprite(player, PSP_FLASH, nullptr); - psp->SetState(nullptr); + psp->SetState(player->ReadyWeapon->FindState(NAME_DeadLowered)); return 0; } // [RH] Clear the flash state. Only needed for Strife. diff --git a/src/p_things.cpp b/src/p_things.cpp index 6f01715ad..d94ba6a01 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -696,16 +696,16 @@ int P_Thing_CheckInputNum(player_t *p, int inputnum) } return renum; } -bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr) +int P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting) { AActor *ref = COPY_AAPTR(self, ptr); // We need these to check out. if (!ref || !classname || distance <= 0) - return false; + return 0; int counter = 0; - bool result = false; + int result = 0; double closer = distance, farther = 0, current = distance; const bool ptrWillChange = !!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER)); const bool ptrDistPref = !!(flags & (CPXF_CLOSEST | CPXF_FARTHEST)); @@ -740,7 +740,7 @@ bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, in if ((ref->Distance2D(mo) < distance && ((flags & CPXF_NOZ) || ((ref->Z() > mo->Z() && ref->Z() - mo->Top() < distance) || - (ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance))))) + (ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance))))) { if ((flags & CPXF_CHECKSIGHT) && !(P_CheckSight(mo, ref, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))) continue; @@ -766,19 +766,19 @@ bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, in { if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY))) continue; - counter++; } else { if (flags & CPXF_DEADONLY) continue; - counter++; } + counter++; // Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal. - if (counter > count) - { - result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true; + // Don't abort if calling the counting version CheckProximity non-action function. + if (!counting && counter > count) + { + result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? 0 : 1; // However, if we have one SET* flag and either the closest or farthest flags, keep the function going. if (ptrWillChange && ptrDistPref) @@ -805,12 +805,14 @@ bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, in } } - if (counter == count) - result = true; - else if (counter < count) - result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)); - - return result; + if (!counting) + { + if (counter == count) + result = 1; + else if (counter < count) + result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)) ? 1 : 0; + } + return counting ? counter : result; } int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch) diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index e38a5cc85..b037fe6dd 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -248,9 +248,6 @@ void FConsoleWindow::AddText(const char* message) AddText(color, buffer); } -#define CHECK_BUFFER_SPACE \ - if (pos >= sizeof buffer - 3) { reset = true; continue; } - if (TEXTCOLOR_ESCAPE == *message) { const BYTE* colorID = reinterpret_cast(message) + 1; @@ -268,42 +265,20 @@ void FConsoleWindow::AddText(const char* message) message += 2; } - else if (0x1d == *message) // Opening bar character + else if (0x1d == *message || 0x1f == *message) // Opening and closing bar characters { - CHECK_BUFFER_SPACE; - - // Insert BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT - buffer[pos++] = '\xe2'; - buffer[pos++] = '\x95'; - buffer[pos++] = '\xbc'; + buffer[pos++] = '-'; ++message; } else if (0x1e == *message) // Middle bar character { - CHECK_BUFFER_SPACE; - - // Insert BOX DRAWINGS HEAVY HORIZONTAL - buffer[pos++] = '\xe2'; - buffer[pos++] = '\x94'; - buffer[pos++] = '\x81'; - ++message; - } - else if (0x1f == *message) // Closing bar character - { - CHECK_BUFFER_SPACE; - - // Insert BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT - buffer[pos++] = '\xe2'; - buffer[pos++] = '\x95'; - buffer[pos++] = '\xbe'; + buffer[pos++] = '='; ++message; } else { buffer[pos++] = *message++; } - -#undef CHECK_BUFFER_SPACE } if (0 != pos) diff --git a/src/r_things.cpp b/src/r_things.cpp index f93f34100..ff5ef48d2 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -809,11 +809,17 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor angle_t rot; if (sprframe->Texture[0] == sprframe->Texture[1]) { - rot = (ang - thing->Angles.Yaw + 45.0/2*9).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28; } else { - rot = (ang - thing->Angles.Yaw + (45.0/2*9-180.0/16)).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; } picnum = sprframe->Texture[rot]; if (sprframe->Flip & (1 << rot)) @@ -848,11 +854,17 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor angle_t rot; if (sprframe->Texture[0] == sprframe->Texture[1]) { - rot = (ang - thing->Angles.Yaw + 45.0 / 2 * 9).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28; } else { - rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + if (thing->flags7 & MF7_SPRITEANGLE) + rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; + else + rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; } picnum = sprframe->Texture[rot]; if (sprframe->Flip & (1 << rot)) @@ -904,7 +916,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor // too far off the side? // if it's a voxel, it can be further off the side if ((voxel == NULL && (fabs(tx / 64) > fabs(tz))) || - (voxel != NULL && (fabs(tx / 128) > abs(tz)))) + (voxel != NULL && (fabs(tx / 128) > fabs(tz)))) { return; } @@ -2805,6 +2817,11 @@ void R_DrawVoxel(const FVector3 &globalpos, FAngle viewangle, // Also do some magic voodoo scaling to make them the right size. daxscale = daxscale / (0xC000 >> 6); dayscale = dayscale / (0xC000 >> 6); + if (daxscale <= 0 || dayscale <= 0) + { + // won't be visible. + return; + } angle_t viewang = viewangle.BAMs(); cosang = FLOAT2FIXED(viewangle.Cos()) >> 2; diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4bb247f94..04ac21890 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -361,16 +361,20 @@ static void FinishThingdef() if (sfunc == NULL) { FCompileContext ctx(ti); - dmg->Resolve(ctx); - VMFunctionBuilder buildit; - buildit.Registers[REGT_POINTER].Get(1); // The self pointer - dmg->Emit(&buildit); - sfunc = buildit.MakeFunction(); - sfunc->NumArgs = 1; - sfunc->Proto = NULL; ///FIXME: Need a proper prototype here - // Save this function in case this damage value was reused - // (which happens quite easily with inheritance). - dmg->SetFunction(sfunc); + dmg = static_cast(dmg->Resolve(ctx)); + + if (dmg != nullptr) + { + VMFunctionBuilder buildit; + buildit.Registers[REGT_POINTER].Get(1); // The self pointer + dmg->Emit(&buildit); + sfunc = buildit.MakeFunction(); + sfunc->NumArgs = 1; + sfunc->Proto = NULL; ///FIXME: Need a proper prototype here + // Save this function in case this damage value was reused + // (which happens quite easily with inheritance). + dmg->SetFunction(sfunc); + } } def->Damage = sfunc; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d1933e142..6904a05d4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -395,6 +395,64 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth) return 0; } +//========================================================================== +// +// GetSpriteAngle +// +// NON-ACTION function returns the sprite angle of a pointer. +//========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteAngle) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *target = COPY_AAPTR(self, ptr); + if (target == nullptr) + { + ret->SetFloat(0.0); + } + else + { + const double ang = target->SpriteAngle.Degrees; + ret->SetFloat(ang); + } + return 1; + } + return 0; +} + +//========================================================================== +// +// GetSpriteRotation +// +// NON-ACTION function returns the sprite rotation of a pointer. +//========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteRotation) +{ + if (numret > 0) + { + assert(ret != NULL); + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *target = COPY_AAPTR(self, ptr); + if (target == nullptr) + { + ret->SetFloat(0.0); + } + else + { + const double ang = target->SpriteRotation.Degrees; + ret->SetFloat(ang); + } + return 1; + } + return 0; +} + //========================================================================== // // GetZAt @@ -585,6 +643,38 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetPlayerInput) return 0; } +//========================================================================== +// +// CountProximity +// +// NON-ACTION function of A_CheckProximity that returns how much it counts. +// Takes a pointer as anyone may or may not be a player. +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) +{ + if (numret > 0) + { + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(classname, AActor); + PARAM_FLOAT(distance); + PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *mobj = COPY_AAPTR(self, ptr); + if (mobj == nullptr) + { + ret->SetInt(0); + } + else + { + ret->SetInt(P_Thing_CheckProximity(self, classname, distance, 0, flags, ptr, true)); + } + return 1; + } + return 0; +} + //=========================================================================== // // __decorate_internal_state__ @@ -3013,12 +3103,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) // A_SelectWeapon // //=========================================================================== +enum SW_Flags +{ + SWF_SELECTPRIORITY = 1, +}; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(cls, AWeapon); + PARAM_INT_OPT(flags) { flags = 0; } - if (cls == NULL || self->player == NULL) + bool selectPriority = !!(flags & SWF_SELECTPRIORITY); + + if ((!selectPriority && cls == NULL) || self->player == NULL) { ACTION_RETURN_BOOL(false); } @@ -3033,6 +3130,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) } ACTION_RETURN_BOOL(true); } + else if (selectPriority) + { + // [XA] if the named weapon cannot be found (or is a dummy like 'None'), + // select the next highest priority weapon. This is basically + // the same as A_CheckReload minus the ammo check. Handy. + self->player->mo->PickNewWeapon(NULL); + ACTION_RETURN_BOOL(true); + } else { ACTION_RETURN_BOOL(false); @@ -7202,7 +7307,7 @@ enum CPSFFlags DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame) { - PARAM_SELF_PROLOGUE(AActor); + PARAM_ACTION_PROLOGUE; PARAM_INT(from); PARAM_INT(to); PARAM_INT_OPT(flags) { flags = 0; } @@ -7219,3 +7324,49 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame) if (!(flags & CPSF_NOFRAME)) copyto->frame = copyfrom->frame; ACTION_RETURN_BOOL(true); } + +//========================================================================== +// +// A_SetSpriteAngle(angle, ptr) +// +// Specifies which angle the actor must always draw its sprite from. +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteAngle) +{ + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT_OPT(angle) { angle = 0.; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *mobj = COPY_AAPTR(self, ptr); + + if (mobj == nullptr) + { + ACTION_RETURN_BOOL(false); + } + mobj->SpriteAngle = angle; + ACTION_RETURN_BOOL(true); +} + +//========================================================================== +// +// A_SetSpriteRotation(angle, ptr) +// +// Specifies how much to fake a sprite rotation. +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteRotation) +{ + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE_OPT(angle) { angle = 0.; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *mobj = COPY_AAPTR(self, ptr); + + if (mobj == nullptr) + { + ACTION_RETURN_BOOL(false); + } + mobj->SpriteRotation = angle; + ACTION_RETURN_BOOL(true); +} diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 0768f80c8..3b114fbee 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -259,6 +259,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, ALLOWTHRUFLAGS, AActor, flags7), DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7), + DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 35932e0be..6a756d9b5 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -392,7 +392,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) return ParseAtan2(sc, identifier, cls); default: args = new FArgumentList; - func = dyn_cast(cls->Symbols.FindSymbol(identifier, true)); + func = (cls == nullptr) ? nullptr : dyn_cast(cls->Symbols.FindSymbol(identifier, true)); try { // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 58820ea15..b878e50f1 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -48,8 +48,10 @@ #define RESOLVE(p,c) if (p!=NULL) p = p->Resolve(c) #define ABORT(p) if (!(p)) { delete this; return NULL; } #define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p) +#define SAFE_RESOLVE_OPT(p,c) if (p!=NULL) { SAFE_RESOLVE(p,c) } class VMFunctionBuilder; +class FxJumpStatement; //========================================================================== // @@ -59,21 +61,15 @@ class VMFunctionBuilder; struct FCompileContext { - PClassActor *cls; + TArray Jumps; + PClassActor *Class; - FCompileContext(PClassActor *_cls = NULL) - { - cls = _cls; - } + FCompileContext(PClassActor *cls = nullptr); - PSymbol *FindInClass(FName identifier) - { - return cls ? cls->Symbols.FindSymbol(identifier, true) : NULL; - } - PSymbol *FindGlobal(FName identifier) - { - return GlobalSymbols.FindSymbol(identifier, true); - } + PSymbol *FindInClass(FName identifier); + PSymbol *FindGlobal(FName identifier); + + void HandleJumps(int token, FxExpression *handler); }; //========================================================================== @@ -212,6 +208,8 @@ public: virtual ExpEmit Emit(VMFunctionBuilder *build); + TArray JumpAddresses; + FScriptPosition ScriptPosition; PType *ValueType; @@ -930,6 +928,80 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxWhileLoop +// +//========================================================================== + +class FxWhileLoop : public FxExpression +{ + FxExpression *Condition; + FxExpression *Code; + +public: + FxWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos); + ~FxWhileLoop(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxDoWhileLoop +// +//========================================================================== + +class FxDoWhileLoop : public FxExpression +{ + FxExpression *Condition; + FxExpression *Code; + +public: + FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos); + ~FxDoWhileLoop(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxForLoop +// +//========================================================================== + +class FxForLoop : public FxExpression +{ + FxExpression *Init; + FxExpression *Condition; + FxExpression *Iteration; + FxExpression *Code; + +public: + FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos); + ~FxForLoop(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxJumpStatement +// +//========================================================================== + +class FxJumpStatement : public FxExpression +{ +public: + FxJumpStatement(int token, const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); + + int Token; + size_t Address; + FxExpression *AddressResolver; +}; + //========================================================================== // // FxReturnStatement diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index b4a0b3fda..b57618575 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -85,6 +85,45 @@ static const FLOP FxFlops[] = { NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } }, }; +//========================================================================== +// +// FCompileContext +// +//========================================================================== + +FCompileContext::FCompileContext(PClassActor *cls) : Class(cls) +{ +} + +PSymbol *FCompileContext::FindInClass(FName identifier) +{ + return Class ? Class->Symbols.FindSymbol(identifier, true) : nullptr; +} +PSymbol *FCompileContext::FindGlobal(FName identifier) +{ + return GlobalSymbols.FindSymbol(identifier, true); +} + +void FCompileContext::HandleJumps(int token, FxExpression *handler) +{ + for (unsigned int i = 0; i < Jumps.Size(); i++) + { + if (Jumps[i]->Token == token) + { + Jumps[i]->AddressResolver = handler; + handler->JumpAddresses.Push(Jumps[i]); + Jumps.Delete(i); + i--; + } + } +} + +//========================================================================== +// +// ExpEmit +// +//========================================================================== + ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) { @@ -375,7 +414,7 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) { build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.)); } - else if (from.RegNum == REGT_POINTER) + else if (from.RegType == REGT_POINTER) { build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); } @@ -2838,14 +2877,14 @@ FxSelf::FxSelf(const FScriptPosition &pos) FxExpression *FxSelf::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); - if (!ctx.cls) + if (!ctx.Class) { // can't really happen with DECORATE's expression evaluator. ScriptPosition.Message(MSG_ERROR, "self used outside of a member function"); delete this; return NULL; } - ValueType = ctx.cls; + ValueType = ctx.Class; ValueType = NewPointer(RUNTIME_CLASS(DObject)); return this; } @@ -3818,6 +3857,369 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) return ExpEmit(); } +//========================================================================== +// +// FxWhileLoop +// +//========================================================================== + +FxWhileLoop::FxWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos) +: FxExpression(pos), Condition(condition), Code(code) +{ + ValueType = TypeVoid; +} + +FxWhileLoop::~FxWhileLoop() +{ + SAFE_DELETE(Condition); + SAFE_DELETE(Code); +} + +FxExpression *FxWhileLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Condition, ctx); + SAFE_RESOLVE_OPT(Code, ctx); + + ctx.HandleJumps(TK_Break, this); + ctx.HandleJumps(TK_Continue, this); + + if (Condition->ValueType != TypeBool) + { + Condition = new FxBoolCast(Condition); + SAFE_RESOLVE(Condition, ctx); + } + + if (Condition->isConstant()) + { + if (static_cast(Condition)->GetValue().GetBool() == false) + { // Nothing happens + FxExpression *nop = new FxNop(ScriptPosition); + delete this; + return nop; + } + else if (Code == nullptr) + { // "while (true) { }" + // Someone could be using this for testing. + ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); + } + } + + return this; +} + +ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build) +{ + assert(Condition->ValueType == TypeBool); + + size_t loopstart, loopend; + size_t jumpspot; + + // Evaluate the condition and execute/break out of the loop. + loopstart = build->GetAddress(); + if (!Condition->isConstant()) + { + ExpEmit cond = Condition->Emit(build); + build->Emit(OP_TEST, cond.RegNum, 0); + jumpspot = build->Emit(OP_JMP, 0); + cond.Free(build); + } + else assert(static_cast(Condition)->GetValue().GetBool() == true); + + // Execute the loop's content. + if (Code != nullptr) + { + ExpEmit code = Code->Emit(build); + code.Free(build); + } + + // Loop back. + build->Backpatch(build->Emit(OP_JMP, 0), loopstart); + loopend = build->GetAddress(); + + if (!Condition->isConstant()) + { + build->Backpatch(jumpspot, loopend); + } + + // Give a proper address to any break/continue statement within this loop. + for (unsigned int i = 0; i < JumpAddresses.Size(); i++) + { + if (JumpAddresses[i]->Token == TK_Break) + { + build->Backpatch(JumpAddresses[i]->Address, loopend); + } + else + { // Continue statement. + build->Backpatch(JumpAddresses[i]->Address, loopstart); + } + } + + return ExpEmit(); +} + +//========================================================================== +// +// FxDoWhileLoop +// +//========================================================================== + +FxDoWhileLoop::FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos) +: FxExpression(pos), Condition(condition), Code(code) +{ + ValueType = TypeVoid; +} + +FxDoWhileLoop::~FxDoWhileLoop() +{ + SAFE_DELETE(Condition); + SAFE_DELETE(Code); +} + +FxExpression *FxDoWhileLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Condition, ctx); + SAFE_RESOLVE_OPT(Code, ctx); + + ctx.HandleJumps(TK_Break, this); + ctx.HandleJumps(TK_Continue, this); + + if (Condition->ValueType != TypeBool) + { + Condition = new FxBoolCast(Condition); + SAFE_RESOLVE(Condition, ctx); + } + + if (Condition->isConstant()) + { + if (static_cast(Condition)->GetValue().GetBool() == false) + { // The code executes once, if any. + if (JumpAddresses.Size() == 0) + { // We would still have to handle the jumps however. + FxExpression *e = Code; + if (e == nullptr) e = new FxNop(ScriptPosition); + Code = nullptr; + delete this; + return e; + } + } + else if (Code == nullptr) + { // "do { } while (true);" + // Someone could be using this for testing. + ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); + } + } + + return this; +} + +ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build) +{ + assert(Condition->ValueType == TypeBool); + + size_t loopstart, loopend; + size_t codestart; + + // Execute the loop's content. + codestart = build->GetAddress(); + if (Code != nullptr) + { + ExpEmit code = Code->Emit(build); + code.Free(build); + } + + // Evaluate the condition and execute/break out of the loop. + loopstart = build->GetAddress(); + if (!Condition->isConstant()) + { + ExpEmit cond = Condition->Emit(build); + build->Emit(OP_TEST, cond.RegNum, 1); + cond.Free(build); + build->Backpatch(build->Emit(OP_JMP, 0), codestart); + } + else if (static_cast(Condition)->GetValue().GetBool() == true) + { // Always looping + build->Backpatch(build->Emit(OP_JMP, 0), codestart); + } + loopend = build->GetAddress(); + + // Give a proper address to any break/continue statement within this loop. + for (unsigned int i = 0; i < JumpAddresses.Size(); i++) + { + if (JumpAddresses[i]->Token == TK_Break) + { + build->Backpatch(JumpAddresses[i]->Address, loopend); + } + else + { // Continue statement. + build->Backpatch(JumpAddresses[i]->Address, loopstart); + } + } + + return ExpEmit(); +} + +//========================================================================== +// +// FxForLoop +// +//========================================================================== + +FxForLoop::FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos) +: FxExpression(pos), Init(init), Condition(condition), Iteration(iteration), Code(code) +{ + ValueType = TypeVoid; +} + +FxForLoop::~FxForLoop() +{ + SAFE_DELETE(Init); + SAFE_DELETE(Condition); + SAFE_DELETE(Iteration); + SAFE_DELETE(Code); +} + +FxExpression *FxForLoop::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE_OPT(Init, ctx); + SAFE_RESOLVE_OPT(Condition, ctx); + SAFE_RESOLVE_OPT(Iteration, ctx); + SAFE_RESOLVE_OPT(Code, ctx); + + ctx.HandleJumps(TK_Break, this); + ctx.HandleJumps(TK_Continue, this); + + if (Condition != nullptr) + { + if (Condition->ValueType != TypeBool) + { + Condition = new FxBoolCast(Condition); + SAFE_RESOLVE(Condition, ctx); + } + + if (Condition->isConstant()) + { + if (static_cast(Condition)->GetValue().GetBool() == false) + { // Nothing happens + FxExpression *nop = new FxNop(ScriptPosition); + delete this; + return nop; + } + else + { // "for (..; true; ..)" + delete Condition; + Condition = nullptr; + } + } + } + if (Condition == nullptr && Code == nullptr) + { // "for (..; ; ..) { }" + // Someone could be using this for testing. + ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); + } + + return this; +} + +ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) +{ + assert((Condition && Condition->ValueType == TypeBool && !Condition->isConstant()) || Condition == nullptr); + + size_t loopstart, loopend; + size_t codestart; + size_t jumpspot; + + // Init statement. + if (Init != nullptr) + { + ExpEmit init = Init->Emit(build); + init.Free(build); + } + + // Evaluate the condition and execute/break out of the loop. + codestart = build->GetAddress(); + if (Condition != nullptr) + { + ExpEmit cond = Condition->Emit(build); + build->Emit(OP_TEST, cond.RegNum, 0); + cond.Free(build); + jumpspot = build->Emit(OP_JMP, 0); + } + + // Execute the loop's content. + if (Code != nullptr) + { + ExpEmit code = Code->Emit(build); + code.Free(build); + } + + // Iteration statement. + loopstart = build->GetAddress(); + if (Iteration != nullptr) + { + ExpEmit iter = Iteration->Emit(build); + iter.Free(build); + } + build->Backpatch(build->Emit(OP_JMP, 0), codestart); + + // End of loop. + loopend = build->GetAddress(); + if (Condition != nullptr) + { + build->Backpatch(jumpspot, loopend); + } + + // Give a proper address to any break/continue statement within this loop. + for (unsigned int i = 0; i < JumpAddresses.Size(); i++) + { + if (JumpAddresses[i]->Token == TK_Break) + { + build->Backpatch(JumpAddresses[i]->Address, loopend); + } + else + { // Continue statement. + build->Backpatch(JumpAddresses[i]->Address, loopstart); + } + } + + return ExpEmit(); +} + +//========================================================================== +// +// FxJumpStatement +// +//========================================================================== + +FxJumpStatement::FxJumpStatement(int token, const FScriptPosition &pos) +: FxExpression(pos), Token(token), AddressResolver(nullptr) +{ + ValueType = TypeVoid; +} + +FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + ctx.Jumps.Push(this); + + return this; +} + +ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build) +{ + if (AddressResolver == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Jump statement %s has nowhere to go!", FScanner::TokenName(Token).GetChars()); + } + + Address = build->Emit(OP_JMP, 0); + + return ExpEmit(); +} + //========================================================================== // //========================================================================== @@ -4008,19 +4410,21 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - if (ctx.cls->NumOwnedStates == 0) + ABORT(ctx.Class); + + if (ctx.Class->NumOwnedStates == 0) { // This can't really happen assert(false); } - if (ctx.cls->NumOwnedStates <= index) + if (ctx.Class->NumOwnedStates <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", - ctx.cls->TypeName.GetChars(), index); + ctx.Class->TypeName.GetChars(), index); delete this; return NULL; } - FxExpression *x = new FxConstant(ctx.cls->OwnedStates + index, ScriptPosition); + FxExpression *x = new FxConstant(ctx.Class->OwnedStates + index, ScriptPosition); delete this; return x; } @@ -4062,13 +4466,15 @@ FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPositi FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); + ABORT(ctx.Class); + if (names[0] == NAME_None) { scope = NULL; } else if (names[0] == NAME_Super) { - scope = dyn_cast(ctx.cls->ParentClass); + scope = dyn_cast(ctx.Class->ParentClass); } else { @@ -4079,9 +4485,9 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) delete this; return NULL; } - else if (!scope->IsDescendantOf(ctx.cls)) + else if (!scope->IsDescendantOf(ctx.Class)) { - ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.cls->TypeName.GetChars()); + ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.Class->TypeName.GetChars()); delete this; return NULL; } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index f4bad69bb..566643b8e 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -191,7 +191,12 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FxExpression *expr = ParseExpression (sc, cls, true); sc.MustGetToken(';'); - if (!expr->isConstant()) + if (expr == nullptr) + { + sc.ScriptMessage("Error while resolving constant definition"); + FScriptPosition::ErrorCounter++; + } + else if (!expr->isConstant()) { sc.ScriptMessage("Constant definition is not a constant"); FScriptPosition::ErrorCounter++; @@ -247,16 +252,24 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls, true); - if (!expr->isConstant()) + if (expr != nullptr) { - sc.ScriptMessage("'%s' must be constant", symname.GetChars()); - FScriptPosition::ErrorCounter++; + if (!expr->isConstant()) + { + sc.ScriptMessage("'%s' must be constant", symname.GetChars()); + FScriptPosition::ErrorCounter++; + } + else + { + currvalue = static_cast(expr)->GetValue().GetInt(); + } + delete expr; } else { - currvalue = static_cast(expr)->GetValue().GetInt(); + sc.ScriptMessage("Error while resolving expression of '%s'", symname.GetChars()); + FScriptPosition::ErrorCounter++; } - delete expr; } PSymbolConstNumeric *sym = new PSymbolConstNumeric(symname, TypeSInt32); sym->Value = currvalue; @@ -568,7 +581,13 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls, true); - if (!expr->isConstant()) + if (expr == nullptr) + { + sc.ScriptMessage("Error while resolving array size"); + FScriptPosition::ErrorCounter++; + maxelems = 1; + } + else if (!expr->isConstant()) { sc.ScriptMessage("Array size must be a constant"); FScriptPosition::ErrorCounter++; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index db6ef14a0..372f444cd 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1345,6 +1345,24 @@ DEFINE_PROPERTY(gravity, F, Actor) defaults->Gravity = i; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(spriteangle, F, Actor) +{ + PROP_DOUBLE_PARM(i, 0); + defaults->SpriteAngle = i; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(spriterotation, F, Actor) +{ + PROP_DOUBLE_PARM(i, 0); + defaults->SpriteRotation = i; +} + //========================================================================== // //========================================================================== diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index ae1805119..ecc62bf29 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -480,6 +480,93 @@ static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Ba return add; } +static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, + PPrototype *&retproto, bool &lastwasret) +{ + FxExpression *cond, *code; + PPrototype *proto; + bool ret; + + sc.MustGetStringName("("); + cond = ParseExpression(sc, bag.Info); + sc.MustGetStringName(")"); + sc.MustGetStringName("{"); // Enforce braces like for if statements. + + code = ParseActions(sc, state, statestring, bag, proto, ret); + sc.MustGetString(); + + retproto = ReturnCheck(retproto, proto, sc); + lastwasret = false; // A while loop always jumps back. + + return new FxWhileLoop(cond, code, sc); +} + +static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, + PPrototype *&retproto, bool &lastwasret) +{ + FxExpression *cond, *code; + PPrototype *proto; + bool ret; + + sc.MustGetStringName("{"); // Enforce braces like for if statements. + code = ParseActions(sc, state, statestring, bag, proto, ret); + + sc.MustGetStringName("while"); + sc.MustGetStringName("("); + cond = ParseExpression(sc, bag.Info); + sc.MustGetStringName(")"); + sc.MustGetStringName(";"); + sc.MustGetString(); + + retproto = ReturnCheck(retproto, proto, sc); + lastwasret = false; + + return new FxDoWhileLoop(cond, code, sc); +} + +static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, + PPrototype *&retproto, bool &lastwasret) +{ + FxExpression *init = nullptr; + FxExpression *cond = nullptr; + FxExpression *iter = nullptr; + FxExpression *code = nullptr; + PPrototype *proto; + bool ret; + + // Parse the statements. + sc.MustGetStringName("("); + sc.MustGetString(); + if (!sc.Compare(";")) + { + init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now. + sc.MustGetStringName(";"); + } + sc.MustGetString(); + if (!sc.Compare(";")) + { + sc.UnGet(); + cond = ParseExpression(sc, bag.Info); + sc.MustGetStringName(";"); + } + sc.MustGetString(); + if (!sc.Compare(")")) + { + iter = ParseAction(sc, state, statestring, bag); + sc.MustGetStringName(")"); + } + + // Now parse the loop's content. + sc.MustGetStringName("{"); // Enforce braces like for if statements. + code = ParseActions(sc, state, statestring, bag, proto, ret); + sc.MustGetString(); + + retproto = ReturnCheck(retproto, proto, sc); + lastwasret = false; + + return new FxForLoop(init, cond, iter, code, sc); +} + FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&retproto, bool &endswithret) { @@ -505,9 +592,21 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg FxExpression *add; lastwasret = false; if (sc.Compare("if")) - { // Hangle an if statement + { // Handle an if statement add = ParseIf(sc, state, statestring, bag, proto, lastwasret); } + else if (sc.Compare("while")) + { // Handle a while loop + add = ParseWhile(sc, state, statestring, bag, proto, lastwasret); + } + else if (sc.Compare("do")) + { // Handle a do-while loop + add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret); + } + else if (sc.Compare("for")) + { // Handle a for loop + add = ParseFor(sc, state, statestring, bag, proto, lastwasret); + } else if (sc.Compare("return")) { // Handle a return statement lastwasret = true; @@ -529,6 +628,18 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg sc.MustGetString(); add = new FxReturnStatement(retexp, sc); } + else if (sc.Compare("break")) + { + add = new FxJumpStatement(TK_Break, sc); + sc.MustGetStringName(";"); + sc.MustGetString(); + } + else if (sc.Compare("continue")) + { + add = new FxJumpStatement(TK_Continue, sc); + sc.MustGetStringName(";"); + sc.MustGetString(); + } else { // Handle a regular action function call add = ParseAction(sc, state, statestring, bag); diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 0fb433343..0a039e6ff 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1326,6 +1326,19 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin } } +//========================================================================== +// +// no-ops. This is so that renderer backends can better manage the +// processing of the subsector drawing in the automap +// +//========================================================================== + +void DCanvas::StartSimplePolys() +{} + +void DCanvas::FinishSimplePolys() +{} + //========================================================================== // // DCanvas :: FillSimplePoly diff --git a/src/v_video.h b/src/v_video.h index 19213bd26..526d2a562 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -217,6 +217,9 @@ public: // Fill an area with a texture virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false); + virtual void StartSimplePolys(); + virtual void FinishSimplePolys(); + // Fill a simple polygon with a texture virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, diff --git a/src/version.h b/src/version.h index 9aa4ad799..cffa25bdd 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4548 +#define SAVEVER 4549 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index 2a4f6b1a8..eb49ffb14 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -436,6 +436,17 @@ bool VMFunctionBuilder::RegAvailability::Reuse(int reg) return true; } +//========================================================================== +// +// VMFunctionBuilder :: GetAddress +// +//========================================================================== + +size_t VMFunctionBuilder::GetAddress() +{ + return Code.Size(); +} + //========================================================================== // // VMFunctionBuilder :: Emit diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 89b626c18..2d8721acc 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -34,6 +34,9 @@ public: int GetConstantAddress(void *ptr, VM_ATAG tag); int GetConstantString(FString str); + // Returns the address of the next instruction to be emitted. + size_t GetAddress(); + // Returns the address of the newly-emitted instruction. size_t Emit(int opcode, int opa, int opb, int opc); size_t Emit(int opcode, int opa, VM_SHALF opbc); diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 77250b3df..fa8932050 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -35,6 +35,8 @@ ACTOR Actor native //: Thinker BloodType "Blood", "BloodSplatter", "AxeBlood" ExplosionDamage 128 MissileHeight 32 + SpriteAngle 0 + SpriteRotation 0 // Functions native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); @@ -48,6 +50,9 @@ ACTOR Actor native //: Thinker native float GetCrouchFactor(int ptr = AAPTR_PLAYER1); native float GetCVar(string cvar); native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); + native int CountProximity(class classname, float distance, int flags = 0, int ptr = AAPTR_DEFAULT); + native float GetSpriteAngle(int ptr = AAPTR_DEFAULT); + native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support. @@ -239,7 +244,7 @@ ACTOR Actor native //: Thinker native state A_JumpIfInTargetInventory(class itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); native bool A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); native bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); - native int A_RadiusGive(class itemtype, float distance, int flags, int amount = 0, class filter = "None", name species = "None", int mindist = 0, int limit = 0); + native int A_RadiusGive(class itemtype, float distance, int flags, int amount = 0, class filter = "None", name species = "None", float mindist = 0, int limit = 0); native state A_CheckSpecies(state jump, name species = "", int ptr = AAPTR_DEFAULT); native void A_CountdownArg(int argnum, state targstate = ""); action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); @@ -260,7 +265,7 @@ ACTOR Actor native //: Thinker native state A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, float offsetforward = 0); native state A_JumpIfTargetInLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); native state A_JumpIfInTargetLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - native bool A_SelectWeapon(class whichweapon); + native bool A_SelectWeapon(class whichweapon, int flags = 0); action native A_Punch(); action native A_Feathers(); action native A_ClassBossHealth(); @@ -331,6 +336,8 @@ ACTOR Actor native //: Thinker action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); action native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); action native bool A_CopySpriteFrame(int from, int to, int flags = 0); + action native bool A_SetSpriteAngle(float angle = 0, int ptr = AAPTR_DEFAULT); + action native bool A_SetSpriteRotation(float angle = 0, int ptr = AAPTR_DEFAULT); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 76bdcf9eb..30afd1064 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -150,6 +150,9 @@ const int WRF_ALLOWUSER2 = 256; const int WRF_ALLOWUSER3 = 512; const int WRF_ALLOWUSER4 = 1024; +// Flags for A_SelectWeapon +const int SWF_SELECTPRIORITY = 1; + // Morph constants const int MRF_ADDSTAMINA = 1; const int MRF_FULLHEALTH = 2; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index b0cbf4d91..81363e099 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2201,6 +2201,7 @@ OPTVAL_PLAYER = "Player"; OPTVAL_MAP = "Map"; OPTVAL_SCALETO640X400 = "Scale to 640x400"; OPTVAL_PIXELDOUBLE = "Pixel double"; +OPTVAL_PIXELQUADRUPLE = "Pixel quadruple"; OPTVAL_CURRENTWEAPON = "Current weapon"; OPTVAL_AVAILABLEWEAPONS = "Available weapons"; OPTVAL_ALLWEAPONS = "All weapons"; @@ -2235,6 +2236,7 @@ OPTVAL_ANIMATED = "Animated"; OPTVAL_ROTATED = "Rotated"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colors only"; OPTVAL_DOUBLE = "Double"; +OPTVAL_QUADRUPLE = "Quadruple"; OPTVAL_ITEMPICKUP = "Item Pickup"; OPTVAL_OBITUARIES = "Obituaries"; OPTVAL_CRITICALMESSAGES = "Critical Messages"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index c1f6fd805..d44a99d5a 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -764,7 +764,7 @@ OptionMenu "HUDOptions" Option "$HUDMNU_GROWCROSSHAIR", "crosshairgrow", "OnOff" ColorPicker "$HUDMNU_CROSSHAIRCOLOR", "crosshaircolor" Option "$HUDMNU_CROSSHAIRHEALTH", "crosshairhealth", "OnOff" - Option "$HUDMNU_CROSSHAIRSCALE", "crosshairscale", "OnOff" + Slider "$HUDMNU_CROSSHAIRSCALE", "crosshairscale", 0.0, 2.0, 0.05, 2 StaticText " " Option "$HUDMNU_NAMETAGS", "displaynametags", "DisplayTagsTypes" Option "$HUDMNU_NAMETAGCOLOR", "nametagcolor", "TextColors", "displaynametags" @@ -795,6 +795,7 @@ OptionValue "AltHUDScale" 0, "$OPTVAL_OFF" 1, "$OPTVAL_SCALETO640X400" 2, "$OPTVAL_PIXELDOUBLE" + 3, "$OPTVAL_PIXELQUADRUPLE" } OptionValue "AltHUDAmmo" @@ -1111,6 +1112,7 @@ OptionValue ScaleValues 0, "$OPTVAL_OFF" 1, "$OPTVAL_ON" 2, "$OPTVAL_DOUBLE" + 3, "$OPTVAL_QUADRUPLE" } OptionValue MessageLevels diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index 4db96f2da..90a41a4e8 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -251,3 +251,13 @@ enum 466 = 0, Floor_TransferTrigger(0) 467 = 0, Floor_TransferNumeric(0) 468 = 0, FloorAndCeiling_LowerRaise(0) +469 = 0, HealThing(0) +470 = 0, Sector_SetRotation(0) +471 = 0, Sector_SetFloorPanning(0) +472 = 0, Sector_SetCeilingPanning(0) +473 = 0, Light_MinNeighbor(0) +474 = 0, Polyobj_Stop(0) +475 = 0, Plat_RaiseAndStayTx0(0) +476 = 0, Plat_UpByValueStayTx(0) +477 = 0, ACS_ExecuteAlways(0) +478 = 0, Thing_Remove(0)