From b3d7980b909acab178c337ae536329b82c9f9f8e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Feb 2017 21:19:35 +0100 Subject: [PATCH 001/207] - fixed: PowerProtection clamped its damage minimum to 1, but should do it to 0. --- src/menu/menu.cpp | 1 + wadsrc/static/zscript/inventory/powerups.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 676057321e..a8dac6b540 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -270,6 +270,7 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) void DMenu::Close () { + if (DMenu::CurrentMenu == nullptr) return; // double closing can happen in the save menu. assert(DMenu::CurrentMenu == this); DMenu::CurrentMenu = mParentMenu; Destroy(); diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index d355a5e14f..828113ac8b 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1767,7 +1767,7 @@ class PowerProtection : Powerup { if (passive && damage > 0) { - newdamage = max(1, ApplyDamageFactors(GetClass(), damageType, damage, damage / 4)); + newdamage = max(0, ApplyDamageFactors(GetClass(), damageType, damage, damage / 4)); if (Owner != null && newdamage < damage) Owner.A_PlaySound(ActiveSound, CHAN_AUTO, 1.0, false, ATTN_NONE); } } From 4df2a221a8e41267d5576c49b05ba98cd7e058b9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Feb 2017 22:49:13 +0100 Subject: [PATCH 002/207] - fixed: The special called by the InterpolationSpecial actor must have no activator. This required splitting A_CallSpecial into a direct wrapper around P_ExecuteSpecial and implementing itself as a script function calling ExecuteSpecial so that this special case can use a version of the function that can be used without an activator. --- src/p_actionfunctions.cpp | 20 ---------------- src/p_lnspec.cpp | 24 +++++++++++++++++++ wadsrc/static/zscript/actor.txt | 6 ++++- wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/shared/movingcamera.txt | 2 +- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 40629bfcb2..15e82a56c5 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1410,26 +1410,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_RadiusDamageSelf) return 0; } -//========================================================================== -// -// Execute a line special / script -// -//========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_CallSpecial) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (special); - PARAM_INT_DEF (arg1); - PARAM_INT_DEF (arg2); - PARAM_INT_DEF (arg3); - PARAM_INT_DEF (arg4); - PARAM_INT_DEF (arg5); - - bool res = !!P_ExecuteSpecial(special, NULL, self, false, arg1, arg2, arg3, arg4, arg5); - - ACTION_RETURN_BOOL(res); -} - //========================================================================== // // The ultimate code pointer: Fully customizable missiles! diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index e71cf2f794..6f44cedcdd 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3717,3 +3717,27 @@ int P_ExecuteSpecial(int num, } return 0; } + +//========================================================================== +// +// Execute a line special / script +// +//========================================================================== +DEFINE_ACTION_FUNCTION(FLevelLocals, ExecuteSpecial) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_INT(special); + PARAM_OBJECT(activator, AActor); + PARAM_POINTER(linedef, line_t); + PARAM_BOOL(lineside); + PARAM_INT_DEF(arg1); + PARAM_INT_DEF(arg2); + PARAM_INT_DEF(arg3); + PARAM_INT_DEF(arg4); + PARAM_INT_DEF(arg5); + + bool res = !!P_ExecuteSpecial(special, linedef, activator, lineside, arg1, arg2, arg3, arg4, arg5); + + ACTION_RETURN_BOOL(res); +} + diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 5e2454ed25..0666fce8ba 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -737,7 +737,11 @@ class Actor : Thinker native native void A_VileChase(); native void A_BossDeath(); native void A_Detonate(); - native bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0); + bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0) + { + return Level.ExecuteSpecial(special, self, null, false, arg1, arg2, arg3, arg4, arg5); + } + native void A_ActiveSound(); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index bffee91f01..7b872f4729 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -469,6 +469,7 @@ struct LevelLocals native native String GetUDMFString(int type, int index, Name key); native int GetUDMFInt(int type, int index, Name key); native double GetUDMFFloat(int type, int index, Name key); + native bool ExecuteSpecial(int special, Actor activator, line linedef, bool lineside, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0, int arg5 = 0); } diff --git a/wadsrc/static/zscript/shared/movingcamera.txt b/wadsrc/static/zscript/shared/movingcamera.txt index 15fdd08368..c6af13b42f 100644 --- a/wadsrc/static/zscript/shared/movingcamera.txt +++ b/wadsrc/static/zscript/shared/movingcamera.txt @@ -311,7 +311,7 @@ class PathFollower : Actor while ( (spec = InterpolationSpecial(iterator.Next ())) ) { - A_CallSpecial(spec.special, spec.args[0], spec.args[1], spec.args[2], spec.args[3], spec.args[4]); + Level.ExecuteSpecial(spec.special, null, null, false, spec.args[0], spec.args[1], spec.args[2], spec.args[3], spec.args[4]); } } From 304e9894966e78902af1f9d084034c2c873de4a7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Feb 2017 23:06:24 +0100 Subject: [PATCH 003/207] - allow splashing on non-swimmable, non-solid 3D floors if they are marked liquid and have a splash assigned. --- src/p_trace.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 3597535e55..818372e745 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -41,6 +41,7 @@ #include "r_defs.h" #include "p_spec.h" #include "g_levellocals.h" +#include "p_terrain.h" //========================================================================== // @@ -135,6 +136,13 @@ static void GetPortalTransition(DVector3 &pos, sector_t *&sec) } } +static bool isLiquid(F3DFloor *ff) +{ + if (ff->flags & FF_SWIMMABLE) return true; + auto terrain = ff->model->GetTerrain(ff->flags & FF_INVERTPLANES ? sector_t::floor : sector_t::ceiling); + return Terrains[terrain].IsLiquid && Terrains[terrain].Splash != -1; +} + //========================================================================== // // Trace entry point @@ -300,9 +308,9 @@ void FTraceInfo::Setup3DFloors() if (!(rover->flags&FF_EXISTS)) continue; - if (rover->flags&FF_SWIMMABLE && Results->Crossed3DWater == NULL) + if (Results->Crossed3DWater == NULL) { - if (Check3DFloorPlane(rover, false)) + if (Check3DFloorPlane(rover, false) && isLiquid(rover)) { // only consider if the plane is above the actual floor. if (rover->top.plane->ZatPoint(Results->HitPos) > bf) @@ -767,7 +775,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) { for (auto rover : CurSector->e->XFloor.ffloors) { - if ((rover->flags & FF_EXISTS) && (rover->flags&FF_SWIMMABLE)) + if ((rover->flags & FF_EXISTS) && isLiquid(rover)) { if (Check3DFloorPlane(rover, false)) { From 59db1a882fe09983f534d20ba3343c3e9663938f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 16 Feb 2017 11:01:06 +0200 Subject: [PATCH 004/207] Fixed compilation warnings reported by MSVC src\s_sound.cpp(1259): warning C4244: 'argument': conversion from 'double' to 'float', possible loss of data src\c_bind.cpp(479): warning C4101: 'c': unreferenced local variable --- src/c_bind.cpp | 2 +- src/s_sound.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/c_bind.cpp b/src/c_bind.cpp index e6c76ab064..c21e200d38 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -476,7 +476,7 @@ DEFINE_ACTION_FUNCTION(FKeyBindings, GetKeysForCommand) { PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings); PARAM_STRING(cmd); - int k1, k2, c; + int k1, k2; self->GetKeysForCommand(cmd.GetChars(), &k1, &k2); if (numret > 0) ret[0].SetInt(k1); if (numret > 1) ret[1].SetInt(k2); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 5c0ae69e27..840559127a 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1256,7 +1256,7 @@ DEFINE_ACTION_FUNCTION(DObject, S_Sound) PARAM_INT(channel); PARAM_FLOAT_DEF(volume); PARAM_FLOAT_DEF(attn); - S_Sound(channel, id, volume, attn); + S_Sound(channel, id, static_cast(volume), static_cast(attn)); return 0; } From 4d99b58f968157000bfd7bf83b50c3c27adae198 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 17:45:04 +0100 Subject: [PATCH 005/207] - allow using the default menu settings classes when none is specified in MENUDEFS. --- src/dobjgc.cpp | 2 +- src/menu/menu.cpp | 10 ++++++++-- src/menu/menudef.cpp | 4 ++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 8ac991aa82..4fe609a5a0 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -544,7 +544,7 @@ void FullGC() void Barrier(DObject *pointing, DObject *pointed) { - assert(pointed->GetClass() < (void*)0x1000000000000000); + assert(pointed->GetClass() != nullptr); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointed->IsWhite() && !pointed->IsDead()); assert(State != GCS_Finalize && State != GCS_Pause); diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index a8dac6b540..c5b1b40714 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -94,6 +94,8 @@ float BackbuttonAlpha; static bool MenuEnabled = true; void M_InitVideoModes(); +extern PClass *DefaultListMenuClass; +extern PClass *DefaultOptionMenuClass; #define KEY_REPEAT_DELAY (TICRATE*5/12) @@ -623,7 +625,9 @@ void M_SetMenu(FName menu, int param) } else { - const PClass *cls = ld->mClass == nullptr? RUNTIME_CLASS(DListMenu) : ld->mClass; + PClass *cls = ld->mClass; + if (cls == nullptr) cls = DefaultListMenuClass; + if (cls == nullptr) cls = PClass::FindClass("ListMenu"); DListMenu *newmenu = (DListMenu *)cls->CreateNew(); newmenu->Init(DMenu::CurrentMenu, ld); @@ -633,7 +637,9 @@ void M_SetMenu(FName menu, int param) else if ((*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) { DOptionMenuDescriptor *ld = static_cast(*desc); - const PClass *cls = ld->mClass == nullptr? PClass::FindClass("OptionMenu") : ld->mClass; + PClass *cls = ld->mClass; + if (cls == nullptr) cls = DefaultOptionMenuClass; + if (cls == nullptr) cls = PClass::FindClass("OptionMenu"); DMenu *newmenu = (DMenu*)cls->CreateNew(); IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 057f544c5e..5ada8a2dca 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -62,6 +62,8 @@ static DOptionMenuDescriptor *DefaultOptionMenuSettings; // contains common sett FOptionMenuSettings OptionSettings; FOptionMap OptionValues; bool mustPrintErrors; +PClass *DefaultListMenuClass; +PClass *DefaultOptionMenuClass; void I_BuildALDeviceList(FOptionValues *opt); @@ -948,7 +950,9 @@ void M_ParseMenuDefs() } } } + DefaultListMenuClass = DefaultListMenuSettings->GetClass(); DefaultListMenuSettings = nullptr; + DefaultOptionMenuClass = DefaultOptionMenuSettings->GetClass(); DefaultOptionMenuSettings = nullptr; } From cfeb1724fea6cc47a5f75db6972be5ced8e6dbab Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 18:35:58 +0100 Subject: [PATCH 006/207] - added a Door_AnimatedClose special. --- src/actionspecials.h | 1 + src/menu/menu.h | 2 +- src/menu/menudef.cpp | 4 ++-- src/p_doors.cpp | 26 +++++++++++++++----------- src/p_lnspec.cpp | 9 ++++++++- src/p_spec.h | 14 +++++++++++--- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 3edb1671d3..42861b702c 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -259,5 +259,6 @@ DEFINE_SPECIAL(Stairs_BuildDownDoom, 270, 5, 5, 5) DEFINE_SPECIAL(Stairs_BuildUpDoomSync, 271, 4, 4, 4) DEFINE_SPECIAL(Stairs_BuildDownDoomSync, 272, 4, 4, 4) DEFINE_SPECIAL(Stairs_BuildUpDoomCrush, 273, 5, 5, 5) +DEFINE_SPECIAL(Door_AnimatedClose, 274, 4, 4, 4) #undef DEFINE_SPECIAL diff --git a/src/menu/menu.h b/src/menu/menu.h index ffc15e8808..68367e701b 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -112,7 +112,7 @@ class DMenuDescriptor : public DObject public: FName mMenuName; FString mNetgameMessage; - const PClass *mClass; + PClass *mClass; virtual size_t PropagateMark() { return 0; } }; diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 5ada8a2dca..ec1ae12b56 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -293,7 +293,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) else if (sc.Compare("Class")) { sc.MustGetString(); - const PClass *cls = PClass::FindClass(sc.String); + PClass *cls = PClass::FindClass(sc.String); if (cls == nullptr || !cls->IsDescendantOf(RUNTIME_CLASS(DListMenu))) { sc.ScriptError("Unknown menu class '%s'", sc.String); @@ -701,7 +701,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) else if (sc.Compare("Class")) { sc.MustGetString(); - const PClass *cls = PClass::FindClass(sc.String); + PClass *cls = PClass::FindClass(sc.String); if (cls == nullptr || !cls->IsDescendantOf("OptionMenu")) { sc.ScriptError("Unknown menu class '%s'", sc.String); diff --git a/src/p_doors.cpp b/src/p_doors.cpp index 3101be1c77..aff66cd740 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -538,7 +538,8 @@ void DAnimatedDoor::Serialize(FSerializer &arc) ("delay", m_Delay) ("dooranim", m_DoorAnim) ("setblock1", m_SetBlocking1) - ("setblock2", m_SetBlocking2); + ("setblock2", m_SetBlocking2) + ("tyoe", m_Type); } //============================================================================ @@ -614,7 +615,6 @@ void DAnimatedDoor::Tick () } m_Timer = m_Delay; - m_Status = Waiting; } else { @@ -631,7 +631,7 @@ void DAnimatedDoor::Tick () case Waiting: // IF DOOR IS DONE WAITING... - if (!m_Timer--) + if (m_Type == adClose || !m_Timer--) { if (!StartClosing()) { @@ -683,7 +683,7 @@ void DAnimatedDoor::Tick () // //============================================================================ -DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim) +DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim, DAnimatedDoor::EADType type) : DMovingCeiling (sec, false) { double topdist; @@ -717,7 +717,8 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, topdist = m_Sector->ceilingplane.fD() - topdist * m_Sector->ceilingplane.fC(); - m_Status = Opening; + m_Type = type; + m_Status = type == adClose? Waiting : Opening; m_Speed = speed; m_Delay = delay; m_Timer = m_Speed; @@ -728,9 +729,12 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, m_Line2->flags |= ML_BLOCKING; m_BotDist = m_Sector->ceilingplane.fD(); m_Sector->MoveCeiling (2048., topdist, 1); - if (m_DoorAnim->OpenSound != NAME_None) + if (type == adOpenClose) { - SN_StartSequence (m_Sector, CHAN_INTERIOR, m_DoorAnim->OpenSound, 1); + if (m_DoorAnim->OpenSound != NAME_None) + { + SN_StartSequence(m_Sector, CHAN_INTERIOR, m_DoorAnim->OpenSound, 1); + } } } @@ -741,7 +745,7 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, // //============================================================================ -bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) +bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay, DAnimatedDoor::EADType type) { sector_t *sec; int secnum; @@ -756,7 +760,7 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) sec = line->backsector; // Make sure door isn't already being animated - if (sec->ceilingdata != NULL) + if (sec->ceilingdata != NULL ) { if (actor->player == NULL) return false; @@ -774,7 +778,7 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) FDoorAnimation *anim = TexMan.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top)); if (anim != NULL) { - new DAnimatedDoor (sec, line, speed, delay, anim); + new DAnimatedDoor (sec, line, speed, delay, anim, type); return true; } return false; @@ -799,7 +803,7 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) if (anim != NULL) { rtn = true; - new DAnimatedDoor (sec, line, speed, delay, anim); + new DAnimatedDoor (sec, line, speed, delay, anim, type); break; } } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 6f44cedcdd..9cbb4aec1d 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -297,7 +297,13 @@ FUNC(LS_Door_Animated) if (arg3 != 0 && !P_CheckKeys (it, arg3, arg0 != 0)) return false; - return EV_SlidingDoor (ln, it, arg0, arg1, arg2); + return EV_SlidingDoor (ln, it, arg0, arg1, arg2, DAnimatedDoor::adOpenClose); +} + +FUNC(LS_Door_AnimatedClose) +// Door_AnimatedClose (tag, speed) +{ + return EV_SlidingDoor(ln, it, arg0, arg1, -1, DAnimatedDoor::adClose); } FUNC(LS_Generic_Door) @@ -3594,6 +3600,7 @@ static lnSpecFunc LineSpecials[] = /* 271 */ LS_Stairs_BuildUpDoomSync, /* 272 */ LS_Stairs_BuildDownDoomSync, /* 273 */ LS_Stairs_BuildUpDoomCrush, + /* 274 */ LS_Door_AnimatedClose, }; diff --git a/src/p_spec.h b/src/p_spec.h index c5e7b2f5c9..5cb8861e44 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -322,8 +322,15 @@ class DAnimatedDoor : public DMovingCeiling { DECLARE_CLASS (DAnimatedDoor, DMovingCeiling) public: + + enum EADType + { + adOpenClose, + adClose + }; + DAnimatedDoor (sector_t *sector); - DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim); + DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim, EADType type); void Serialize(FSerializer &arc); void Tick (); @@ -336,6 +343,7 @@ protected: int m_Timer; double m_BotDist; int m_Status; + int m_Type; enum { Opening, @@ -347,12 +355,12 @@ protected: int m_Delay; bool m_SetBlocking1, m_SetBlocking2; - friend bool EV_SlidingDoor (line_t *line, AActor *thing, int tag, int speed, int delay); + friend bool EV_SlidingDoor (line_t *line, AActor *thing, int tag, int speed, int delay, EADType type); private: DAnimatedDoor (); }; -bool EV_SlidingDoor (line_t *line, AActor *thing, int tag, int speed, int delay); +bool EV_SlidingDoor (line_t *line, AActor *thing, int tag, int speed, int delay, DAnimatedDoor::EADType type); // // P_CEILNG From ccb083ed25f47ace216399c2ac6125a97c548aaa Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 18:55:36 +0100 Subject: [PATCH 007/207] - fixed initialization of joystick menu with bogus MENUDEFS --- src/menu/joystickmenu.cpp | 10 +++++----- src/menu/menu.h | 2 +- src/menu/menudef.cpp | 4 ++-- wadsrc/static/menudef.txt | 7 ++++++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index f1015b79c1..9b16b90f41 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -138,9 +138,13 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, GetNumAxes) void UpdateJoystickMenu(IJoystickConfig *selected) { DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_JoystickOptions); + DMenuDescriptor **ddesc = MenuDescriptors.CheckKey("JoystickOptionsDefaults"); + if (ddesc == nullptr) return; // without any data the menu cannot be set up and must remain empty. if (desc != NULL && (*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) { DOptionMenuDescriptor *opt = (DOptionMenuDescriptor *)*desc; + DOptionMenuDescriptor *dopt = (DOptionMenuDescriptor *)*ddesc; + if (dopt == nullptr) return; DMenuItemBase *it; int i; @@ -162,11 +166,7 @@ void UpdateJoystickMenu(IJoystickConfig *selected) } } } -#ifdef _WIN32 - opt->mItems.Resize(8); -#else - opt->mItems.Resize(5); -#endif + opt->mItems = dopt->mItems; it = opt->GetItem("ConfigureMessage"); if (it != nullptr) it->SetValue(0, !!Joysticks.Size()); diff --git a/src/menu/menu.h b/src/menu/menu.h index 68367e701b..d272fe242a 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -112,7 +112,7 @@ class DMenuDescriptor : public DObject public: FName mMenuName; FString mNetgameMessage; - PClass *mClass; + PClass *mClass = nullptr; virtual size_t PropagateMark() { return 0; } }; diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index ec1ae12b56..8afed617e4 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -950,9 +950,9 @@ void M_ParseMenuDefs() } } } - DefaultListMenuClass = DefaultListMenuSettings->GetClass(); + DefaultListMenuClass = DefaultListMenuSettings->mClass; DefaultListMenuSettings = nullptr; - DefaultOptionMenuClass = DefaultOptionMenuSettings->GetClass(); + DefaultOptionMenuClass = DefaultOptionMenuSettings->mClass; DefaultOptionMenuSettings = nullptr; } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 3fba5fd6a0..d90d1851c9 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -558,7 +558,7 @@ OptionMenu "MouseOptions" // //------------------------------------------------------------------------------------------- -OptionMenu "JoystickOptions" +OptionMenu "JoystickOptionsDefaults" { Title "$JOYMNU_OPTIONS" Option "$JOYMNU_ENABLE", "use_joystick", "YesNo" @@ -576,6 +576,11 @@ OptionMenu "JoystickOptions" // The rest will be filled in by joystick code if devices get connected or disconnected } +OptionMenu "JoystickOptions" +{ + Title "$JOYMNU_OPTIONS" +} + OptionValue "JoyAxisMapNames" { -1, "$OPTVAL_NONE" From 944f2bf266db79349564ada1343ecd961e19142e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 19:29:07 +0100 Subject: [PATCH 008/207] - fixed armor save percentage values in Dehacked. --- src/d_dehacked.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 9cfd745203..7e2b22e277 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1942,13 +1942,13 @@ static int PatchMisc (int dummy) if (armor!=NULL) { armor->IntVar(NAME_SaveAmount) = 100 * deh.GreenAC; - armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 0.33335 : 0.5; + armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 33.335 : 50; } armor = GetDefaultByName ("BlueArmor"); if (armor!=NULL) { armor->IntVar(NAME_SaveAmount) = 100 * deh.BlueAC; - armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 0.33335 : 0.5; + armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 33.335 : 50; } auto barmor = GetDefaultByName ("ArmorBonus"); From 36e5bab657b7fa90ec35de60448a7eeafee2439e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 19:45:03 +0100 Subject: [PATCH 009/207] - removed the fixed search path for FMod on drive E: because this can cause problems with automated builds on unknown systems. This should never have been set up like this. --- src/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 84e1f576d7..c4e07aa73a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,8 +103,6 @@ if( WIN32 ) set( FMOD_SEARCH_PATHS "C:/Program Files/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" "C:/Program Files (x86)/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" - # This next one is for Randy. - "E:/Software/Dev/FMOD/${WIN_TYPE}/api" ) set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) From 1d5203777935890aaa639b43c9a8d350a8acf9a8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 21:01:52 +0100 Subject: [PATCH 010/207] - skip the Direct3D setup if building with a non-XP toolset on Visual Studio. --- src/CMakeLists.txt | 101 ++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4e07aa73a..b673b2c20e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -107,55 +107,62 @@ if( WIN32 ) set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) - find_path( D3D_INCLUDE_DIR d3d9.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT D3D_INCLUDE_DIR ) - # Modern versions of the Windows SDK include d3d9.h. Unfortunately, - # CMake cannot find this file via find_path, so we check for it using - # CHECK_INCLUDE_FILE. - CHECK_INCLUDE_FILE( d3d9.h D3D9_H_FOUND ) - if ( NOT D3D9_H_FOUND ) - message( SEND_ERROR "Could not find DirectX 9 header files" ) - endif() - else() - include_directories( ${D3D_INCLUDE_DIR} ) - endif() - - find_path( XINPUT_INCLUDE_DIR xinput.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT XINPUT_INCLUDE_DIR ) - # Modern versions of the Windows SDK include xinput.h. Unfortunately, - # CMake cannot find this file via find_path, so we check for it using - # CHECK_INCLUDE_FILES. windows.h must be included before xinput.h. - CHECK_INCLUDE_FILES( "windows.h;xinput.h" XINPUT_H_FOUND ) - if( NOT XINPUT_H_FOUND ) - message( WARNING "Could not find xinput.h. XInput will be disabled." ) - add_definitions( -DNO_XINPUT ) - endif() - else() - include_directories( ${XINPUT_INCLUDE_DIR} ) - endif() - - find_library( DX_dinput8_LIBRARY dinput8 - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - find_library( DX_dxguid_LIBRARY dxguid - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - - # Modern versions of the Windows SDK include dinput8.lib. Unfortunately, - # CMake cannot find these libraries via find_library. - if( NOT DX_dinput8_LIBRARY ) - # If we got this far, assume dinput8.lib is in the system library path. + if( ( MSVC14 AND NOT CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" ) OR # For VS 2015. + ( MSVC15 AND NOT CMAKE_GENERATOR_TOOLSET STREQUAL "v150_xp" ) ) # For VS 2017. + # for modern Windows SDKs the DirectX headers should be available by default. set( DX_dinput8_LIBRARY dinput8 ) - endif() + else() + + find_path( D3D_INCLUDE_DIR d3d9.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT D3D_INCLUDE_DIR ) + # Modern versions of the Windows SDK include d3d9.h. Unfortunately, + # CMake cannot find this file via find_path, so we check for it using + # CHECK_INCLUDE_FILE. + CHECK_INCLUDE_FILE( d3d9.h D3D9_H_FOUND ) + if ( NOT D3D9_H_FOUND ) + message( SEND_ERROR "Could not find DirectX 9 header files" ) + endif() + else() + include_directories( ${D3D_INCLUDE_DIR} ) + endif() + + find_path( XINPUT_INCLUDE_DIR xinput.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT XINPUT_INCLUDE_DIR ) + # Modern versions of the Windows SDK include xinput.h. Unfortunately, + # CMake cannot find this file via find_path, so we check for it using + # CHECK_INCLUDE_FILES. windows.h must be included before xinput.h. + CHECK_INCLUDE_FILES( "windows.h;xinput.h" XINPUT_H_FOUND ) + if( NOT XINPUT_H_FOUND ) + message( WARNING "Could not find xinput.h. XInput will be disabled." ) + add_definitions( -DNO_XINPUT ) + endif() + else() + include_directories( ${XINPUT_INCLUDE_DIR} ) + endif() - # Modern versions of the Windows SDK do NOT include dxguid.lib. Its contents - # were moved to dinput8.lib. - if( NOT DX_dxguid_LIBRARY ) - message( STATUS "Could not find dxguid.lib. Build may fail on old Windows SDKs.") + find_library( DX_dinput8_LIBRARY dinput8 + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + find_library( DX_dxguid_LIBRARY dxguid + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + + # Modern versions of the Windows SDK include dinput8.lib. Unfortunately, + # CMake cannot find these libraries via find_library. + if( NOT DX_dinput8_LIBRARY ) + # If we got this far, assume dinput8.lib is in the system library path. + set( DX_dinput8_LIBRARY dinput8 ) + endif() + + # Modern versions of the Windows SDK do NOT include dxguid.lib. Its contents + # were moved to dinput8.lib. + if( NOT DX_dxguid_LIBRARY ) + message( STATUS "Could not find dxguid.lib. Build may fail on old Windows SDKs.") + endif() endif() set( ZDOOM_LIBS From b523aa13c8bd1b2aaef8ef05b57c1cf99fcc6f40 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 21:51:32 +0100 Subject: [PATCH 011/207] - fixed crash with bad state labels. --- src/scripting/backend/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index db7d7425fe..252788023a 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -1530,7 +1530,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) SAFE_RESOLVE(basex, ctx); // first deal with the simple types - if (ValueType == TypeError || basex->ValueType == TypeError) + if (ValueType == TypeError || basex->ValueType == TypeError || basex->ValueType == nullptr) { ScriptPosition.Message(MSG_ERROR, "Trying to cast to invalid type."); delete this; From 18925d07beb6cb0f8d2890eb40c7fcc7c2a63c3f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 16 Feb 2017 23:17:19 +0100 Subject: [PATCH 012/207] - fixed a typo. --- src/p_doors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_doors.cpp b/src/p_doors.cpp index aff66cd740..05c93a8989 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -539,7 +539,7 @@ void DAnimatedDoor::Serialize(FSerializer &arc) ("dooranim", m_DoorAnim) ("setblock1", m_SetBlocking1) ("setblock2", m_SetBlocking2) - ("tyoe", m_Type); + ("type", m_Type); } //============================================================================ From 74c474859324623fc1859125f8937e536c4b5d84 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 12:10:10 +0100 Subject: [PATCH 013/207] - fixed the message switch for the controls menu. --- wadsrc/static/zscript/menu/optionmenuitems.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/menu/optionmenuitems.txt b/wadsrc/static/zscript/menu/optionmenuitems.txt index 8efe0cfb91..4d61edcd0a 100644 --- a/wadsrc/static/zscript/menu/optionmenuitems.txt +++ b/wadsrc/static/zscript/menu/optionmenuitems.txt @@ -388,7 +388,7 @@ class EnterKey : Menu let parent = OptionMenu(mParentMenu); if (parent != null) { - let it = parent.GetItem('Controlmessage'); + let it = parent.mDesc.GetItem('Controlmessage'); if (it != null) { it.SetValue(0, which); From 416911587ee5d77c73ccc44c7b20bdb615ac408b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 16:53:36 +0100 Subject: [PATCH 014/207] - scriptified PlayerMenu.Drawer --- src/menu/playermenu.cpp | 38 ++--------------------- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/menu/playermenu.txt | 25 +++++++++++++++ 3 files changed, 28 insertions(+), 36 deletions(-) create mode 100644 wadsrc/static/zscript/menu/playermenu.txt diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 3a13760529..ce657feae7 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -65,6 +65,7 @@ class DPlayerMenu : public DListMenu { DECLARE_CLASS(DPlayerMenu, DListMenu) +public: int PlayerClassIndex; FPlayerClass *PlayerClass; TArray PlayerColorSets; @@ -91,8 +92,6 @@ public: bool Responder (event_t *ev); bool MenuEvent (int mkey, bool fromcontroller); bool MouseEvent(int type, int x, int y); - void Ticker (); - void Drawer (); }; IMPLEMENT_CLASS(DPlayerMenu, false, false) @@ -693,38 +692,5 @@ bool DPlayerMenu::MouseEvent(int type, int x, int y) return res; } -//============================================================================= -// -// -// -//============================================================================= -void DPlayerMenu::Ticker () -{ - - Super::Ticker(); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DPlayerMenu::Drawer () -{ - - Super::Drawer(); - - const char *str = "PRESS " TEXTCOLOR_WHITE "SPACE"; - screen->DrawText (SmallFont, CR_GOLD, 320 - 32 - 32 - - SmallFont->StringWidth (str)/2, - 50 + 48 + 70, str, - DTA_Clean, true, TAG_DONE); - str = mRotation ? "TO SEE FRONT" : "TO SEE BACK"; - screen->DrawText (SmallFont, CR_GOLD, 320 - 32 - 32 - - SmallFont->StringWidth (str)/2, - 50 + 48 + 70 + SmallFont->GetHeight (), str, - DTA_Clean, true, TAG_DONE); - -} +DEFINE_FIELD(DPlayerMenu, mRotation) diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index d755c85b97..ae582e058e 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -15,6 +15,7 @@ #include "zscript/menu/optionmenuitems.txt" #include "zscript/menu/colorpickermenu.txt" #include "zscript/menu/joystickmenu.txt" +#include "zscript/menu/playermenu.txt" #include "zscript/menu/playerdisplay.txt" #include "zscript/menu/playercontrols.txt" #include "zscript/menu/textentermenu.txt" diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt new file mode 100644 index 0000000000..c8f5373405 --- /dev/null +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -0,0 +1,25 @@ + + +class PlayerMenu : ListMenu native +{ + native int mRotation; + + //============================================================================= + // + // + // + //============================================================================= + + override void Drawer () + { + + Super.Drawer(); + + String str = "PRESS " .. TEXTCOLOR_WHITE .. "SPACE"; + screen.DrawText (SmallFont, Font.CR_GOLD, 320 - 32 - 32 - SmallFont.StringWidth (str)/2, 50 + 48 + 70, str, DTA_Clean, true); + str = mRotation ? "TO SEE FRONT" : "TO SEE BACK"; + screen.DrawText (SmallFont, Font.CR_GOLD, 320 - 32 - 32 - SmallFont.StringWidth (str)/2, 50 + 48 + 70 + SmallFont.GetHeight (), str, DTA_Clean, true); + + } + +} \ No newline at end of file From f4e9cd000999cb55f8fe474d32d350cb2e22e045 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 18:21:59 +0100 Subject: [PATCH 015/207] - scriptified DPlayerMenu::MouseEvent. --- src/menu/playermenu.cpp | 108 +++++++--------------- src/p_user.cpp | 14 +++ wadsrc/static/zscript/menu/playermenu.txt | 70 +++++++++++++- wadsrc/static/zscript/shared/player.txt | 3 + 4 files changed, 119 insertions(+), 76 deletions(-) diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index ce657feae7..8049349d97 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -91,7 +91,6 @@ public: void Init(DMenu *parent, DListMenuDescriptor *desc); bool Responder (event_t *ev); bool MenuEvent (int mkey, bool fromcontroller); - bool MouseEvent(int type, int x, int y); }; IMPLEMENT_CLASS(DPlayerMenu, false, false) @@ -278,30 +277,18 @@ void DPlayerMenu::UpdateTranslation() void DPlayerMenu::PickPlayerClass() { + int pclass = 0; + // [GRB] Pick a class from player class list + if (PlayerClasses.Size () > 1) + { + pclass = players[consoleplayer].userinfo.GetPlayerClassNum(); - /* - // What's the point of this? Aren't we supposed to edit the - // userinfo? - if (players[consoleplayer].mo != NULL) - { - PlayerClassIndex = players[consoleplayer].CurrentPlayerClass; - } - else - */ - { - int pclass = 0; - // [GRB] Pick a class from player class list - if (PlayerClasses.Size () > 1) + if (pclass < 0) { - pclass = players[consoleplayer].userinfo.GetPlayerClassNum(); - - if (pclass < 0) - { - pclass = (MenuTime>>7) % PlayerClasses.Size (); - } + pclass = (MenuTime>>7) % PlayerClasses.Size (); } - PlayerClassIndex = pclass; } + PlayerClassIndex = pclass; PlayerClass = &PlayerClasses[PlayerClassIndex]; UpdateTranslation(); } @@ -314,14 +301,25 @@ void DPlayerMenu::PickPlayerClass() void DPlayerMenu::SendNewColor (int red, int green, int blue) { - char command[24]; - players[consoleplayer].userinfo.ColorChanged(MAKERGB(red,green,blue)); - mysnprintf (command, countof(command), "color \"%02x %02x %02x\"", red, green, blue); - C_DoCommand (command); UpdateTranslation(); } +DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) +{ + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_INT(r); + PARAM_INT(g); + PARAM_INT(b); + // only allow if the menu is active to prevent abuse. + if (self == DMenu::CurrentMenu) + { + players[consoleplayer].userinfo.ColorChanged(MAKERGB(r, g, b)); + } + return 0; +} + + //============================================================================= // // @@ -456,10 +454,7 @@ void DPlayerMenu::ColorSetChanged (DMenuItemBase *li) if (green != NULL) green->Enable(mycolorset == -1); if (blue != NULL) blue->Enable(mycolorset == -1); - char command[24]; players[consoleplayer].userinfo.ColorSetChanged(mycolorset); - mysnprintf(command, countof(command), "colorset %d", mycolorset); - C_DoCommand(command); UpdateTranslation(); } } @@ -545,6 +540,17 @@ void DPlayerMenu::AutoaimChanged (DMenuItemBase *li) } } +DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) +{ + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_FLOAT(val); + // only allow if the menu is active to prevent abuse. + if (self == DMenu::CurrentMenu) + { + autoaim = float(val); + } + return 0; +} //============================================================================= // // @@ -648,49 +654,5 @@ bool DPlayerMenu::MenuEvent (int mkey, bool fromcontroller) return Super::MenuEvent(mkey, fromcontroller); } - -bool DPlayerMenu::MouseEvent(int type, int x, int y) -{ - int v; - DMenuItemBase *li = mFocusControl; - bool res = Super::MouseEvent(type, x, y); - if (li == NULL) li = mFocusControl; - if (li != NULL) - { - // Check if the colors have changed - FName current = li->GetAction(NULL); - switch(current) - { - case NAME_Red: - if (li->GetValue(0, &v)) - { - uint32 color = players[consoleplayer].userinfo.GetColor(); - SendNewColor (v, GPART(color), BPART(color)); - } - break; - - case NAME_Green: - if (li->GetValue(0, &v)) - { - uint32 color = players[consoleplayer].userinfo.GetColor(); - SendNewColor (RPART(color), v, BPART(color)); - } - break; - - case NAME_Blue: - if (li->GetValue(0, &v)) - { - uint32 color = players[consoleplayer].userinfo.GetColor(); - SendNewColor (RPART(color), GPART(color), v); - } - break; - case NAME_Autoaim: - AutoaimChanged(li); - break; - } - } - return res; -} - - DEFINE_FIELD(DPlayerMenu, mRotation) +DEFINE_FIELD_NAMED(DPlayerMenu, PlayerClass, mPlayerClass) diff --git a/src/p_user.cpp b/src/p_user.cpp index eea26cc4b1..8fc334d70e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -163,6 +163,13 @@ FString GetPrintableDisplayName(PClassActor *cls) return cls->DisplayName; } +DEFINE_ACTION_FUNCTION(APlayerPawn, GetPrintableDisplayName) +{ + PARAM_PROLOGUE; + PARAM_CLASS(type, AActor); + ACTION_RETURN_STRING(type->DisplayName); +} + bool ValidatePlayerClass(PClassActor *ti, const char *name) { if (ti == NULL) @@ -654,6 +661,13 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetNeverSwitch) ACTION_RETURN_BOOL(self->userinfo.GetNeverSwitch()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_INT(self->userinfo.GetColor()); +} + + //=========================================================================== // // APlayerPawn diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index c8f5373405..0226b58495 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -1,8 +1,74 @@ - class PlayerMenu : ListMenu native { native int mRotation; + native PlayerClass mPlayerClass; + + protected native void AutoaimChanged(float val); + protected native void ColorChanged(int red, int green, int blue); + + protected void UpdateTranslation() + { + Translation.SetPlayerTranslation(TRANSLATION_Players, MAXPLAYERS, consoleplayer, mPlayerClass); + } + + protected void SendNewColor (int red, int green, int blue) + { + ColorChanged(red, green, blue); + UpdateTranslation(); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + let li = mFocusControl; + bool res = Super.MouseEvent(type, x, y); + if (li == NULL) li = mFocusControl; + if (li != NULL) + { + // Check if the colors have changed + Name ctrl = li.GetAction(); + bool resv; + int v; + [resv, v]= li.GetValue(0); + switch(ctrl) + { + case 'Red': + if (resv) + { + Color colr = players[consoleplayer].GetColor(); + SendNewColor (v, colr.g, colr.b); + } + break; + + case 'Green': + if (resv) + { + Color colr = players[consoleplayer].GetColor(); + SendNewColor (colr.r, v, colr.b); + } + break; + + case 'Blue': + if (resv) + { + Color colr = players[consoleplayer].GetColor(); + SendNewColor (colr.r, colr.g, v); + } + break; + case 'Autoaim': + AutoaimChanged(v); + break; + } + } + return res; + } + //============================================================================= // @@ -12,9 +78,7 @@ class PlayerMenu : ListMenu native override void Drawer () { - Super.Drawer(); - String str = "PRESS " .. TEXTCOLOR_WHITE .. "SPACE"; screen.DrawText (SmallFont, Font.CR_GOLD, 320 - 32 - 32 - SmallFont.StringWidth (str)/2, 50 + 48 + 70, str, DTA_Clean, true); str = mRotation ? "TO SEE FRONT" : "TO SEE BACK"; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 9039b37b6b..28ed4826b6 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -136,6 +136,8 @@ class PlayerPawn : Actor native native int GetMaxHealth(); native bool ResetAirSupply (bool playgasp = false); native void CheckWeaponSwitch(class item); + native static String GetPrintableDisplayName(Class cls); + } class PlayerChunk : PlayerPawn @@ -308,6 +310,7 @@ userinfo_t userinfo; native void SetLogNumber (int text); native void SetLogText (String text); native String GetUserName(); + native Color GetColor(); native bool GetNeverSwitch(); native void DropWeapon(); native void BringUpWeapon(); From 51493cde8cc8aca702df2dd7d797d7646a73f27d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 20:02:26 +0100 Subject: [PATCH 016/207] - scriptified DPlayerMenu::MenuEvent. --- src/menu/playermenu.cpp | 241 ++++++++++------------ wadsrc/static/zscript/menu/playermenu.txt | 147 +++++++++++++ 2 files changed, 254 insertions(+), 134 deletions(-) diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 8049349d97..21498ec2c1 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -81,7 +81,6 @@ public: void PlayerNameChanged(DMenuItemBase *li); void ColorSetChanged (DMenuItemBase *li); void ClassChanged (DMenuItemBase *li); - void AutoaimChanged (DMenuItemBase *li); void SkinChanged (DMenuItemBase *li); @@ -90,7 +89,6 @@ public: DPlayerMenu() {} void Init(DMenu *parent, DListMenuDescriptor *desc); bool Responder (event_t *ev); - bool MenuEvent (int mkey, bool fromcontroller); }; IMPLEMENT_CLASS(DPlayerMenu, false, false) @@ -403,20 +401,22 @@ void DPlayerMenu::UpdateSkins() //============================================================================= // -// +// access to the player config is done natively, so that broader access +// functions do not need to be exported. // //============================================================================= -void DPlayerMenu::PlayerNameChanged(DMenuItemBase *li) +DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) { - char pp[MAXPLAYERNAME+1]; - const char *p; - if (li->GetString(0, pp, MAXPLAYERNAME)) - { - FString command("name \""); + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_STRING(s); + const char *pp = s; + FString command("name \""); + if (self == DMenu::CurrentMenu) + { // Escape any backslashes or quotation marks before sending the name to the console. - for (p = pp; *p != '\0'; ++p) + for (auto p = pp; *p != '\0'; ++p) { if (*p == '"' || *p == '\\') { @@ -425,8 +425,9 @@ void DPlayerMenu::PlayerNameChanged(DMenuItemBase *li) command << *p; } command << '"'; - C_DoCommand (command); + C_DoCommand(command); } + return 0; } //============================================================================= @@ -435,28 +436,15 @@ void DPlayerMenu::PlayerNameChanged(DMenuItemBase *li) // //============================================================================= -void DPlayerMenu::ColorSetChanged (DMenuItemBase *li) +DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) { - int sel; - - if (li->GetValue(0, &sel)) + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_INT(sel); + if (self == DMenu::CurrentMenu) { - int mycolorset = -1; - - if (sel > 0) mycolorset = PlayerColorSets[sel-1]; - - DMenuItemBase *red = GetItem(NAME_Red); - DMenuItemBase *green = GetItem(NAME_Green); - DMenuItemBase *blue = GetItem(NAME_Blue); - - // disable the sliders if a valid colorset is selected - if (red != NULL) red->Enable(mycolorset == -1); - if (green != NULL) green->Enable(mycolorset == -1); - if (blue != NULL) blue->Enable(mycolorset == -1); - - players[consoleplayer].userinfo.ColorSetChanged(mycolorset); - UpdateTranslation(); + players[consoleplayer].userinfo.ColorSetChanged(sel); } + return 0; } //============================================================================= @@ -493,6 +481,18 @@ void DPlayerMenu::ClassChanged (DMenuItemBase *li) } } +DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) +{ + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_OBJECT(sel, DMenuItemBase); + if (self == DMenu::CurrentMenu) + { + self->ClassChanged(sel); + } + return 0; +} + + //============================================================================= // // @@ -514,7 +514,6 @@ void DPlayerMenu::SkinChanged (DMenuItemBase *li) sel = PlayerSkins[sel]; players[consoleplayer].userinfo.SkinNumChanged(sel); UpdateTranslation(); - cvar_set ("skin", skins[sel].name); li = GetItem(NAME_Playerdisplay); if (li != NULL) @@ -524,22 +523,24 @@ void DPlayerMenu::SkinChanged (DMenuItemBase *li) } } -//============================================================================= -// -// -// -//============================================================================= - -void DPlayerMenu::AutoaimChanged (DMenuItemBase *li) +DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) { - int sel; - - if (li->GetValue(0, &sel)) + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_OBJECT(sel, DMenuItemBase); + if (self == DMenu::CurrentMenu) { - autoaim = (float)sel; + self->SkinChanged(sel); } + return 0; } + +//============================================================================= +// +// +// +//============================================================================= + DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) { PARAM_SELF_PROLOGUE(DPlayerMenu); @@ -551,108 +552,80 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) } return 0; } + //============================================================================= // // // //============================================================================= -bool DPlayerMenu::MenuEvent (int mkey, bool fromcontroller) +DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged) { - int v; - if (mDesc->mSelectedItem >= 0) + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_INT(val); + // only allow if the menu is active to prevent abuse. + if (self == DMenu::CurrentMenu) { - DMenuItemBase *li = mDesc->mItems[mDesc->mSelectedItem]; - if (li->MenuEvent(mkey, fromcontroller)) - { - FName current = li->GetAction(NULL); - switch(current) - { - // item specific handling comes here - - case NAME_Playerbox: - if (mkey == MKEY_Input) - { - PlayerNameChanged(li); - } - break; - - case NAME_Team: - if (li->GetValue(0, &v)) - { - team = v==0? TEAM_NONE : v-1; - } - break; - - case NAME_Color: - ColorSetChanged(li); - break; - - case NAME_Red: - if (li->GetValue(0, &v)) - { - uint32 color = players[consoleplayer].userinfo.GetColor(); - SendNewColor (v, GPART(color), BPART(color)); - } - break; - - case NAME_Green: - if (li->GetValue(0, &v)) - { - uint32 color = players[consoleplayer].userinfo.GetColor(); - SendNewColor (RPART(color), v, BPART(color)); - } - break; - - case NAME_Blue: - if (li->GetValue(0, &v)) - { - uint32 color = players[consoleplayer].userinfo.GetColor(); - SendNewColor (RPART(color), GPART(color), v); - } - break; - - case NAME_Class: - ClassChanged(li); - break; - - case NAME_Skin: - SkinChanged(li); - break; - - case NAME_Gender: - if (li->GetValue(0, &v)) - { - cvar_set ("gender", v==0? "male" : v==1? "female" : "other"); - } - break; - - case NAME_Autoaim: - AutoaimChanged(li); - break; - - case NAME_Switch: - if (li->GetValue(0, &v)) - { - neverswitchonpickup = !!v; - } - break; - - case NAME_AlwaysRun: - if (li->GetValue(0, &v)) - { - cl_run = !!v; - } - break; - - default: - break; - } - return true; - } + team = val == 0 ? TEAM_NONE : val - 1; } - return Super::MenuEvent(mkey, fromcontroller); + return 0; } +//============================================================================= +// +// +// +//============================================================================= + +DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged) +{ + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_INT(v); + // only allow if the menu is active to prevent abuse. + if (self == DMenu::CurrentMenu) + { + cvar_set("gender", v == 0 ? "male" : v == 1 ? "female" : "other"); + } + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged) +{ + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_INT(v); + // only allow if the menu is active to prevent abuse. + if (self == DMenu::CurrentMenu) + { + neverswitchonpickup = !!v; + } + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged) +{ + PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_INT(v); + // only allow if the menu is active to prevent abuse. + if (self == DMenu::CurrentMenu) + { + cl_run = !!v; + } + return 0; +} + + DEFINE_FIELD(DPlayerMenu, mRotation) DEFINE_FIELD_NAMED(DPlayerMenu, PlayerClass, mPlayerClass) +DEFINE_FIELD(DPlayerMenu, PlayerColorSets) diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index 0226b58495..3b08480804 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -3,9 +3,20 @@ class PlayerMenu : ListMenu native { native int mRotation; native PlayerClass mPlayerClass; + native Array PlayerColorSets; + // All write function for the player config are native to prevent abuse. protected native void AutoaimChanged(float val); + protected native void TeamChanged(int val); + protected native void AlwaysRunChanged(int val); + protected native void GenderChanged(int val); + protected native void SwitchOnPickupChanged(int val); protected native void ColorChanged(int red, int green, int blue); + protected native void ColorSetChanged(int red); + protected native void PlayerNameChanged(String name); + + protected native void ClassChanged(ListMenuItem it); + protected native void SkinChanged (ListMenuItem li); protected void UpdateTranslation() { @@ -24,6 +35,142 @@ class PlayerMenu : ListMenu native // //============================================================================= + override bool MenuEvent (int mkey, bool fromcontroller) + { + int v; + bool res; + String s; + if (mDesc.mSelectedItem >= 0) + { + let li = mDesc.mItems[mDesc.mSelectedItem]; + if (li.MenuEvent(mkey, fromcontroller)) + { + Name ctrl = li.GetAction(); + switch(ctrl) + { + // item specific handling comes here + + case 'Playerbox': + if (mkey == MKEY_Input) + { + [res, s] = li.GetString(0); + if (res) PlayerNameChanged(s); + } + break; + + case 'Team': + [res, v] = li.GetValue(0); + if (res) TeamChanged(v); + break; + + case 'Color': + [res, v] = li.GetValue(0); + if (res) + { + int mycolorset = -1; + + if (v > 0) mycolorset = PlayerColorSets[v - 1]; + + let red = GetItem('Red'); + let green = GetItem('Green'); + let blue = GetItem('Blue'); + + // disable the sliders if a valid colorset is selected + if (red != NULL) red.Enable(mycolorset == -1); + if (green != NULL) green.Enable(mycolorset == -1); + if (blue != NULL) blue.Enable(mycolorset == -1); + + ColorSetChanged(v - 1); + UpdateTranslation(); + } + break; + + case 'Red': + [res, v] = li.GetValue(0); + if (res) + { + Color colr = players[consoleplayer].GetColor(); + SendNewColor (v, colr.g, colr.b); + } + break; + + case 'Green': + [res, v] = li.GetValue(0); + if (res) + { + Color colr = players[consoleplayer].GetColor(); + SendNewColor (colr.r, v, colr.b); + } + break; + + case 'Blue': + [res, v] = li.GetValue(0); + if (res) + { + Color colr = players[consoleplayer].GetColor(); + SendNewColor (colr.r, colr.g, v); + } + break; + + case 'Class': + [res, v] = li.GetValue(0); + if (res) + { + ClassChanged(li); + } + break; + + case 'Skin': + SkinChanged(li); + break; + + case 'Gender': + [res, v] = li.GetValue(0); + if (res) + { + GenderChanged(v); + } + break; + + case 'Autoaim': + [res, v] = li.GetValue(0); + if (res) + { + AutoaimChanged(v); + } + break; + + case 'Switch': + [res, v] = li.GetValue(0); + if (res) + { + SwitchOnPickupChanged(v); + } + break; + + case 'AlwaysRun': + [res, v] = li.GetValue(0); + if (res) + { + AlwaysRunChanged(v); + } + break; + + default: + break; + } + return true; + } + } + return Super.MenuEvent(mkey, fromcontroller); + } + + //============================================================================= + // + // + // + //============================================================================= + override bool MouseEvent(int type, int x, int y) { let li = mFocusControl; From b375657509f9f7f6a2d50fc3cc2aa126507e69e1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 20:49:04 +0100 Subject: [PATCH 017/207] - scriptified DPlayerMenu::SkinChanged. --- src/menu/playermenu.cpp | 30 ++---------------- src/p_user.cpp | 6 ++++ wadsrc/static/zscript/menu/playermenu.txt | 38 +++++++++++++++++++++-- wadsrc/static/zscript/shared/player.txt | 1 + 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 21498ec2c1..03e84ecbf9 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -499,42 +499,17 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) // //============================================================================= -void DPlayerMenu::SkinChanged (DMenuItemBase *li) -{ - if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN || - players[consoleplayer].userinfo.GetPlayerClassNum() == -1) - { - return; - } - - int sel; - - if (li->GetValue(0, &sel)) - { - sel = PlayerSkins[sel]; - players[consoleplayer].userinfo.SkinNumChanged(sel); - UpdateTranslation(); - - li = GetItem(NAME_Playerdisplay); - if (li != NULL) - { - li->SetValue(ListMenuItemPlayerDisplay_PDF_SKIN, sel); - } - } -} - DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) { PARAM_SELF_PROLOGUE(DPlayerMenu); - PARAM_OBJECT(sel, DMenuItemBase); + PARAM_INT(sel); if (self == DMenu::CurrentMenu) { - self->SkinChanged(sel); + players[consoleplayer].userinfo.SkinNumChanged(sel); } return 0; } - //============================================================================= // // @@ -629,3 +604,4 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged) DEFINE_FIELD(DPlayerMenu, mRotation) DEFINE_FIELD_NAMED(DPlayerMenu, PlayerClass, mPlayerClass) DEFINE_FIELD(DPlayerMenu, PlayerColorSets) +DEFINE_FIELD(DPlayerMenu, PlayerSkins) diff --git a/src/p_user.cpp b/src/p_user.cpp index 8fc334d70e..5816a96897 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -667,6 +667,12 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetColor) ACTION_RETURN_INT(self->userinfo.GetColor()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetPlayerClassNum) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_INT(self->userinfo.GetPlayerClassNum()); +} + //=========================================================================== // diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index 3b08480804..4463bcea2c 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -4,6 +4,7 @@ class PlayerMenu : ListMenu native native int mRotation; native PlayerClass mPlayerClass; native Array PlayerColorSets; + native Array PlayerSkins; // All write function for the player config are native to prevent abuse. protected native void AutoaimChanged(float val); @@ -14,9 +15,9 @@ class PlayerMenu : ListMenu native protected native void ColorChanged(int red, int green, int blue); protected native void ColorSetChanged(int red); protected native void PlayerNameChanged(String name); + protected native void SkinChanged (int val); protected native void ClassChanged(ListMenuItem it); - protected native void SkinChanged (ListMenuItem li); protected void UpdateTranslation() { @@ -29,6 +30,39 @@ class PlayerMenu : ListMenu native UpdateTranslation(); } + + //============================================================================= + // + // + // + //============================================================================= + + protected void ChangeSkin (MenuItemBase li) + { + if (GetDefaultByType (mPlayerClass.Type).bNoSkin || players[consoleplayer].GetPlayerClassNum() == -1) + { + return; + } + + bool res; + int sel; + + [res, sel] = li.GetValue(0); + if (res) + { + sel = PlayerSkins[sel]; + SkinChanged(sel); + UpdateTranslation(); + + li = GetItem('Playerdisplay'); + if (li != NULL) + { + li.SetValue(ListMenuItemPlayerDisplay.PDF_SKIN, sel); + } + } + } + + //============================================================================= // // @@ -121,7 +155,7 @@ class PlayerMenu : ListMenu native break; case 'Skin': - SkinChanged(li); + ChangeSkin(li); break; case 'Gender': diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 28ed4826b6..24bfa51c60 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -311,6 +311,7 @@ userinfo_t userinfo; native void SetLogText (String text); native String GetUserName(); native Color GetColor(); + native int GetPlayerClassNum(); native bool GetNeverSwitch(); native void DropWeapon(); native void BringUpWeapon(); From 6a2525b737fb4ea4d0a1d0e36eb93ce65a04d65a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 20:58:11 +0100 Subject: [PATCH 018/207] - scriptified PickPlayerClass. --- src/menu/playermenu.cpp | 8 +------ wadsrc/static/zscript/menu/playermenu.txt | 26 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 03e84ecbf9..daa18d57b6 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -76,7 +76,6 @@ public: void UpdateColorsets(); void UpdateSkins(); void UpdateTranslation(); - void SendNewColor (int red, int green, int blue); void PlayerNameChanged(DMenuItemBase *li); void ColorSetChanged (DMenuItemBase *li); @@ -297,12 +296,6 @@ void DPlayerMenu::PickPlayerClass() // //============================================================================= -void DPlayerMenu::SendNewColor (int red, int green, int blue) -{ - players[consoleplayer].userinfo.ColorChanged(MAKERGB(red,green,blue)); - UpdateTranslation(); -} - DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) { PARAM_SELF_PROLOGUE(DPlayerMenu); @@ -605,3 +598,4 @@ DEFINE_FIELD(DPlayerMenu, mRotation) DEFINE_FIELD_NAMED(DPlayerMenu, PlayerClass, mPlayerClass) DEFINE_FIELD(DPlayerMenu, PlayerColorSets) DEFINE_FIELD(DPlayerMenu, PlayerSkins) +DEFINE_FIELD(DPlayerMenu, PlayerClassIndex) diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index 4463bcea2c..0ac5328a03 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -2,6 +2,7 @@ class PlayerMenu : ListMenu native { native int mRotation; + native int PlayerClassIndex; native PlayerClass mPlayerClass; native Array PlayerColorSets; native Array PlayerSkins; @@ -30,7 +31,30 @@ class PlayerMenu : ListMenu native UpdateTranslation(); } - + //============================================================================= + // + // + // + //============================================================================= + + protected void PickPlayerClass() + { + int pclass = 0; + // [GRB] Pick a class from player class list + if (PlayerClasses.Size () > 1) + { + pclass = players[consoleplayer].GetPlayerClassNum(); + + if (pclass < 0) + { + pclass = (MenuTime() >> 7) % PlayerClasses.Size (); + } + } + PlayerClassIndex = pclass; + mPlayerClass = PlayerClasses[PlayerClassIndex]; + UpdateTranslation(); + } + //============================================================================= // // From 498da825a514ea2ba2b9916d8305ba874ad46ce2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 21:51:23 +0100 Subject: [PATCH 019/207] - made the Skins array scripting friendly and exported it. --- src/d_netinfo.cpp | 8 +- src/g_game.cpp | 2 +- src/g_shared/a_morph.cpp | 2 +- src/g_statusbar/sbar_mugshot.cpp | 2 +- src/intermission/intermission.cpp | 4 +- src/menu/playermenu.cpp | 8 +- src/p_actionfunctions.cpp | 2 +- src/p_mobj.cpp | 10 +- src/p_saveg.cpp | 2 +- src/p_setup.cpp | 1 - src/p_states.cpp | 6 +- src/p_user.cpp | 14 +-- src/r_data/r_translate.cpp | 6 +- src/r_data/sprites.cpp | 140 ++++++++++++------------ src/r_data/sprites.h | 24 ++-- src/scripting/thingdef_data.cpp | 9 ++ wadsrc/static/zscript/shared/player.txt | 14 +++ 17 files changed, 136 insertions(+), 118 deletions(-) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 62beb54601..8a856b44b2 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -729,7 +729,7 @@ void D_WriteUserInfoStrings (int pnum, BYTE **stream, bool compact) break; case NAME_Skin: - *stream += sprintf(*((char **)stream), "\\%s", D_EscapeUserInfo(skins[info->GetSkin()].name).GetChars()); + *stream += sprintf(*((char **)stream), "\\%s", D_EscapeUserInfo(Skins[info->GetSkin()].Name).GetChars()); break; default: @@ -828,7 +828,7 @@ void D_ReadUserInfoStrings (int pnum, BYTE **stream, bool update) players[pnum].mo->state->sprite == GetDefaultByType (players[pnum].cls)->SpawnState->sprite) { // Only change the sprite if the player is using a standard one - players[pnum].mo->sprite = skins[info->GetSkin()].sprite; + players[pnum].mo->sprite = Skins[info->GetSkin()].sprite; } } // Rebuild translation in case the new skin uses a different range @@ -898,7 +898,7 @@ void WriteUserInfo(FSerializer &arc, userinfo_t &info) switch (pair->Key.GetIndex()) { case NAME_Skin: - string = skins[info.GetSkin()].name; + string = Skins[info.GetSkin()].Name; break; case NAME_PlayerClass: @@ -986,7 +986,7 @@ CCMD (playerinfo) // Print special info Printf("%20s: %s\n", "Name", ui->GetName()); Printf("%20s: %s (%d)\n", "Team", ui->GetTeam() == TEAM_NONE ? "None" : Teams[ui->GetTeam()].GetName(), ui->GetTeam()); - Printf("%20s: %s (%d)\n", "Skin", skins[ui->GetSkin()].name, ui->GetSkin()); + Printf("%20s: %s (%d)\n", "Skin", Skins[ui->GetSkin()].Name.GetChars(), ui->GetSkin()); Printf("%20s: %s (%d)\n", "Gender", GenderNames[ui->GetGender()], ui->GetGender()); Printf("%20s: %s (%d)\n", "PlayerClass", ui->GetPlayerClassNum() == -1 ? "Random" : ui->GetPlayerClassType()->DisplayName.GetChars(), diff --git a/src/g_game.cpp b/src/g_game.cpp index 627d51f04a..dcd36b041b 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1695,7 +1695,7 @@ static void G_QueueBody (AActor *body) { // Apply skin's scale to actor's scale, it will be lost otherwise const AActor *const defaultActor = body->GetDefault(); - const FPlayerSkin &skin = skins[skinidx]; + const FPlayerSkin &skin = Skins[skinidx]; body->Scale.X *= skin.Scale.X / defaultActor->Scale.X; body->Scale.Y *= skin.Scale.Y / defaultActor->Scale.Y; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 359e8a1742..1ae3c4b5ef 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -298,7 +298,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, // If a custom skin was in use, then reload it // or else the base skin for the player class. if ((unsigned int)player->userinfo.GetSkin() >= PlayerClasses.Size () && - (size_t)player->userinfo.GetSkin() < numskins) + (unsigned)player->userinfo.GetSkin() < Skins.Size()) { skinindex = player->userinfo.GetSkin(); diff --git a/src/g_statusbar/sbar_mugshot.cpp b/src/g_statusbar/sbar_mugshot.cpp index d24298b949..18e0fec42a 100644 --- a/src/g_statusbar/sbar_mugshot.cpp +++ b/src/g_statusbar/sbar_mugshot.cpp @@ -489,7 +489,7 @@ FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accu if (CurrentState != NULL) { int skin = player->userinfo.GetSkin(); - const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? ((APlayerPawn*)GetDefaultByType(player->MorphedPlayerClass))->Face.GetChars() : skins[skin].face); + const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? ((APlayerPawn*)GetDefaultByType(player->MorphedPlayerClass))->Face.GetChars() : Skins[skin].Face.GetChars()); return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 8310914bef..27532e7e98 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -593,7 +593,7 @@ void DIntermissionScreenCast::Drawer () if (!(mDefaults->flags4 & MF4_NOSKIN) && mDefaults->SpawnState != NULL && caststate->sprite == mDefaults->SpawnState->sprite && mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)) && - skins != NULL) + Skins.Size() > 0) { // Only use the skin sprite if this class has not been removed from the // PlayerClasses list. @@ -601,7 +601,7 @@ void DIntermissionScreenCast::Drawer () { if (PlayerClasses[i].Type == mClass) { - FPlayerSkin *skin = &skins[players[consoleplayer].userinfo.GetSkin()]; + FPlayerSkin *skin = &Skins[players[consoleplayer].userinfo.GetSkin()]; castsprite = skin->sprite; if (!(mDefaults->flags4 & MF4_NOSKIN)) diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index daa18d57b6..ec2d76a5cd 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -260,9 +260,9 @@ void DPlayerMenu::UpdateTranslation() if (PlayerClass != NULL) { - PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); + PlayerSkin = R_FindSkin (Skins[PlayerSkin].Name, int(PlayerClass - &PlayerClasses[0])); R_GetPlayerTranslation(PlayerColor, GetColorSet(PlayerClass->Type, PlayerColorset), - &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); + &Skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -368,12 +368,12 @@ void DPlayerMenu::UpdateSkins() else { PlayerSkins.Clear(); - for(int i=0;i<(int)numskins; i++) + for (unsigned i = 0; i < Skins.Size(); i++) { if (PlayerClass->CheckSkin(i)) { int j = PlayerSkins.Push(i); - li->SetString(j, skins[i].name); + li->SetString(j, Skins[i].Name); if (players[consoleplayer].userinfo.GetSkin() == i) { sel = j; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 15e82a56c5..8a062cd189 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -3919,7 +3919,7 @@ DEFINE_ACTION_FUNCTION(AActor, PlayerSkinCheck) PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(self->player != NULL && - skins[self->player->userinfo.GetSkin()].othergame); + Skins[self->player->userinfo.GetSkin()].othergame); } // [KS] *** Start of my modifications *** diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5bf6118004..2508f50f22 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -522,7 +522,7 @@ void AActor::PostSerialize() !(flags4 & MF4_NOSKIN) && state->sprite == GetDefaultByType(player->cls)->SpawnState->sprite) { // Give player back the skin - sprite = skins[player->userinfo.GetSkin()].sprite; + sprite = Skins[player->userinfo.GetSkin()].sprite; } if (Speed == 0) { @@ -666,9 +666,9 @@ bool AActor::SetState (FState *newstate, bool nofunction) // for Dehacked, I would move sprite changing out of the states // altogether, since actors rarely change their sprites after // spawning. - if (player != NULL && skins != NULL) + if (player != NULL && Skins.Size() > 0) { - sprite = skins[player->userinfo.GetSkin()].sprite; + sprite = Skins[player->userinfo.GetSkin()].sprite; } else if (newsprite != prevsprite) { @@ -5398,7 +5398,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) } // [GRB] Reset skin - p->userinfo.SkinNumChanged(R_FindSkin (skins[p->userinfo.GetSkin()].name, p->CurrentPlayerClass)); + p->userinfo.SkinNumChanged(R_FindSkin (Skins[p->userinfo.GetSkin()].Name, p->CurrentPlayerClass)); if (!(mobj->flags2 & MF2_DONTTRANSLATE)) { @@ -5416,7 +5416,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) // [RH] Set player sprite based on skin if (!(mobj->flags4 & MF4_NOSKIN)) { - mobj->sprite = skins[p->userinfo.GetSkin()].sprite; + mobj->sprite = Skins[p->userinfo.GetSkin()].sprite; } p->DesiredFOV = p->FOV = 90.f; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index a3208598d2..8f06b78098 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -837,7 +837,7 @@ void CopyPlayer(player_t *dst, player_t *src, const char *name) } // Validate the skin - dst->userinfo.SkinNumChanged(R_FindSkin(skins[dst->userinfo.GetSkin()].name, dst->CurrentPlayerClass)); + dst->userinfo.SkinNumChanged(R_FindSkin(Skins[dst->userinfo.GetSkin()].Name, dst->CurrentPlayerClass)); // Make sure the player pawn points to the proper player struct. if (dst->mo != nullptr) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 875d3fbc07..ac7faea765 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -4203,7 +4203,6 @@ static void P_Shutdown () { // [ZZ] delete global event handlers E_Shutdown(false); - R_DeinitSpriteData (); P_DeinitKeyMessages (); P_FreeLevelData (); P_FreeExtraLevelData (); diff --git a/src/p_states.cpp b/src/p_states.cpp index 3602cfc81e..d6f43aabe2 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -74,9 +74,9 @@ DEFINE_ACTION_FUNCTION(FState, GetSpriteTexture) } else { - sprframe = &SpriteFrames[sprites[skins[skin].sprite].spriteframes + self->GetFrame()]; - scalex = skins[skin].Scale.X; - scaley = skins[skin].Scale.Y; + sprframe = &SpriteFrames[sprites[Skins[skin].sprite].spriteframes + self->GetFrame()]; + scalex = Skins[skin].Scale.X; + scaley = Skins[skin].Scale.Y; } if (numret > 0) ret[0].SetInt(sprframe->Texture[rotation].GetIndex()); if (numret > 1) ret[1].SetInt(!!(sprframe->Flip & (1 << rotation))); diff --git a/src/p_user.cpp b/src/p_user.cpp index 5816a96897..bd6b2be4ed 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1247,9 +1247,9 @@ const char *APlayerPawn::GetSoundClass() const if (player != NULL && (player->mo == NULL || !(player->mo->flags4 &MF4_NOSKIN)) && (unsigned int)player->userinfo.GetSkin() >= PlayerClasses.Size () && - (size_t)player->userinfo.GetSkin() < numskins) + (unsigned)player->userinfo.GetSkin() < Skins.Size()) { - return skins[player->userinfo.GetSkin()].name; + return Skins[player->userinfo.GetSkin()].Name.GetChars(); } return SoundClass != NAME_None? SoundClass.GetChars() : "player"; @@ -1801,8 +1801,8 @@ void P_CheckPlayerSprite(AActor *actor, int &spritenum, DVector2 &scale) { // Convert from default scale to skin scale. DVector2 defscale = actor->GetDefault()->Scale; - scale.X *= skins[player->userinfo.GetSkin()].Scale.X / defscale.X; - scale.Y *= skins[player->userinfo.GetSkin()].Scale.Y / defscale.Y; + scale.X *= Skins[player->userinfo.GetSkin()].Scale.X / defscale.X; + scale.Y *= Skins[player->userinfo.GetSkin()].Scale.Y / defscale.Y; } // Set the crouch sprite? @@ -1813,10 +1813,10 @@ void P_CheckPlayerSprite(AActor *actor, int &spritenum, DVector2 &scale) crouchspriteno = player->mo->crouchsprite; } else if (!(actor->flags4 & MF4_NOSKIN) && - (spritenum == skins[player->userinfo.GetSkin()].sprite || - spritenum == skins[player->userinfo.GetSkin()].crouchsprite)) + (spritenum == Skins[player->userinfo.GetSkin()].sprite || + spritenum == Skins[player->userinfo.GetSkin()].crouchsprite)) { - crouchspriteno = skins[player->userinfo.GetSkin()].crouchsprite; + crouchspriteno = Skins[player->userinfo.GetSkin()].crouchsprite; } else { // no sprite -> squash the existing one diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index 0f4d58e6de..fd1bf5d215 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -1171,7 +1171,7 @@ void R_BuildPlayerTranslation (int player) D_GetPlayerColor (player, &h, &s, &v, &colorset); R_CreatePlayerTranslation (h, s, v, colorset, - &skins[players[player].userinfo.GetSkin()], + &Skins[players[player].userinfo.GetSkin()], translationtables[TRANSLATION_Players][player], translationtables[TRANSLATION_PlayersExtra][player], translationtables[TRANSLATION_RainPillar][player] @@ -1218,9 +1218,9 @@ DEFINE_ACTION_FUNCTION(_Translation, SetPlayerTranslation) if (cls != nullptr) { - PlayerSkin = R_FindSkin(skins[PlayerSkin].name, int(cls - &PlayerClasses[0])); + PlayerSkin = R_FindSkin(Skins[PlayerSkin].Name, int(cls - &PlayerClasses[0])); R_GetPlayerTranslation(PlayerColor, GetColorSet(cls->Type, PlayerColorset), - &skins[PlayerSkin], translationtables[tgroup][tnum]); + &Skins[PlayerSkin], translationtables[tgroup][tnum]); } ACTION_RETURN_BOOL(true); } diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index c3f73760db..72199cece7 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -30,8 +30,7 @@ struct spriteframewithrotate : public spriteframe_t // [RH] skin globals -FPlayerSkin *skins; -size_t numskins; +TArray Skins; BYTE OtherGameSkinRemap[256]; PalEntry OtherGameSkinPalette[256]; @@ -512,7 +511,7 @@ void R_InitSkins (void) int sndlumps[NUMSKINSOUNDS]; char key[65]; DWORD intname, crouchname; - size_t i; + unsigned i; int j, k, base; int lastlump; int aliasid; @@ -538,7 +537,7 @@ void R_InitSkins (void) i++; for (j = 0; j < NUMSKINSOUNDS; j++) sndlumps[j] = -1; - skins[i].namespc = Wads.GetLumpNamespace (base); + Skins[i].namespc = Wads.GetLumpNamespace (base); FScanner sc(base); intname = 0; @@ -560,14 +559,13 @@ void R_InitSkins (void) sc.GetString (); if (0 == stricmp (key, "name")) { - strncpy (skins[i].name, sc.String, 16); - for (j = 0; (size_t)j < i; j++) + Skins[i].Name = sc.String; + for (j = 0; (unsigned)j < i; j++) { - if (stricmp (skins[i].name, skins[j].name) == 0) + if (Skins[i].Name.CompareNoCase(Skins[j].Name) == 0) { - mysnprintf (skins[i].name, countof(skins[i].name), "skin%d", (int)i); - Printf (PRINT_BOLD, "Skin %s duplicated as %s\n", - skins[j].name, skins[i].name); + Skins[i].Name.Format("skin%u", i); + Printf (PRINT_BOLD, "Skin %s duplicated as %s\n", Skins[j].Name.GetChars(), Skins[i].Name.GetChars()); break; } } @@ -586,18 +584,16 @@ void R_InitSkins (void) } else if (0 == stricmp (key, "face")) { - for (j = 2; j >= 0; j--) - skins[i].face[j] = toupper (sc.String[j]); - skins[i].face[3] = '\0'; + Skins[i].Face = FString(sc.String, 3); } else if (0 == stricmp (key, "gender")) { - skins[i].gender = D_GenderToInt (sc.String); + Skins[i].gender = D_GenderToInt (sc.String); } else if (0 == stricmp (key, "scale")) { - skins[i].Scale.X = clamp(atof (sc.String), 1./65536, 256.); - skins[i].Scale.Y = skins[i].Scale.X; + Skins[i].Scale.X = clamp(atof (sc.String), 1./65536, 256.); + Skins[i].Scale.Y = Skins[i].Scale.X; } else if (0 == stricmp (key, "game")) { @@ -615,7 +611,7 @@ void R_InitSkins (void) if (gameinfo.gametype & GAME_DoomChex) { transtype = PClass::FindActor(NAME_HereticPlayer); - skins[i].othergame = true; + Skins[i].othergame = true; } else if (gameinfo.gametype != GAME_Heretic) { @@ -634,7 +630,7 @@ void R_InitSkins (void) if (gameinfo.gametype == GAME_Heretic) { transtype = PClass::FindActor(NAME_DoomPlayer); - skins[i].othergame = true; + Skins[i].othergame = true; } else if (!(gameinfo.gametype & GAME_DoomChex)) { @@ -659,7 +655,7 @@ void R_InitSkins (void) } else if (key[0] == '*') { // Player sound replacment (ZDoom extension) - int lump = Wads.CheckNumForName (sc.String, skins[i].namespc); + int lump = Wads.CheckNumForName (sc.String, Skins[i].namespc); if (lump == -1) { lump = Wads.CheckNumForFullName (sc.String, true, ns_sounds); @@ -668,11 +664,11 @@ void R_InitSkins (void) { if (stricmp (key, "*pain") == 0) { // Replace all pain sounds in one go - aliasid = S_AddPlayerSound (skins[i].name, skins[i].gender, + aliasid = S_AddPlayerSound (Skins[i].Name, Skins[i].gender, playersoundrefs[0], lump, true); for (int l = 3; l > 0; --l) { - S_AddPlayerSoundExisting (skins[i].name, skins[i].gender, + S_AddPlayerSoundExisting (Skins[i].Name, Skins[i].gender, playersoundrefs[l], aliasid, true); } } @@ -681,7 +677,7 @@ void R_InitSkins (void) int sndref = S_FindSoundNoHash (key); if (sndref != 0) { - S_AddPlayerSound (skins[i].name, skins[i].gender, sndref, lump, true); + S_AddPlayerSound (Skins[i].Name, Skins[i].gender, sndref, lump, true); } } } @@ -692,7 +688,7 @@ void R_InitSkins (void) { if (stricmp (key, skinsoundnames[j][0]) == 0) { - sndlumps[j] = Wads.CheckNumForName (sc.String, skins[i].namespc); + sndlumps[j] = Wads.CheckNumForName (sc.String, Skins[i].namespc); if (sndlumps[j] == -1) { // Replacement not found, try finding it in the global namespace sndlumps[j] = Wads.CheckNumForFullName (sc.String, true, ns_sounds); @@ -715,7 +711,7 @@ void R_InitSkins (void) { basetype = PClass::FindActor(NAME_HereticPlayer); transtype = PClass::FindActor(NAME_DoomPlayer); - skins[i].othergame = true; + Skins[i].othergame = true; } else { @@ -728,8 +724,8 @@ void R_InitSkins (void) auto transdef = ((APlayerPawn*)GetDefaultByType(transtype)); auto basedef = ((APlayerPawn*)GetDefaultByType(basetype)); - skins[i].range0start = transdef->ColorRangeStart; - skins[i].range0end = transdef->ColorRangeEnd; + Skins[i].range0start = transdef->ColorRangeStart; + Skins[i].range0end = transdef->ColorRangeEnd; remove = true; for (j = 0; j < (int)PlayerClasses.Size (); j++) @@ -750,8 +746,8 @@ void R_InitSkins (void) if (!remove) { - if (skins[i].name[0] == 0) - mysnprintf (skins[i].name, countof(skins[i].name), "skin%d", (int)i); + if (Skins[i].Name.IsEmpty()) + Skins[i].Name.Format("skin%u", i); // Now collect the sprite frames for this skin. If the sprite name was not // specified, use whatever immediately follows the specifier lump. @@ -783,7 +779,7 @@ void R_InitSkins (void) } else { - skins[i].crouchsprite = -1; + Skins[i].crouchsprite = -1; break; } } @@ -806,7 +802,7 @@ void R_InitSkins (void) if (spr == 0 && maxframe <= 0) { - Printf (PRINT_BOLD, "Skin %s (#%d) has no frames. Removing.\n", skins[i].name, (int)i); + Printf (PRINT_BOLD, "Skin %s (#%u) has no frames. Removing.\n", Skins[i].Name, i); remove = true; break; } @@ -814,16 +810,18 @@ void R_InitSkins (void) Wads.GetLumpName (temp.name, base+1); temp.name[4] = 0; int sprno = (int)sprites.Push (temp); - if (spr==0) skins[i].sprite = sprno; - else skins[i].crouchsprite = sprno; + if (spr==0) Skins[i].sprite = sprno; + else Skins[i].crouchsprite = sprno; R_InstallSprite (sprno, sprtemp, maxframe); } } if (remove) { - if (i < numskins-1) - memmove (&skins[i], &skins[i+1], sizeof(skins[0])*(numskins-i-1)); + if (i < Skins.Size() - 1) + { + Skins.Delete(i); + } i--; continue; } @@ -836,25 +834,25 @@ void R_InitSkins (void) { if (j == 0 || sndlumps[j] != sndlumps[j-1]) { - aliasid = S_AddPlayerSound (skins[i].name, skins[i].gender, + aliasid = S_AddPlayerSound (Skins[i].Name, Skins[i].gender, playersoundrefs[j], sndlumps[j], true); } else { - S_AddPlayerSoundExisting (skins[i].name, skins[i].gender, + S_AddPlayerSoundExisting (Skins[i].Name, Skins[i].gender, playersoundrefs[j], aliasid, true); } } } // Make sure face prefix is a full 3 chars - if (skins[i].face[1] == 0 || skins[i].face[2] == 0) + if (Skins[i].Face.Len() < 3) { - skins[i].face[0] = 0; + Skins[i].Face = ""; } } - if (numskins > PlayerClasses.Size ()) + if (Skins.Size() > PlayerClasses.Size ()) { // The sound table may have changed, so rehash it. S_HashSounds (); S_ShrinkPlayerSoundLists (); @@ -869,9 +867,9 @@ int R_FindSkin (const char *name, int pclass) return pclass; } - for (unsigned i = PlayerClasses.Size(); i < numskins; i++) + for (unsigned i = PlayerClasses.Size(); i < Skins.Size(); i++) { - if (strnicmp (skins[i].name, name, 16) == 0) + if (Skins[i].Name.CompareNoCase(name) == 0) { if (PlayerClasses[pclass].CheckSkin (i)) return i; @@ -887,8 +885,8 @@ CCMD (skins) { int i; - for (i = PlayerClasses.Size ()-1; i < (int)numskins; i++) - Printf ("% 3d %s\n", i-PlayerClasses.Size ()+1, skins[i].name); + for (i = PlayerClasses.Size() - 1; i < (int)Skins.Size(); i++) + Printf("% 3d %s\n", i - PlayerClasses.Size() + 1, Skins[i].Name.GetChars()); } @@ -914,6 +912,7 @@ void R_InitSprites () { int lump, lastlump; unsigned int i, j; + unsigned numskins; // [RH] Create a standard translation to map skins between Heretic and Doom if (gameinfo.gametype == GAME_DoomChex) @@ -934,15 +933,15 @@ void R_InitSprites () } // [RH] Do some preliminary setup - if (skins != NULL) delete [] skins; - skins = new FPlayerSkin[numskins]; - memset (skins, 0, sizeof(*skins) * numskins); + Skins.Clear(); + Skins.Resize(numskins); + for (i = 0; i < numskins; i++) { // Assume Doom skin by default auto type = ((APlayerPawn*)GetDefaultByType(PlayerClasses[0].Type)); - skins[i].range0start = type->ColorRangeStart; - skins[i].range0end = type->ColorRangeEnd; - skins[i].Scale = type->Scale; + Skins[i].range0start = type->ColorRangeStart; + Skins[i].range0end = type->ColorRangeEnd; + Skins[i].Scale = type->Scale; } R_InitSpriteDefs (); @@ -956,33 +955,30 @@ void R_InitSprites () { auto basetype = ((APlayerPawn*)GetDefaultByType(PlayerClasses[i].Type)); - strcpy (skins[i].name, "Base"); + Skins[i].Name = "Base"; if (basetype->Face == NAME_None) { - skins[i].face[0] = 'S'; - skins[i].face[1] = 'T'; - skins[i].face[2] = 'F'; - skins[i].face[3] = '\0'; + Skins[i].Face = "STF"; } else { - strcpy(skins[i].face, basetype->Face); + Skins[i].Face = basetype->Face; } - skins[i].range0start = basetype->ColorRangeStart; - skins[i].range0end = basetype->ColorRangeEnd; - skins[i].Scale = basetype->Scale; - skins[i].sprite = basetype->SpawnState->sprite; - skins[i].namespc = ns_global; + Skins[i].range0start = basetype->ColorRangeStart; + Skins[i].range0end = basetype->ColorRangeEnd; + Skins[i].Scale = basetype->Scale; + Skins[i].sprite = basetype->SpawnState->sprite; + Skins[i].namespc = ns_global; PlayerClasses[i].Skins.Push (i); - if (memcmp (sprites[skins[i].sprite].name, "PLAY", 4) == 0) + if (memcmp (sprites[Skins[i].sprite].name, "PLAY", 4) == 0) { for (j = 0; j < sprites.Size (); j++) { if (memcmp (sprites[j].name, deh.PlayerSprite, 4) == 0) { - skins[i].sprite = (int)j; + Skins[i].sprite = (int)j; break; } } @@ -995,12 +991,14 @@ void R_InitSprites () gl_InitModels(); } -void R_DeinitSpriteData() -{ - // Free skins - if (skins != NULL) - { - delete[] skins; - skins = NULL; - } -} + +DEFINE_FIELD(FPlayerSkin, Name); +DEFINE_FIELD(FPlayerSkin, Face); +DEFINE_FIELD(FPlayerSkin, gender); +DEFINE_FIELD(FPlayerSkin, range0start); +DEFINE_FIELD(FPlayerSkin, range0end); +DEFINE_FIELD(FPlayerSkin, othergame); +DEFINE_FIELD(FPlayerSkin, Scale); +DEFINE_FIELD(FPlayerSkin, sprite); +DEFINE_FIELD(FPlayerSkin, crouchsprite); +DEFINE_FIELD(FPlayerSkin, namespc); diff --git a/src/r_data/sprites.h b/src/r_data/sprites.h index d882ee9810..9e7d9392ec 100644 --- a/src/r_data/sprites.h +++ b/src/r_data/sprites.h @@ -47,25 +47,23 @@ extern TArray SpriteFrames; class FPlayerSkin { public: - char name[17]; // 16 chars + NULL - char face[4]; // 3 chars ([MH] + NULL so can use as a C string) - BYTE gender; // This skin's gender (not really used) - BYTE range0start; - BYTE range0end; - bool othergame; // [GRB] - DVector2 Scale; - int sprite; - int crouchsprite; - int namespc; // namespace for this skin + FString Name; + FString Face; + BYTE gender = 0; // This skin's gender (not really used) + BYTE range0start = 0; + BYTE range0end = 0; + bool othergame = 0; // [GRB] + DVector2 Scale = { 1, 1 }; + int sprite = 0; + int crouchsprite = 0; + int namespc = 0; // namespace for this skin }; -extern size_t numskins; // [RH] -extern FPlayerSkin * skins; // [RH] +extern TArray Skins; extern BYTE OtherGameSkinRemap[256]; extern PalEntry OtherGameSkinPalette[256]; void R_InitSprites (); -void R_DeinitSpriteData (); #endif diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f257c7c2d6..c9679c4b24 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -57,6 +57,7 @@ #include "v_video.h" #include "c_bind.h" #include "menu/menu.h" +#include "r_data/sprites.h" static TArray properties; static TArray AFTable; @@ -759,6 +760,10 @@ void InitThingdef() playerclassstruct->Size = sizeof(FPlayerClass); playerclassstruct->Align = alignof(FPlayerClass); + auto playerskinstruct = NewNativeStruct("PlayerSkin", nullptr); + playerskinstruct->Size = sizeof(FPlayerSkin); + playerskinstruct->Align = alignof(FPlayerSkin); + // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. sectorstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(linestruct, false)), false), myoffsetof(sector_t, Lines), VARF_Native); @@ -798,6 +803,10 @@ void InitThingdef() PField *plrclsf = new PField("PlayerClasses", plrcls, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PlayerClasses); Namespaces.GlobalNamespace->Symbols.AddSymbol(plrclsf); + auto plrskn = NewPointer(NewResizableArray(playerskinstruct), false); + PField *plrsknf = new PField("PlayerSkins", plrcls, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Skins); + Namespaces.GlobalNamespace->Symbols.AddSymbol(plrsknf); + auto bindcls = NewNativeStruct("KeyBindings", nullptr); PField *binding = new PField("Bindings", bindcls, VARF_Native | VARF_Static, (intptr_t)&Bindings); Namespaces.GlobalNamespace->Symbols.AddSymbol(binding); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 24bfa51c60..ab3019dcdb 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -326,3 +326,17 @@ struct PlayerClass native native bool CheckSkin(int skin); } + +struct PlayerSkin native +{ + native readonly String Name; + native readonly String Face; + native readonly uint8 gender; + native readonly uint8 range0start; + native readonly uint8 range0end; + native readonly bool othergame; + native readonly Vector2 Scale; + native readonly int sprite; + native readonly int crouchsprite; + native readonly int namespc; +}; From 97eed1e6df0fcda6ee559f9af302c415d404b021 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 22:12:56 +0100 Subject: [PATCH 020/207] - scriptified UpdateSkins. --- src/menu/playermenu.cpp | 2 +- src/p_user.cpp | 5 +++ src/r_data/sprites.cpp | 2 +- src/scripting/thingdef_data.cpp | 2 +- wadsrc/static/zscript/menu/playermenu.txt | 50 ++++++++++++++++++++++- wadsrc/static/zscript/shared/player.txt | 13 +++--- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index ec2d76a5cd..ac47323294 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -597,5 +597,5 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged) DEFINE_FIELD(DPlayerMenu, mRotation) DEFINE_FIELD_NAMED(DPlayerMenu, PlayerClass, mPlayerClass) DEFINE_FIELD(DPlayerMenu, PlayerColorSets) -DEFINE_FIELD(DPlayerMenu, PlayerSkins) +DEFINE_FIELD_NAMED(DPlayerMenu, PlayerSkins, mPlayerSkins) DEFINE_FIELD(DPlayerMenu, PlayerClassIndex) diff --git a/src/p_user.cpp b/src/p_user.cpp index bd6b2be4ed..79f691ec04 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -673,6 +673,11 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetPlayerClassNum) ACTION_RETURN_INT(self->userinfo.GetPlayerClassNum()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkin) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_INT(self->userinfo.GetSkin()); +} //=========================================================================== // diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 72199cece7..45167580fb 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -992,7 +992,7 @@ void R_InitSprites () } -DEFINE_FIELD(FPlayerSkin, Name); +DEFINE_FIELD_NAMED(FPlayerSkin, Name, SkinName); DEFINE_FIELD(FPlayerSkin, Face); DEFINE_FIELD(FPlayerSkin, gender); DEFINE_FIELD(FPlayerSkin, range0start); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index c9679c4b24..3550a78c96 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -804,7 +804,7 @@ void InitThingdef() Namespaces.GlobalNamespace->Symbols.AddSymbol(plrclsf); auto plrskn = NewPointer(NewResizableArray(playerskinstruct), false); - PField *plrsknf = new PField("PlayerSkins", plrcls, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Skins); + PField *plrsknf = new PField("PlayerSkins", plrskn, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Skins); Namespaces.GlobalNamespace->Symbols.AddSymbol(plrsknf); auto bindcls = NewNativeStruct("KeyBindings", nullptr); diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index 0ac5328a03..4a6a94b2d6 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -5,7 +5,7 @@ class PlayerMenu : ListMenu native native int PlayerClassIndex; native PlayerClass mPlayerClass; native Array PlayerColorSets; - native Array PlayerSkins; + native Array mPlayerSkins; // All write function for the player config are native to prevent abuse. protected native void AutoaimChanged(float val); @@ -61,6 +61,52 @@ class PlayerMenu : ListMenu native // //============================================================================= + protected void UpdateSkins() + { + int sel = 0; + int skin; + let li = GetItem('Skin'); + if (li != NULL) + { + if (GetDefaultByType (mPlayerClass.Type).bNoSkin || players[consoleplayer].GetPlayerClassNum() == -1) + { + li.SetString(0, "Base"); + li.SetValue(0, 0); + skin = 0; + } + else + { + mPlayerSkins.Clear(); + for (int i = 0; i < PlayerSkins.Size(); i++) + { + if (mPlayerClass.CheckSkin(i)) + { + int j = mPlayerSkins.Push(i); + li.SetString(j, PlayerSkins[i].SkinName); + if (players[consoleplayer].GetSkin() == i) + { + sel = j; + } + } + } + li.SetValue(0, sel); + skin = mPlayerSkins[sel]; + } + li = GetItem('Playerdisplay'); + if (li != NULL) + { + li.SetValue(ListMenuItemPlayerDisplay.PDF_SKIN, skin); + } + } + UpdateTranslation(); + } + +//============================================================================= + // + // + // + //============================================================================= + protected void ChangeSkin (MenuItemBase li) { if (GetDefaultByType (mPlayerClass.Type).bNoSkin || players[consoleplayer].GetPlayerClassNum() == -1) @@ -74,7 +120,7 @@ class PlayerMenu : ListMenu native [res, sel] = li.GetValue(0); if (res) { - sel = PlayerSkins[sel]; + sel = mPlayerSkins[sel]; SkinChanged(sel); UpdateTranslation(); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index ab3019dcdb..9203dee0e7 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -295,7 +295,6 @@ struct PlayerInfo native // this is what internally is known as player_t /* these are not doable yet ticcmd_t cmd; usercmd_t original_cmd; -userinfo_t userinfo; */ @@ -309,13 +308,15 @@ userinfo_t userinfo; native PSprite FindPSprite(int id); native void SetLogNumber (int text); native void SetLogText (String text); - native String GetUserName(); - native Color GetColor(); - native int GetPlayerClassNum(); - native bool GetNeverSwitch(); native void DropWeapon(); native void BringUpWeapon(); + native String GetUserName(); + native Color GetColor(); + native int GetPlayerClassNum(); + native int GetSkin(); + native bool GetNeverSwitch(); + } struct PlayerClass native @@ -329,7 +330,7 @@ struct PlayerClass native struct PlayerSkin native { - native readonly String Name; + native readonly String SkinName; native readonly String Face; native readonly uint8 gender; native readonly uint8 range0start; From 50d2846e40457fd6715d498404ad97063b766d59 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 23:16:07 +0100 Subject: [PATCH 021/207] - scriptified UpdateColorsets. --- src/p_user.cpp | 22 ++++++++++++++ src/scripting/zscript/zcc_compile.cpp | 25 +++++++--------- wadsrc/static/zscript/menu/playermenu.txt | 36 ++++++++++++++++++++++- wadsrc/static/zscript/shared/player.txt | 4 ++- 4 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 79f691ec04..0d69810d97 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -584,6 +584,14 @@ void EnumColorSets(PClassActor *cls, TArray *out) qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); } +DEFINE_ACTION_FUNCTION(FPlayerClass, EnumColorSets) +{ + PARAM_SELF_STRUCT_PROLOGUE(FPlayerClass); + PARAM_POINTER(out, TArray); + EnumColorSets(self->Type, out); + return 0; +} + //========================================================================== // // @@ -603,6 +611,14 @@ FPlayerColorSet *GetColorSet(PClassActor *cls, int setnum) return nullptr; } +DEFINE_ACTION_FUNCTION(FPlayerClass, GetColorSetName) +{ + PARAM_SELF_STRUCT_PROLOGUE(FPlayerClass); + PARAM_INT(setnum); + auto p = GetColorSet(self->Type, setnum); + ACTION_RETURN_INT(p ? p->Name.GetIndex() : 0); +} + //========================================================================== // // @@ -667,6 +683,12 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetColor) ACTION_RETURN_INT(self->userinfo.GetColor()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetColorSet) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_INT(self->userinfo.GetColorSet()); +} + DEFINE_ACTION_FUNCTION(_PlayerInfo, GetPlayerClassNum) { PARAM_SELF_STRUCT_PROLOGUE(player_t); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index a240c19733..c802dda367 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1361,22 +1361,19 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n break; case AST_DynArrayType: - if (allowarraytypes) + { + auto atype = static_cast(ztype); + auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true); + if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1) { - auto atype = static_cast(ztype); - auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true); - if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1) - { - Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); - } - else - { - retval = NewDynArray(ftype); - } - break; + Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName()); + } + else + { + retval = NewDynArray(ftype); } break; - + } case AST_ClassType: { auto ctype = static_cast(ztype); @@ -2135,7 +2132,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool { auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); int flags = 0; - if (type->IsA(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) + if ((type->IsA(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) || type->IsA(RUNTIME_CLASS(PDynArray))) { // Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly. type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/); diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index 4a6a94b2d6..8c4c66f56d 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -61,6 +61,40 @@ class PlayerMenu : ListMenu native // //============================================================================= + protected void UpdateColorsets() + { + let li = GetItem('Color'); + if (li != NULL) + { + int sel = 0; + mPlayerClass.EnumColorSets(PlayerColorSets); + li.SetString(0, "Custom"); + for(int i = 0; i < PlayerColorSets.Size(); i++) + { + let cname = mPlayerClass.GetColorSetName(PlayerColorSets[i]); + li.SetString(i+1, cname); + } + int mycolorset = players[consoleplayer].GetColorSet(); + if (mycolorset != -1) + { + for(int i = 0; i < PlayerColorSets.Size(); i++) + { + if (PlayerColorSets[i] == mycolorset) + { + sel = i + 1; + } + } + } + li.SetValue(0, sel); + } + } + + //============================================================================= + // + // + // + //============================================================================= + protected void UpdateSkins() { int sel = 0; @@ -101,7 +135,7 @@ class PlayerMenu : ListMenu native UpdateTranslation(); } -//============================================================================= + //============================================================================= // // // diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 9203dee0e7..f7333220bc 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -313,10 +313,10 @@ usercmd_t original_cmd; native String GetUserName(); native Color GetColor(); + native int GetColorSet(); native int GetPlayerClassNum(); native int GetSkin(); native bool GetNeverSwitch(); - } struct PlayerClass native @@ -326,6 +326,8 @@ struct PlayerClass native native Array Skins; native bool CheckSkin(int skin); + native void EnumColorsets(out Array data); + native Name GetColorsetName(int setnum); } struct PlayerSkin native From 49a07180c07c6b74cf1edd9d45555b179fb0ec53 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Feb 2017 23:56:22 +0100 Subject: [PATCH 022/207] - scriptified ClassChanged. --- src/gi.cpp | 1 + src/menu/playermenu.cpp | 55 +++++++---------------- wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/menu/playermenu.txt | 42 ++++++++++++++--- 4 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/gi.cpp b/src/gi.cpp index 9f6827ab45..b05000d01b 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -50,6 +50,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass) const char *GameNames[17] = diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index ac47323294..93db2040ce 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -77,12 +77,6 @@ public: void UpdateSkins(); void UpdateTranslation(); - void PlayerNameChanged(DMenuItemBase *li); - void ColorSetChanged (DMenuItemBase *li); - void ClassChanged (DMenuItemBase *li); - void SkinChanged (DMenuItemBase *li); - - public: DPlayerMenu() {} @@ -248,7 +242,7 @@ bool DPlayerMenu::Responder (event_t *ev) //============================================================================= // -// +// done // //============================================================================= @@ -268,7 +262,7 @@ void DPlayerMenu::UpdateTranslation() //============================================================================= // -// +// done // //============================================================================= @@ -305,7 +299,10 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) { + char command[24]; players[consoleplayer].userinfo.ColorChanged(MAKERGB(r, g, b)); + mysnprintf(command, countof(command), "color \"%02x %02x %02x\"", r, g, b); + C_DoCommand(command); } return 0; } @@ -313,7 +310,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) //============================================================================= // -// +// done // //============================================================================= @@ -347,7 +344,7 @@ void DPlayerMenu::UpdateColorsets() //============================================================================= // -// +// done // //============================================================================= @@ -436,6 +433,9 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) if (self == DMenu::CurrentMenu) { players[consoleplayer].userinfo.ColorSetChanged(sel); + char command[24]; + mysnprintf(command, countof(command), "colorset %d", sel); + C_DoCommand(command); } return 0; } @@ -446,41 +446,15 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) // //============================================================================= -void DPlayerMenu::ClassChanged (DMenuItemBase *li) -{ - if (PlayerClasses.Size () == 1) - { - return; - } - - int sel; - - if (li->GetValue(0, &sel)) - { - players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel-1); - PickPlayerClass(); - - cvar_set ("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(PlayerClass->Type).GetChars()); - - UpdateSkins(); - UpdateColorsets(); - UpdateTranslation(); - - li = GetItem(NAME_Playerdisplay); - if (li != NULL) - { - li->SetValue(ListMenuItemPlayerDisplay_PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum()); - } - } -} - DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) { PARAM_SELF_PROLOGUE(DPlayerMenu); - PARAM_OBJECT(sel, DMenuItemBase); + PARAM_INT(sel); + PARAM_POINTER(cls, FPlayerClass); if (self == DMenu::CurrentMenu) { - self->ClassChanged(sel); + players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel - 1); + cvar_set("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(cls->Type).GetChars()); } return 0; } @@ -499,6 +473,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) if (self == DMenu::CurrentMenu) { players[consoleplayer].userinfo.SkinNumChanged(sel); + cvar_set("skin", Skins[sel].Name); } return 0; } diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 7b872f4729..57bdc7b019 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -309,6 +309,7 @@ struct GameInfoStruct native native String ArmorIcon1; native String ArmorIcon2; native int gametype; + native bool norandomplayerclass; } class Object native diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index 8c4c66f56d..4fbc91620f 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -17,8 +17,7 @@ class PlayerMenu : ListMenu native protected native void ColorSetChanged(int red); protected native void PlayerNameChanged(String name); protected native void SkinChanged (int val); - - protected native void ClassChanged(ListMenuItem it); + protected native void ClassChanged(int sel, PlayerClass cls); protected void UpdateTranslation() { @@ -37,13 +36,13 @@ class PlayerMenu : ListMenu native // //============================================================================= - protected void PickPlayerClass() + protected void PickPlayerClass(int pick = -100) { int pclass = 0; // [GRB] Pick a class from player class list if (PlayerClasses.Size () > 1) { - pclass = players[consoleplayer].GetPlayerClassNum(); + pclass = pick == -100? players[consoleplayer].GetPlayerClassNum() : pick; if (pclass < 0) { @@ -141,6 +140,39 @@ class PlayerMenu : ListMenu native // //============================================================================= + void ChangeClass (MenuItemBase li) + { + if (PlayerClasses.Size () == 1) + { + return; + } + + bool res; + int sel; + + [res, sel] = li.GetValue(0); + if (res) + { + PickPlayerClass(gameinfo.norandomplayerclass ? sel : sel-1); + ClassChanged(sel, mPlayerClass); + UpdateSkins(); + UpdateColorsets(); + UpdateTranslation(); + + li = GetItem('Playerdisplay'); + if (li != NULL) + { + li.SetValue(ListMenuItemPlayerDisplay.PDF_CLASS, players[consoleplayer].GetPlayerClassNum()); + } + } + } + + //============================================================================= + // + // + // + //============================================================================= + protected void ChangeSkin (MenuItemBase li) { if (GetDefaultByType (mPlayerClass.Type).bNoSkin || players[consoleplayer].GetPlayerClassNum() == -1) @@ -254,7 +286,7 @@ class PlayerMenu : ListMenu native [res, v] = li.GetValue(0); if (res) { - ClassChanged(li); + ChangeClass(li); } break; From 5f1241a55c73986aa36d32363a1196128a44af8b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 01:20:07 +0100 Subject: [PATCH 023/207] - scriptified the rest of the player menu. This compiles and runs but doesn't work yet, it will be fixed in the next commit. --- src/d_player.h | 5 + src/menu/playermenu.cpp | 345 +--------------------- src/p_user.cpp | 19 ++ src/scripting/thingdef_data.cpp | 9 + src/teaminfo.cpp | 3 + src/teaminfo.h | 2 + wadsrc/static/zscript/menu/playermenu.txt | 201 ++++++++++++- wadsrc/static/zscript/shared/player.txt | 10 + 8 files changed, 256 insertions(+), 338 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 7fa0d45b26..b16af36116 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -297,6 +297,11 @@ struct userinfo_t : TMap return aim; } } + // Same but unfiltered. + double GetAutoaim() const + { + return *static_cast(*CheckKey(NAME_Autoaim)); + } const char *GetName() const { return *static_cast(*CheckKey(NAME_Name)); diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 93db2040ce..519af0a9d7 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -48,241 +48,10 @@ #include "r_data/r_translate.h" #include "v_text.h" -EXTERN_CVAR (String, playerclass) -EXTERN_CVAR (String, name) -EXTERN_CVAR (Int, team) -EXTERN_CVAR (Float, autoaim) +EXTERN_CVAR(Int, team) +EXTERN_CVAR(Float, autoaim) EXTERN_CVAR(Bool, neverswitchonpickup) -EXTERN_CVAR (Bool, cl_run) - -//============================================================================= -// -// -// -//============================================================================= - -class DPlayerMenu : public DListMenu -{ - DECLARE_CLASS(DPlayerMenu, DListMenu) - -public: - int PlayerClassIndex; - FPlayerClass *PlayerClass; - TArray PlayerColorSets; - TArray PlayerSkins; - int mRotation; - - void PickPlayerClass (); - void UpdateColorsets(); - void UpdateSkins(); - void UpdateTranslation(); - -public: - - DPlayerMenu() {} - void Init(DMenu *parent, DListMenuDescriptor *desc); - bool Responder (event_t *ev); -}; - -IMPLEMENT_CLASS(DPlayerMenu, false, false) - -//============================================================================= -// -// -// -//============================================================================= -enum EPDFlags -{ - ListMenuItemPlayerDisplay_PDF_ROTATION = 0x10001, - ListMenuItemPlayerDisplay_PDF_SKIN = 0x10002, - ListMenuItemPlayerDisplay_PDF_CLASS = 0x10003, - ListMenuItemPlayerDisplay_PDF_MODE = 0x10004, - ListMenuItemPlayerDisplay_PDF_TRANSLATE = 0x10005, -}; - -void DPlayerMenu::Init(DMenu *parent, DListMenuDescriptor *desc) -{ - DMenuItemBase *li; - - Super::Init(parent, desc); - PickPlayerClass(); - mRotation = 0; - - li = GetItem(NAME_Playerdisplay); - if (li != NULL) - { - li->SetValue(ListMenuItemPlayerDisplay_PDF_ROTATION, 0); - li->SetValue(ListMenuItemPlayerDisplay_PDF_MODE, 1); - li->SetValue(ListMenuItemPlayerDisplay_PDF_TRANSLATE, 1); - li->SetValue(ListMenuItemPlayerDisplay_PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum()); - if (PlayerClass != NULL && !(GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN) && - players[consoleplayer].userinfo.GetPlayerClassNum() != -1) - { - li->SetValue(ListMenuItemPlayerDisplay_PDF_SKIN, players[consoleplayer].userinfo.GetSkin()); - } - } - - li = GetItem(NAME_Playerbox); - if (li != NULL) - { - li->SetString(0, name); - } - - li = GetItem(NAME_Team); - if (li != NULL) - { - li->SetString(0, "None"); - for(unsigned i=0;iSetString(i+1, Teams[i].GetName()); - } - li->SetValue(0, team == TEAM_NONE? 0 : team + 1); - } - - int mycolorset = players[consoleplayer].userinfo.GetColorSet(); - int color = players[consoleplayer].userinfo.GetColor(); - - UpdateColorsets(); - - li = GetItem(NAME_Red); - if (li != NULL) - { - li->Enable(mycolorset == -1); - li->SetValue(0, RPART(color)); - } - - li = GetItem(NAME_Green); - if (li != NULL) - { - li->Enable(mycolorset == -1); - li->SetValue(0, GPART(color)); - } - - li = GetItem(NAME_Blue); - if (li != NULL) - { - li->Enable(mycolorset == -1); - li->SetValue(0, BPART(color)); - } - - li = GetItem(NAME_Class); - if (li != NULL) - { - if (PlayerClasses.Size() == 1) - { - li->SetString(0, GetPrintableDisplayName(PlayerClasses[0].Type)); - li->SetValue(0, 0); - } - else - { - // [XA] Remove the "Random" option if the relevant gameinfo flag is set. - if(!gameinfo.norandomplayerclass) - li->SetString(0, "Random"); - for(unsigned i=0; i< PlayerClasses.Size(); i++) - { - const char *cls = GetPrintableDisplayName(PlayerClasses[i].Type); - li->SetString(gameinfo.norandomplayerclass ? i : i+1, cls); - } - int pclass = players[consoleplayer].userinfo.GetPlayerClassNum(); - li->SetValue(0, gameinfo.norandomplayerclass && pclass >= 0 ? pclass : pclass + 1); - } - } - - UpdateSkins(); - - li = GetItem(NAME_Gender); - if (li != NULL) - { - li->SetValue(0, players[consoleplayer].userinfo.GetGender()); - } - - li = GetItem(NAME_Autoaim); - if (li != NULL) - { - li->SetValue(0, (int)autoaim); - } - - li = GetItem(NAME_Switch); - if (li != NULL) - { - li->SetValue(0, neverswitchonpickup); - } - - li = GetItem(NAME_AlwaysRun); - if (li != NULL) - { - li->SetValue(0, cl_run); - } - - if (mDesc->mSelectedItem < 0) mDesc->mSelectedItem = 1; - -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DPlayerMenu::Responder (event_t *ev) -{ - if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_Char && ev->data1 == ' ') - { - // turn the player sprite around - mRotation = 8 - mRotation; - DMenuItemBase *li = GetItem(NAME_Playerdisplay); - if (li != NULL) - { - li->SetValue(ListMenuItemPlayerDisplay_PDF_ROTATION, mRotation); - } - return true; - } - return Super::Responder(ev); -} - -//============================================================================= -// -// done -// -//============================================================================= - -void DPlayerMenu::UpdateTranslation() -{ - int PlayerColor = players[consoleplayer].userinfo.GetColor(); - int PlayerSkin = players[consoleplayer].userinfo.GetSkin(); - int PlayerColorset = players[consoleplayer].userinfo.GetColorSet(); - - if (PlayerClass != NULL) - { - PlayerSkin = R_FindSkin (Skins[PlayerSkin].Name, int(PlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, GetColorSet(PlayerClass->Type, PlayerColorset), - &Skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); - } -} - -//============================================================================= -// -// done -// -//============================================================================= - -void DPlayerMenu::PickPlayerClass() -{ - int pclass = 0; - // [GRB] Pick a class from player class list - if (PlayerClasses.Size () > 1) - { - pclass = players[consoleplayer].userinfo.GetPlayerClassNum(); - - if (pclass < 0) - { - pclass = (MenuTime>>7) % PlayerClasses.Size (); - } - } - PlayerClassIndex = pclass; - PlayerClass = &PlayerClasses[PlayerClassIndex]; - UpdateTranslation(); -} +EXTERN_CVAR(Bool, cl_run) //============================================================================= // @@ -292,7 +61,7 @@ void DPlayerMenu::PickPlayerClass() DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(r); PARAM_INT(g); PARAM_INT(b); @@ -308,87 +77,6 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) } -//============================================================================= -// -// done -// -//============================================================================= - -void DPlayerMenu::UpdateColorsets() -{ - DMenuItemBase *li = GetItem(NAME_Color); - if (li != NULL) - { - int sel = 0; - EnumColorSets(PlayerClass->Type, &PlayerColorSets); - li->SetString(0, "Custom"); - for(unsigned i=0;iType, PlayerColorSets[i]); - li->SetString(i+1, colorset->Name); - } - int mycolorset = players[consoleplayer].userinfo.GetColorSet(); - if (mycolorset != -1) - { - for(unsigned i=0;iSetValue(0, sel); - } -} - -//============================================================================= -// -// done -// -//============================================================================= - -void DPlayerMenu::UpdateSkins() -{ - int sel = 0; - int skin; - DMenuItemBase *li = GetItem(NAME_Skin); - if (li != NULL) - { - if (GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN || - players[consoleplayer].userinfo.GetPlayerClassNum() == -1) - { - li->SetString(0, "Base"); - li->SetValue(0, 0); - skin = 0; - } - else - { - PlayerSkins.Clear(); - for (unsigned i = 0; i < Skins.Size(); i++) - { - if (PlayerClass->CheckSkin(i)) - { - int j = PlayerSkins.Push(i); - li->SetString(j, Skins[i].Name); - if (players[consoleplayer].userinfo.GetSkin() == i) - { - sel = j; - } - } - } - li->SetValue(0, sel); - skin = PlayerSkins[sel]; - } - li = GetItem(NAME_Playerdisplay); - if (li != NULL) - { - li->SetValue(ListMenuItemPlayerDisplay_PDF_SKIN, skin); - } - } - UpdateTranslation(); -} - //============================================================================= // // access to the player config is done natively, so that broader access @@ -398,7 +86,7 @@ void DPlayerMenu::UpdateSkins() DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_STRING(s); const char *pp = s; FString command("name \""); @@ -428,7 +116,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(sel); if (self == DMenu::CurrentMenu) { @@ -448,7 +136,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(sel); PARAM_POINTER(cls, FPlayerClass); if (self == DMenu::CurrentMenu) @@ -468,7 +156,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(sel); if (self == DMenu::CurrentMenu) { @@ -486,7 +174,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_FLOAT(val); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -504,7 +192,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(val); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -522,7 +210,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -540,7 +228,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -558,7 +246,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged) { - PARAM_SELF_PROLOGUE(DPlayerMenu); + PARAM_SELF_PROLOGUE(DListMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -567,10 +255,3 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged) } return 0; } - - -DEFINE_FIELD(DPlayerMenu, mRotation) -DEFINE_FIELD_NAMED(DPlayerMenu, PlayerClass, mPlayerClass) -DEFINE_FIELD(DPlayerMenu, PlayerColorSets) -DEFINE_FIELD_NAMED(DPlayerMenu, PlayerSkins, mPlayerSkins) -DEFINE_FIELD(DPlayerMenu, PlayerClassIndex) diff --git a/src/p_user.cpp b/src/p_user.cpp index 0d69810d97..53e27c0f54 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -701,6 +701,25 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkin) ACTION_RETURN_INT(self->userinfo.GetSkin()); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetGender) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_INT(self->userinfo.GetGender()); +} + +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetAutoaim) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_FLOAT(self->userinfo.GetAutoaim()); +} + +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetTeam) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + ACTION_RETURN_INT(self->userinfo.GetTeam()); +} + + //=========================================================================== // // APlayerPawn diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 3550a78c96..4fb167f561 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -57,6 +57,7 @@ #include "v_video.h" #include "c_bind.h" #include "menu/menu.h" +#include "teaminfo.h" #include "r_data/sprites.h" static TArray properties; @@ -764,6 +765,10 @@ void InitThingdef() playerskinstruct->Size = sizeof(FPlayerSkin); playerskinstruct->Align = alignof(FPlayerSkin); + auto teamstruct = NewNativeStruct("Team", nullptr); + teamstruct->Size = sizeof(FTeam); + teamstruct->Align = alignof(FTeam); + // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. sectorstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(linestruct, false)), false), myoffsetof(sector_t, Lines), VARF_Native); @@ -807,6 +812,10 @@ void InitThingdef() PField *plrsknf = new PField("PlayerSkins", plrskn, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Skins); Namespaces.GlobalNamespace->Symbols.AddSymbol(plrsknf); + auto teamst = NewPointer(NewResizableArray(teamstruct), false); + PField *teamf = new PField("Teams", teamst, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Teams); + Namespaces.GlobalNamespace->Symbols.AddSymbol(teamf); + auto bindcls = NewNativeStruct("KeyBindings", nullptr); PField *binding = new PField("Bindings", bindcls, VARF_Native | VARF_Static, (intptr_t)&Bindings); Namespaces.GlobalNamespace->Symbols.AddSymbol(binding); diff --git a/src/teaminfo.cpp b/src/teaminfo.cpp index 38ba56f4cd..18a2580e2d 100644 --- a/src/teaminfo.cpp +++ b/src/teaminfo.cpp @@ -333,3 +333,6 @@ CCMD (teamlist) Printf ("End of team list.\n"); } + + +DEFINE_FIELD_NAMED(FTeam, m_Name, mName) \ No newline at end of file diff --git a/src/teaminfo.h b/src/teaminfo.h index 41408b546a..1c84d9b9b8 100644 --- a/src/teaminfo.h +++ b/src/teaminfo.h @@ -63,7 +63,9 @@ private: void ParseTeamDefinition (FScanner &Scan); void ClearTeams (); +public: // needed for script access. FString m_Name; +private: int m_iPlayerColor; FString m_TextColor; FString m_Logo; diff --git a/wadsrc/static/zscript/menu/playermenu.txt b/wadsrc/static/zscript/menu/playermenu.txt index 4fbc91620f..4502cc9fa8 100644 --- a/wadsrc/static/zscript/menu/playermenu.txt +++ b/wadsrc/static/zscript/menu/playermenu.txt @@ -1,11 +1,45 @@ +/* +** playermenu.cpp +** The player setup menu +** +**--------------------------------------------------------------------------- +** Copyright 2001-2010 Randy Heit +** Copyright 2010-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ -class PlayerMenu : ListMenu native +class PlayerMenu : ListMenu { - native int mRotation; - native int PlayerClassIndex; - native PlayerClass mPlayerClass; - native Array PlayerColorSets; - native Array mPlayerSkins; + int mRotation; + int PlayerClassIndex; + PlayerClass mPlayerClass; + Array PlayerColorSets; + Array mPlayerSkins; // All write function for the player config are native to prevent abuse. protected native void AutoaimChanged(float val); @@ -19,6 +53,12 @@ class PlayerMenu : ListMenu native protected native void SkinChanged (int val); protected native void ClassChanged(int sel, PlayerClass cls); + //============================================================================= + // + // + // + //============================================================================= + protected void UpdateTranslation() { Translation.SetPlayerTranslation(TRANSLATION_Players, MAXPLAYERS, consoleplayer, mPlayerClass); @@ -30,6 +70,133 @@ class PlayerMenu : ListMenu native UpdateTranslation(); } + //============================================================================= + // + // + // + //============================================================================= + + override void Init(Menu parent, ListMenuDescriptor desc) + { + MenuItemBase li; + PlayerInfo p = players[consoleplayer]; + + Super.Init(parent, desc); + PickPlayerClass(); + mRotation = 0; + + li = GetItem('Playerdisplay'); + if (li != NULL) + { + li.SetValue(ListMenuItemPlayerDisplay.PDF_ROTATION, 0); + li.SetValue(ListMenuItemPlayerDisplay.PDF_MODE, 1); + li.SetValue(ListMenuItemPlayerDisplay.PDF_TRANSLATE, 1); + li.SetValue(ListMenuItemPlayerDisplay.PDF_CLASS, p.GetPlayerClassNum()); + if (mPlayerClass != NULL && !(GetDefaultByType (mPlayerClass.Type).bNoSkin) && + p.GetPlayerClassNum() != -1) + { + li.SetValue(ListMenuItemPlayerDisplay.PDF_SKIN, p.GetSkin()); + } + } + + li = GetItem('Playerbox'); + if (li != NULL) + { + li.SetString(0, p.GetUserName()); + } + + li = GetItem('Team'); + if (li != NULL) + { + li.SetString(0, "None"); + for(int i=0;i= 0 ? pclass : pclass + 1); + } + } + + UpdateSkins(); + + li = GetItem('Gender'); + if (li != NULL) + { + li.SetValue(0, p.GetGender()); + } + + li = GetItem('Autoaim'); + if (li != NULL) + { + li.SetValue(0, int(p.GetAutoaim())); + } + + li = GetItem('Switch'); + if (li != NULL) + { + li.SetValue(0, p.GetNeverSwitch()); + } + + li = GetItem('AlwaysRun'); + if (li != NULL) + { + li.SetValue(0, cl_run); + } + + if (mDesc.mSelectedItem < 0) mDesc.mSelectedItem = 1; + + } + + //============================================================================= // // @@ -199,6 +366,28 @@ class PlayerMenu : ListMenu native } + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder (InputEventData ev) + { + if (ev.type == InputEventData.GUI_Event && ev.subtype == InputEventData.GUI_Char && ev.data1 == 32) + { + // turn the player sprite around + mRotation = 8 - mRotation; + MenuItemBase li = GetItem('Playerdisplay'); + if (li != NULL) + { + li.SetValue(ListMenuItemPlayerDisplay.PDF_ROTATION, mRotation); + } + return true; + } + return Super.Responder(ev); + } + //============================================================================= // // diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index f7333220bc..8886e6744c 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -317,6 +317,9 @@ usercmd_t original_cmd; native int GetPlayerClassNum(); native int GetSkin(); native bool GetNeverSwitch(); + native int GetGender(); + native int GetTeam(); + native float GetAutoaim(); } struct PlayerClass native @@ -343,3 +346,10 @@ struct PlayerSkin native native readonly int crouchsprite; native readonly int namespc; }; + +struct Team native +{ + const NoTeam = 255; + const Max = 16; + native String mName; +} From 013e52fabdac535bf17dbb64a1d2e8db1726313d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 01:31:01 +0100 Subject: [PATCH 024/207] - fixed: newly created list menus did not call their scripted virtual Init method. --- src/menu/menu.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index c5b1b40714..f32c203737 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -630,7 +630,11 @@ void M_SetMenu(FName menu, int param) if (cls == nullptr) cls = PClass::FindClass("ListMenu"); DListMenu *newmenu = (DListMenu *)cls->CreateNew(); - newmenu->Init(DMenu::CurrentMenu, ld); + IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init) + { + VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld }; + GlobalVMStack.Call(func, params, 3, nullptr, 0); + } M_ActivateMenu(newmenu); } } From 0ffd475d8ca39fefaf1aa1c631edae3aff74f937 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 18 Feb 2017 10:34:27 +0200 Subject: [PATCH 025/207] Fixed compilation with GCC/Clang src/r_data/sprites.cpp:805:79: error: cannot pass non-trivial object of type 'FString' to variadic function; expected type from format string was 'char *' [-Wnon-pod-varargs] --- src/r_data/sprites.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 45167580fb..d6d6aa4e11 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -802,7 +802,7 @@ void R_InitSkins (void) if (spr == 0 && maxframe <= 0) { - Printf (PRINT_BOLD, "Skin %s (#%u) has no frames. Removing.\n", Skins[i].Name, i); + Printf (PRINT_BOLD, "Skin %s (#%u) has no frames. Removing.\n", Skins[i].Name.GetChars(), i); remove = true; break; } From 128dfdeee62593c23fd008219ef0c78c6bd21c0c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 12:36:31 +0100 Subject: [PATCH 026/207] - made some of the load/save menu's data a bit more scripting friendly, this mostly means removal of static string buffers. --- src/menu/loadsavemenu.cpp | 31 ++--- src/menu/menu.h | 2 +- src/menu/messagebox.cpp | 8 +- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/menu/loadsavemenu.txt | 128 ++++++++++++++++++++ 5 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 wadsrc/static/zscript/menu/loadsavemenu.txt diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index ec92a591f8..d90c03b662 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -120,8 +120,7 @@ int SavegameManager::InsertSaveNode(FSaveGameNode *node) unsigned int i; for (i = 0; i < SaveGames.Size(); i++) { - if (SaveGames[i]->bOldVersion || - stricmp(node->Title, SaveGames[i]->Title) <= 0) + if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0) { break; } @@ -212,7 +211,7 @@ void SavegameManager::ReadSaveStrings() node->Filename = filepath; node->bOldVersion = oldVer; node->bMissingWads = missing; - strncpy(node->Title, title.GetChars(), SAVESTRINGSIZE); + node->SaveTitle = title; InsertSaveNode(node); delete savegame; } @@ -287,7 +286,7 @@ void SavegameManager::ReadSaveStrings() node->Filename = filepath; node->bOldVersion = true; node->bMissingWads = false; - memcpy(node->Title, title, SAVESTRINGSIZE); + node->SaveTitle = title; InsertSaveNode(node); } fclose(file); @@ -324,7 +323,7 @@ void SavegameManager::NotifyNewSave(const char *file, const char *title, bool ok if (node->Filename.CompareNoCase(file) == 0) #endif { - strcpy(node->Title, title); + node->SaveTitle = title; node->bOldVersion = false; node->bMissingWads = false; if (okForQuicksave) @@ -337,7 +336,7 @@ void SavegameManager::NotifyNewSave(const char *file, const char *title, bool ok } node = new FSaveGameNode; - strcpy(node->Title, title); + node->SaveTitle = title; node->Filename = file; node->bOldVersion = false; node->bMissingWads = false; @@ -597,7 +596,6 @@ protected: // this needs to be kept in memory so that the texture can access it when it needs to. bool mEntering; - char savegamestring[SAVESTRINGSIZE]; DTextEnterMenu *mInput = nullptr; DLoadSaveMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); @@ -756,7 +754,7 @@ void DLoadSaveMenu::Drawer () if (!mEntering) { screen->DrawText (SmallFont, color, - listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->Title, + listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->SaveTitle.GetChars(), DTA_CleanNoMove, true, TAG_DONE); } else @@ -770,7 +768,7 @@ void DLoadSaveMenu::Drawer () else { screen->DrawText (SmallFont, color, - listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->Title, + listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->SaveTitle.GetChars(), DTA_CleanNoMove, true, TAG_DONE); } } @@ -936,7 +934,7 @@ bool DLoadSaveMenu::Responder (event_t *ev) { FString EndString; EndString.Format("%s" TEXTCOLOR_WHITE "%s" TEXTCOLOR_NORMAL "?\n\n%s", - GStrings("MNU_DELETESG"), manager->SaveGames[Selected]->Title, GStrings("PRESSYN")); + GStrings("MNU_DELETESG"), manager->SaveGames[Selected]->SaveTitle.GetChars(), GStrings("PRESSYN")); M_StartMessage (EndString, 0); } return true; @@ -991,7 +989,7 @@ IMPLEMENT_CLASS(DSaveMenu, false, false) DSaveMenu::DSaveMenu(DMenu *parent, DListMenuDescriptor *desc) : DLoadSaveMenu(parent, desc) { - strcpy (NewSaveNode.Title, GStrings["NEWSAVE"]); + NewSaveNode.SaveTitle = GStrings["NEWSAVE"]; NewSaveNode.bNoDelete = true; manager->SaveGames.Insert(0, &NewSaveNode); TopItem = 0; @@ -1042,15 +1040,8 @@ bool DSaveMenu::MenuEvent (int mkey, bool fromcontroller) if (mkey == MKEY_Enter) { - if (Selected != 0) - { - strcpy (savegamestring, manager->SaveGames[Selected]->Title); - } - else - { - savegamestring[0] = 0; - } - mInput = new DTextEnterMenu(this, savegamestring, SAVESTRINGSIZE, 1, fromcontroller); + const char *SavegameString = (Selected != 0)? manager->SaveGames[Selected]->SaveTitle.GetChars() : ""; + mInput = new DTextEnterMenu(this, SavegameString, SAVESTRINGSIZE, 1, fromcontroller); M_ActivateMenu(mInput); mEntering = true; } diff --git a/src/menu/menu.h b/src/menu/menu.h index d272fe242a..e48e178147 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -58,7 +58,7 @@ extern FGameStartup GameStartupInfo; struct FSaveGameNode { - char Title[SAVESTRINGSIZE]; + FString SaveTitle; FString Filename; bool bOldVersion; bool bMissingWads; diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index e15940acbb..b1d6025555 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -548,7 +548,7 @@ DQuickSaveMenu::DQuickSaveMenu(bool playsound) { FString tempstring; - tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->Title); + tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars()); Init(NULL, tempstring, 0, playsound); } @@ -562,7 +562,7 @@ void DQuickSaveMenu::HandleResult(bool res) { if (res) { - G_SaveGame (savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title); + G_SaveGame (savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); M_ClearMenus(); } @@ -601,7 +601,7 @@ CCMD (quicksave) // [mxd]. Just save the game, no questions asked. if (!saveloadconfirmation) { - G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title); + G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); return; } @@ -644,7 +644,7 @@ DQuickLoadMenu::DQuickLoadMenu(bool playsound) { FString tempstring; - tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->Title); + tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars()); Init(NULL, tempstring, 0, playsound); } diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index ae582e058e..419adfe76e 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -15,6 +15,7 @@ #include "zscript/menu/optionmenuitems.txt" #include "zscript/menu/colorpickermenu.txt" #include "zscript/menu/joystickmenu.txt" +#include "zscript/menu/loadsavemenu.txt" #include "zscript/menu/playermenu.txt" #include "zscript/menu/playerdisplay.txt" #include "zscript/menu/playercontrols.txt" diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt new file mode 100644 index 0000000000..b07c7a4893 --- /dev/null +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -0,0 +1,128 @@ +/* +** loadsavemenu.cpp +** The load game and save game menus +** +**--------------------------------------------------------------------------- +** Copyright 2001-2010 Randy Heit +** Copyright 2010-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +/* +struct SavegameManager native +{ + native int LastSaved; + native int LastAccessed; + native int WindowSize; + //SaveGameNode quickSaveSlot = nullptr; + //FBrokenLines *SaveComment = nullptr; + + void ClearSaveGames(); + int InsertSaveNode(FSaveGameNode *node); + int RemoveSaveSlot(int index); + void ReadSaveStrings(); + void NotifyNewSave(const char *file, const char *title, bool okForQuicksave); + void LoadSavegame(int Selected); + void DoSave(int Selected, const char *savegamestring); + void DeleteEntry(int Selected); + void ExtractSaveData(int index); + void UnloadSaveData(); + void ClearSaveStuff(); + bool DrawSavePic(int x, int y, int w, int h); + void SetFileInfo(int Selected); + +} +*/ + + +class LoadSaveMenu : ListMenu native +{ + //native SavegameManager manager; + //native int TopItem; + //native int Selected; +} + +class SaveMenu : LoadSaveMenu native +{ +} + +//============================================================================= +// +// +// +//============================================================================= + +class LoadMenu : LoadSaveMenu native +{ + //============================================================================= + // + // + // + //============================================================================= + + /* + override void Init(Menu parent, ListMenuDescriptor desc) + { + Super.Init(parent, desc); + TopItem = 0; + if (manager.LastAccessed != -1) + { + Selected = manager.LastAccessed; + } + manager.ExtractSaveData (Selected); + + } + */ + + //============================================================================= + // + // + // + //============================================================================= + + /* + override bool MenuEvent (int mkey, bool fromcontroller) + { + if (Super.MenuEvent(mkey, fromcontroller)) + { + return true; + } + if (Selected == -1 || manager.SaveGames.Size() == 0) + { + return false; + } + + if (mkey == MKEY_Enter) + { + manager.LoadSavegame(Selected); + return true; + } + return false; + } + */ +} \ No newline at end of file From 9d51266145ae7af888207ffc016e2a95b6e8b08a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 13:05:33 +0100 Subject: [PATCH 027/207] - some more encapsulation of savegame data in the savegame manager, because some of its info is not in a state that can be accessed directly through script code and needs a few helper functions. --- src/g_game.cpp | 2 +- src/menu/loadsavemenu.cpp | 124 +++++++++++++++++++++++++------------- src/menu/menu.h | 13 +++- 3 files changed, 94 insertions(+), 45 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index dcd36b041b..1c6c4cca9b 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2310,7 +2310,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio WriteZip(filename, savegame_filenames, savegame_content); - savegameManager.NotifyNewSave (filename.GetChars(), description, okForQuicksave); + savegameManager.NotifyNewSave (filename, description, okForQuicksave); // delete the JSON buffers we created just above. Everything else will // either still be needed or taken care of automatically. diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index d90c03b662..bfe7969704 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -304,11 +304,11 @@ void SavegameManager::ReadSaveStrings() // //============================================================================= -void SavegameManager::NotifyNewSave(const char *file, const char *title, bool okForQuicksave) +void SavegameManager::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave) { FSaveGameNode *node; - if (file == nullptr) + if (file.IsEmpty()) return; ReadSaveStrings(); @@ -555,6 +555,60 @@ void SavegameManager::SetFileInfo(int Selected) } } +//============================================================================= +// +// +// +//============================================================================= + +unsigned SavegameManager::SavegameCount() +{ + return SaveGames.Size(); +} + +//============================================================================= +// +// +// +//============================================================================= + +FSaveGameNode *SavegameManager::GetSavegame(unsigned i) +{ + return SaveGames[i]; +} + +//============================================================================= +// +// +// +//============================================================================= + +void SavegameManager::InsertNewSaveNode() +{ + NewSaveNode.SaveTitle = GStrings["NEWSAVE"]; + NewSaveNode.bNoDelete = true; + SaveGames.Insert(0, &NewSaveNode); +} + +//============================================================================= +// +// +// +//============================================================================= + +bool SavegameManager::RemoveNewSaveNode() +{ + if (SaveGames[0] == &NewSaveNode) + { + SaveGames.Delete(0); + return true; + } + return false; +} + + + + SavegameManager savegameManager; @@ -576,7 +630,6 @@ protected: int savepicTop; int savepicWidth; int savepicHeight; - int rowHeight; int listboxLeft; int listboxTop; @@ -680,10 +733,10 @@ void DLoadSaveMenu::Drawer () screen->Clear (savepicLeft, savepicTop, savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0); - if (manager->SaveGames.Size() > 0) + if (manager->SavegameCount() > 0) { const char *text = - (Selected == -1 || !manager->SaveGames[Selected]->bOldVersion) + (Selected == -1 || !manager->GetSavegame(Selected)->bOldVersion) ? GStrings("MNU_NOPICTURE") : GStrings("MNU_DIFFVERSION"); const int textlen = SmallFont->StringWidth (text)*CleanXfac; @@ -713,7 +766,7 @@ void DLoadSaveMenu::Drawer () V_DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); screen->Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0); - if (manager->SaveGames.Size() == 0) + if (manager->SavegameCount() == 0) { const char * text = GStrings("MNU_NOFILES"); const int textlen = SmallFont->StringWidth (text)*CleanXfac; @@ -724,10 +777,10 @@ void DLoadSaveMenu::Drawer () return; } - for (i = 0, j = TopItem; i < listboxRows && j < manager->SaveGames.Size(); i++,j++) + for (i = 0, j = TopItem; i < listboxRows && j < manager->SavegameCount(); i++,j++) { int color; - node = manager->SaveGames[j]; + node = manager->GetSavegame(j); if (node->bOldVersion) { color = CR_BLUE; @@ -785,12 +838,12 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) switch (mkey) { case MKEY_Up: - if (manager->SaveGames.Size() > 1) + if (manager->SavegameCount() > 1) { if (Selected == -1) Selected = TopItem; else { - if (--Selected < 0) Selected = manager->SaveGames.Size()-1; + if (--Selected < 0) Selected = manager->SavegameCount()-1; if (Selected < TopItem) TopItem = Selected; else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); } @@ -800,12 +853,12 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) return true; case MKEY_Down: - if (manager->SaveGames.Size() > 1) + if (manager->SavegameCount() > 1) { if (Selected == -1) Selected = TopItem; else { - if (unsigned(++Selected) >= manager->SaveGames.Size()) Selected = 0; + if (unsigned(++Selected) >= manager->SavegameCount()) Selected = 0; if (Selected < TopItem) TopItem = Selected; else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); } @@ -815,16 +868,16 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) return true; case MKEY_PageDown: - if (manager->SaveGames.Size() > 1) + if (manager->SavegameCount() > 1) { - if (TopItem >= (int)manager->SaveGames.Size() - listboxRows) + if (TopItem >= (int)manager->SavegameCount() - listboxRows) { TopItem = 0; if (Selected != -1) Selected = 0; } else { - TopItem = MIN(TopItem + listboxRows, manager->SaveGames.Size() - listboxRows); + TopItem = MIN(TopItem + listboxRows, manager->SavegameCount() - listboxRows); if (TopItem > Selected && Selected != -1) Selected = TopItem; } manager->UnloadSaveData (); @@ -833,11 +886,11 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) return true; case MKEY_PageUp: - if (manager->SaveGames.Size() > 1) + if (manager->SavegameCount() > 1) { if (TopItem == 0) { - TopItem = manager->SaveGames.Size() - listboxRows; + TopItem = manager->SavegameCount() - listboxRows; if (Selected != -1) Selected = TopItem; } else @@ -855,9 +908,9 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) case MKEY_MBYes: { - if ((unsigned)Selected < manager->SaveGames.Size()) + if ((unsigned)Selected < manager->SavegameCount()) { - int listindex = manager->SaveGames[0]->bNoDelete? Selected-1 : Selected; + int listindex = manager->GetSavegame(0)->bNoDelete? Selected-1 : Selected; manager->DeleteEntry(Selected); manager->UnloadSaveData (); Selected = manager->RemoveSaveSlot (Selected); @@ -889,7 +942,7 @@ bool DLoadSaveMenu::MouseEvent(int type, int x, int y) { int lineno = (y - listboxTop) / rowHeight; - if (TopItem + lineno < (int)manager->SaveGames.Size()) + if (TopItem + lineno < (int)manager->SavegameCount()) { Selected = TopItem + lineno; manager->UnloadSaveData (); @@ -921,7 +974,7 @@ bool DLoadSaveMenu::Responder (event_t *ev) { if (ev->subtype == EV_GUI_KeyDown) { - if ((unsigned)Selected < manager->SaveGames.Size()) + if ((unsigned)Selected < manager->SavegameCount()) { switch (ev->data1) { @@ -934,7 +987,7 @@ bool DLoadSaveMenu::Responder (event_t *ev) { FString EndString; EndString.Format("%s" TEXTCOLOR_WHITE "%s" TEXTCOLOR_NORMAL "?\n\n%s", - GStrings("MNU_DELETESG"), manager->SaveGames[Selected]->SaveTitle.GetChars(), GStrings("PRESSYN")); + GStrings("MNU_DELETESG"), manager->GetSavegame(Selected)->SaveTitle.GetChars(), GStrings("PRESSYN")); M_StartMessage (EndString, 0); } return true; @@ -948,7 +1001,7 @@ bool DLoadSaveMenu::Responder (event_t *ev) } else if (ev->subtype == EV_GUI_WheelDown) { - if (TopItem < (int)manager->SaveGames.Size() - listboxRows) TopItem++; + if (TopItem < (int)manager->SavegameCount() - listboxRows) TopItem++; return true; } } @@ -966,8 +1019,6 @@ class DSaveMenu : public DLoadSaveMenu { DECLARE_CLASS(DSaveMenu, DLoadSaveMenu) - FSaveGameNode NewSaveNode; - public: DSaveMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); @@ -989,18 +1040,9 @@ IMPLEMENT_CLASS(DSaveMenu, false, false) DSaveMenu::DSaveMenu(DMenu *parent, DListMenuDescriptor *desc) : DLoadSaveMenu(parent, desc) { - NewSaveNode.SaveTitle = GStrings["NEWSAVE"]; - NewSaveNode.bNoDelete = true; - manager->SaveGames.Insert(0, &NewSaveNode); + manager->InsertNewSaveNode(); TopItem = 0; - if (manager->LastSaved == -1) - { - Selected = 0; - } - else - { - Selected = manager->LastSaved + 1; - } + Selected = manager->LastSaved + 1; manager->ExtractSaveData (Selected); } @@ -1012,11 +1054,9 @@ DSaveMenu::DSaveMenu(DMenu *parent, DListMenuDescriptor *desc) void DSaveMenu::OnDestroy() { - if (manager->SaveGames[0] == &NewSaveNode) + if (manager->RemoveNewSaveNode()) { - manager->SaveGames.Delete(0); - if (Selected == 0) Selected = -1; - else Selected--; + Selected--; } Super::OnDestroy(); } @@ -1040,7 +1080,7 @@ bool DSaveMenu::MenuEvent (int mkey, bool fromcontroller) if (mkey == MKEY_Enter) { - const char *SavegameString = (Selected != 0)? manager->SaveGames[Selected]->SaveTitle.GetChars() : ""; + const char *SavegameString = (Selected != 0)? manager->GetSavegame(Selected)->SaveTitle.GetChars() : ""; mInput = new DTextEnterMenu(this, SavegameString, SAVESTRINGSIZE, 1, fromcontroller); M_ActivateMenu(mInput); mEntering = true; @@ -1139,7 +1179,7 @@ bool DLoadMenu::MenuEvent (int mkey, bool fromcontroller) { return true; } - if (Selected == -1 || manager->SaveGames.Size() == 0) + if (Selected == -1 || manager->SavegameCount() == 0) { return false; } diff --git a/src/menu/menu.h b/src/menu/menu.h index e48e178147..642d36e99f 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -69,7 +69,10 @@ struct FSaveGameNode struct SavegameManager { +private: TArray SaveGames; + FSaveGameNode NewSaveNode; +public: int LastSaved = -1; int LastAccessed = -1; int WindowSize = 0; @@ -81,11 +84,13 @@ struct SavegameManager FTexture *SavePic = nullptr; FBrokenLines *SaveComment = nullptr; - void ClearSaveGames(); +private: int InsertSaveNode(FSaveGameNode *node); +public: + void ClearSaveGames(); int RemoveSaveSlot(int index); void ReadSaveStrings(); - void NotifyNewSave(const char *file, const char *title, bool okForQuicksave); + void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave); void LoadSavegame(int Selected); void DoSave(int Selected, const char *savegamestring); void DeleteEntry(int Selected); @@ -94,6 +99,10 @@ struct SavegameManager void ClearSaveStuff(); bool DrawSavePic(int x, int y, int w, int h); void SetFileInfo(int Selected); + unsigned SavegameCount(); + FSaveGameNode *GetSavegame(unsigned i); + void InsertNewSaveNode(); + bool RemoveNewSaveNode(); }; From 872969eb140e5c46348e7defadcee3aabb227921 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 14:08:16 +0100 Subject: [PATCH 028/207] - scriptified the LoadMenu class and exported the entire interface to handle the LoadSaveMenu. --- src/menu/loadsavemenu.cpp | 190 +++++++++++++------- src/menu/menu.cpp | 2 +- src/menu/menu.h | 38 ++-- wadsrc/static/zscript/base.txt | 5 - wadsrc/static/zscript/menu/loadsavemenu.txt | 90 ++++++---- 5 files changed, 208 insertions(+), 117 deletions(-) diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index bfe7969704..56cd60b39f 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -50,25 +50,13 @@ #include "resourcefiles/resourcefile.h" -//============================================================================= -// -// This should remain native because exposing 'remove' would allow -// the creation of actual malware mods! -// -//============================================================================= - -void SavegameManager::DeleteEntry(int Selected) -{ - remove(SaveGames[Selected]->Filename.GetChars()); -} - //============================================================================= // // Save data maintenance // //============================================================================= -void SavegameManager::ClearSaveGames() +void FSavegameManager::ClearSaveGames() { for (unsigned i = 0; ibNoDelete ? index - 1 : index; + if (listindex < 0) return index; + + remove(SaveGames[index]->Filename.GetChars()); + UnloadSaveData(); + FSaveGameNode *file = SaveGames[index]; if (quickSaveSlot == SaveGames[index]) @@ -93,8 +87,15 @@ int SavegameManager::RemoveSaveSlot(int index) quickSaveSlot = nullptr; } if (!file->bNoDelete) delete file; + + if (LastSaved == listindex) LastSaved = -1; + else if (LastSaved > listindex) LastSaved--; + if (LastAccessed == listindex) LastAccessed = -1; + else if (LastAccessed > listindex) LastAccessed--; + SaveGames.Delete(index); if ((unsigned)index >= SaveGames.Size()) index--; + ExtractSaveData(index); return index; } @@ -104,7 +105,7 @@ int SavegameManager::RemoveSaveSlot(int index) // //============================================================================= -int SavegameManager::InsertSaveNode(FSaveGameNode *node) +int FSavegameManager::InsertSaveNode(FSaveGameNode *node) { if (SaveGames.Size() == 0) { @@ -138,7 +139,7 @@ int SavegameManager::InsertSaveNode(FSaveGameNode *node) // //============================================================================= -void SavegameManager::ReadSaveStrings() +void FSavegameManager::ReadSaveStrings() { if (SaveGames.Size() == 0) { @@ -304,7 +305,7 @@ void SavegameManager::ReadSaveStrings() // //============================================================================= -void SavegameManager::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave) +void FSavegameManager::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave) { FSaveGameNode *node; @@ -355,7 +356,7 @@ void SavegameManager::NotifyNewSave(const FString &file, const FString &title, b // //============================================================================= -void SavegameManager::LoadSavegame(int Selected) +void FSavegameManager::LoadSavegame(int Selected) { G_LoadGame(SaveGames[Selected]->Filename.GetChars(), true); if (quickSaveSlot == (FSaveGameNode*)1) @@ -367,13 +368,21 @@ void SavegameManager::LoadSavegame(int Selected) LastAccessed = Selected; } +DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_INT(sel); + self->LoadSavegame(sel); + return 0; +} + //============================================================================= // // // //============================================================================= -void SavegameManager::DoSave(int Selected, const char *savegamestring) +void FSavegameManager::DoSave(int Selected, const char *savegamestring) { if (Selected != 0) { @@ -409,11 +418,23 @@ void SavegameManager::DoSave(int Selected, const char *savegamestring) // //============================================================================= -void SavegameManager::ExtractSaveData(int index) +unsigned FSavegameManager::ExtractSaveData(int index) { FResourceFile *resf; FSaveGameNode *node; + if (index == -1) + { + if (SaveGames.Size() > 0 && SaveGames[0]->bNoDelete) + { + index = LastSaved + 1; + } + else + { + index = LastAccessed + 1; + } + } + UnloadSaveData(); if ((unsigned)index < SaveGames.Size() && @@ -426,7 +447,7 @@ void SavegameManager::ExtractSaveData(int index) if (info == nullptr) { // this should not happen because the file has already been verified. - return; + return index; } void *data = info->CacheLump(); FSerializer arc; @@ -476,6 +497,14 @@ void SavegameManager::ExtractSaveData(int index) } delete resf; } + return index; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_INT(sel); + ACTION_RETURN_INT(self->ExtractSaveData(sel)); } //============================================================================= @@ -484,7 +513,7 @@ void SavegameManager::ExtractSaveData(int index) // //============================================================================= -void SavegameManager::UnloadSaveData() +void FSavegameManager::UnloadSaveData() { if (SavePic != nullptr) { @@ -511,7 +540,7 @@ void SavegameManager::UnloadSaveData() // //============================================================================= -void SavegameManager::ClearSaveStuff() +void FSavegameManager::ClearSaveStuff() { UnloadSaveData(); if (quickSaveSlot == (FSaveGameNode*)1) @@ -527,7 +556,7 @@ void SavegameManager::ClearSaveStuff() // //============================================================================= -bool SavegameManager::DrawSavePic(int x, int y, int w, int h) +bool FSavegameManager::DrawSavePic(int x, int y, int w, int h) { if (SavePic == nullptr) return false; screen->DrawTexture(SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE); @@ -540,7 +569,33 @@ bool SavegameManager::DrawSavePic(int x, int y, int w, int h) // //============================================================================= -void SavegameManager::SetFileInfo(int Selected) +void FSavegameManager::DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor) +{ + int sx = CleanXfac; + int sy = CleanYfac; + + CleanXfac = CleanYfac = scalefactor; + + // I'm not sure why SaveComment would go nullptr in this loop, but I got + // a crash report where it was nullptr when i reached 1, so now I check + // for that. + for (int i = 0; SaveComment != nullptr && SaveComment[i].Width >= 0 && i < 6; ++i) + { + screen->DrawText(font, cr, x, y + font->GetHeight() * i * scalefactor, SaveComment[i].Text, DTA_CleanNoMove, true, TAG_DONE); + } + + CleanXfac = sx; + CleanYfac = sy; +} + + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManager::SetFileInfo(int Selected) { if (!SaveGames[Selected]->Filename.IsEmpty()) { @@ -561,18 +616,24 @@ void SavegameManager::SetFileInfo(int Selected) // //============================================================================= -unsigned SavegameManager::SavegameCount() +unsigned FSavegameManager::SavegameCount() { return SaveGames.Size(); } +DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + ACTION_RETURN_INT(self->SavegameCount()); +} + //============================================================================= // // // //============================================================================= -FSaveGameNode *SavegameManager::GetSavegame(unsigned i) +FSaveGameNode *FSavegameManager::GetSavegame(unsigned i) { return SaveGames[i]; } @@ -583,7 +644,7 @@ FSaveGameNode *SavegameManager::GetSavegame(unsigned i) // //============================================================================= -void SavegameManager::InsertNewSaveNode() +void FSavegameManager::InsertNewSaveNode() { NewSaveNode.SaveTitle = GStrings["NEWSAVE"]; NewSaveNode.bNoDelete = true; @@ -596,7 +657,7 @@ void SavegameManager::InsertNewSaveNode() // //============================================================================= -bool SavegameManager::RemoveNewSaveNode() +bool FSavegameManager::RemoveNewSaveNode() { if (SaveGames[0] == &NewSaveNode) { @@ -609,7 +670,7 @@ bool SavegameManager::RemoveNewSaveNode() -SavegameManager savegameManager; +FSavegameManager savegameManager; @@ -618,9 +679,9 @@ class DLoadSaveMenu : public DListMenu { DECLARE_CLASS(DLoadSaveMenu, DListMenu) -protected: +public: - SavegameManager *manager; + FSavegameManager *manager; int Selected; int TopItem; @@ -749,18 +810,8 @@ void DLoadSaveMenu::Drawer () // Draw comment area V_DrawFrame (commentLeft, commentTop, commentWidth, commentHeight); screen->Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0); - if (manager->SaveComment != nullptr) - { - // I'm not sure why SaveComment would go nullptr in this loop, but I got - // a crash report where it was nullptr when i reached 1, so now I check - // for that. - for (i = 0; manager->SaveComment != nullptr && manager->SaveComment[i].Width >= 0 && i < 6; ++i) - { - screen->DrawText (SmallFont, CR_GOLD, commentLeft, commentTop - + SmallFont->GetHeight()*i*CleanYfac, manager->SaveComment[i].Text, - DTA_CleanNoMove, true, TAG_DONE); - } - } + + // manager->DrawSaveComment(SmallFont, CR_GOLD, commentLeft, commentTop, CleanYfac); // Draw file area V_DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); @@ -910,16 +961,7 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) { if ((unsigned)Selected < manager->SavegameCount()) { - int listindex = manager->GetSavegame(0)->bNoDelete? Selected-1 : Selected; - manager->DeleteEntry(Selected); - manager->UnloadSaveData (); Selected = manager->RemoveSaveSlot (Selected); - manager->ExtractSaveData (Selected); - - if (manager->LastSaved == listindex) manager->LastSaved = -1; - else if (manager->LastSaved > listindex) manager->LastSaved--; - if (manager->LastAccessed == listindex) manager->LastAccessed = -1; - else if (manager->LastAccessed > listindex) manager->LastAccessed--; } return true; } @@ -1042,8 +1084,7 @@ DSaveMenu::DSaveMenu(DMenu *parent, DListMenuDescriptor *desc) { manager->InsertNewSaveNode(); TopItem = 0; - Selected = manager->LastSaved + 1; - manager->ExtractSaveData (Selected); + Selected = manager->ExtractSaveData (-1); } //============================================================================= @@ -1159,11 +1200,7 @@ DLoadMenu::DLoadMenu(DMenu *parent, DListMenuDescriptor *desc) : DLoadSaveMenu(parent, desc) { TopItem = 0; - if (manager->LastAccessed != -1) - { - Selected = manager->LastAccessed; - } - manager->ExtractSaveData (Selected); + Selected = manager->ExtractSaveData (-1); } @@ -1192,3 +1229,36 @@ bool DLoadMenu::MenuEvent (int mkey, bool fromcontroller) return false; } + +DEFINE_FIELD(FSaveGameNode, SaveTitle); +DEFINE_FIELD(FSaveGameNode, Filename); +DEFINE_FIELD(FSaveGameNode, bOldVersion); +DEFINE_FIELD(FSaveGameNode, bMissingWads); +DEFINE_FIELD(FSaveGameNode, bNoDelete); + +DEFINE_FIELD(FSavegameManager, WindowSize); +DEFINE_FIELD(FSavegameManager, quickSaveSlot); + +DEFINE_FIELD(DLoadSaveMenu, manager); +DEFINE_FIELD(DLoadSaveMenu, Selected); +DEFINE_FIELD(DLoadSaveMenu, TopItem); +DEFINE_FIELD(DLoadSaveMenu, savepicLeft); +DEFINE_FIELD(DLoadSaveMenu, savepicTop); +DEFINE_FIELD(DLoadSaveMenu, savepicWidth); +DEFINE_FIELD(DLoadSaveMenu, savepicHeight); +DEFINE_FIELD(DLoadSaveMenu, rowHeight); +DEFINE_FIELD(DLoadSaveMenu, listboxLeft); +DEFINE_FIELD(DLoadSaveMenu, listboxTop); +DEFINE_FIELD(DLoadSaveMenu, listboxWidth); +DEFINE_FIELD(DLoadSaveMenu, listboxRows); +DEFINE_FIELD(DLoadSaveMenu, listboxHeight); +DEFINE_FIELD(DLoadSaveMenu, listboxRight); +DEFINE_FIELD(DLoadSaveMenu, listboxBottom); +DEFINE_FIELD(DLoadSaveMenu, commentLeft); +DEFINE_FIELD(DLoadSaveMenu, commentTop); +DEFINE_FIELD(DLoadSaveMenu, commentWidth); +DEFINE_FIELD(DLoadSaveMenu, commentHeight); +DEFINE_FIELD(DLoadSaveMenu, commentRight); +DEFINE_FIELD(DLoadSaveMenu, commentBottom); +DEFINE_FIELD(DLoadSaveMenu, mEntering); +DEFINE_FIELD(DLoadSaveMenu, mInput); diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index f32c203737..ee7d5cbdb1 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -630,7 +630,7 @@ void M_SetMenu(FName menu, int param) if (cls == nullptr) cls = PClass::FindClass("ListMenu"); DListMenu *newmenu = (DListMenu *)cls->CreateNew(); - IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init) + IFVIRTUALPTRNAME(newmenu, "ListMenu", Init) { VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld }; GlobalVMStack.Call(func, params, 3, nullptr, 0); diff --git a/src/menu/menu.h b/src/menu/menu.h index 642d36e99f..c73b8a7b6a 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -60,44 +60,44 @@ struct FSaveGameNode { FString SaveTitle; FString Filename; - bool bOldVersion; - bool bMissingWads; - bool bNoDelete; - - FSaveGameNode() { bNoDelete = false; } + bool bOldVersion = false; + bool bMissingWads = false; + bool bNoDelete = false; }; -struct SavegameManager +struct FSavegameManager { private: TArray SaveGames; FSaveGameNode NewSaveNode; -public: int LastSaved = -1; int LastAccessed = -1; + FileReader *currentSavePic = nullptr; + TArray SavePicData; + FTexture *SavePic = nullptr; + FBrokenLines *SaveComment = nullptr; + +public: int WindowSize = 0; FSaveGameNode *quickSaveSlot = nullptr; - FileReader *currentSavePic = nullptr; - TArray SavePicData; - - FTexture *SavePic = nullptr; - FBrokenLines *SaveComment = nullptr; private: int InsertSaveNode(FSaveGameNode *node); public: - void ClearSaveGames(); - int RemoveSaveSlot(int index); - void ReadSaveStrings(); void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave); + void ClearSaveGames(); + + void ReadSaveStrings(); + void UnloadSaveData(); + + int RemoveSaveSlot(int index); void LoadSavegame(int Selected); void DoSave(int Selected, const char *savegamestring); - void DeleteEntry(int Selected); - void ExtractSaveData(int index); - void UnloadSaveData(); + unsigned ExtractSaveData(int index); void ClearSaveStuff(); bool DrawSavePic(int x, int y, int w, int h); + void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor); void SetFileInfo(int Selected); unsigned SavegameCount(); FSaveGameNode *GetSavegame(unsigned i); @@ -106,7 +106,7 @@ public: }; -extern SavegameManager savegameManager; +extern FSavegameManager savegameManager; //============================================================================= // diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 57bdc7b019..6c5d671dee 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -158,11 +158,6 @@ enum DrawTextureTags struct Screen native { - int CleanWidth, CleanHeight; - int CleanXFac, CleanYFac; - int CleanWidth_1, CleanHeight_1; - int CleanXFac_1, CleanYFac_1; - native static Color PaletteColor(int index); native static int GetWidth(); native static int GetHeight(); diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index b07c7a4893..8700494120 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -33,38 +33,72 @@ ** */ -/* + +struct SaveGameNode native +{ + native String SaveTitle; + native String Filename; + native bool bOldVersion; + native bool bMissingWads; + native bool bNoDelete; +} + struct SavegameManager native { - native int LastSaved; - native int LastAccessed; native int WindowSize; - //SaveGameNode quickSaveSlot = nullptr; - //FBrokenLines *SaveComment = nullptr; + native SaveGameNode quickSaveSlot; - void ClearSaveGames(); - int InsertSaveNode(FSaveGameNode *node); - int RemoveSaveSlot(int index); - void ReadSaveStrings(); - void NotifyNewSave(const char *file, const char *title, bool okForQuicksave); - void LoadSavegame(int Selected); - void DoSave(int Selected, const char *savegamestring); - void DeleteEntry(int Selected); - void ExtractSaveData(int index); - void UnloadSaveData(); - void ClearSaveStuff(); - bool DrawSavePic(int x, int y, int w, int h); - void SetFileInfo(int Selected); + //void ReadSaveStrings(); + //void UnloadSaveData(); + + //int RemoveSaveSlot(int index); + native void LoadSavegame(int Selected); + //void DoSave(int Selected, String savegamestring); + native int ExtractSaveData(int index); + //void ClearSaveStuff(); + //bool DrawSavePic(int x, int y, int w, int h); + //void DrawSaveComment(Font font, int cr, int x, int y, int scalefactor); + //void SetFileInfo(int Selected); + native int SavegameCount(); + //SaveGameNode GetSavegame(int i); + //void InsertNewSaveNode(); + //bool RemoveNewSaveNode(); } -*/ + class LoadSaveMenu : ListMenu native { - //native SavegameManager manager; - //native int TopItem; - //native int Selected; + native SavegameManager manager; + native int TopItem; + native int Selected; + + native int savepicLeft; + native int savepicTop; + native int savepicWidth; + native int savepicHeight; + native int rowHeight; + native int listboxLeft; + native int listboxTop; + native int listboxWidth; + + native int listboxRows; + native int listboxHeight; + native int listboxRight; + native int listboxBottom; + + native int commentLeft; + native int commentTop; + native int commentWidth; + native int commentHeight; + native int commentRight; + native int commentBottom; + + native bool mEntering; + native TextEnterMenu mInput; + + } class SaveMenu : LoadSaveMenu native @@ -85,19 +119,13 @@ class LoadMenu : LoadSaveMenu native // //============================================================================= - /* override void Init(Menu parent, ListMenuDescriptor desc) { Super.Init(parent, desc); TopItem = 0; - if (manager.LastAccessed != -1) - { - Selected = manager.LastAccessed; - } - manager.ExtractSaveData (Selected); + Selected = manager.ExtractSaveData (-1); } - */ //============================================================================= // @@ -105,14 +133,13 @@ class LoadMenu : LoadSaveMenu native // //============================================================================= - /* override bool MenuEvent (int mkey, bool fromcontroller) { if (Super.MenuEvent(mkey, fromcontroller)) { return true; } - if (Selected == -1 || manager.SaveGames.Size() == 0) + if (Selected == -1 || manager.SavegameCount() == 0) { return false; } @@ -124,5 +151,4 @@ class LoadMenu : LoadSaveMenu native } return false; } - */ } \ No newline at end of file From e58a03de9bb8a3a643ffcf7e2768dcde6b239a7c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 14:18:27 +0100 Subject: [PATCH 029/207] - the savegame manager needs a destructor --- src/menu/loadsavemenu.cpp | 4 ++++ src/menu/menu.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 56cd60b39f..b8989d2fa6 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -66,6 +66,10 @@ void FSavegameManager::ClearSaveGames() SaveGames.Clear(); } +FSavegameManager::~FSavegameManager() +{ + ClearSaveGames(); +} //============================================================================= // // Save data maintenance diff --git a/src/menu/menu.h b/src/menu/menu.h index c73b8a7b6a..2241513cb2 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -80,7 +80,7 @@ private: public: int WindowSize = 0; FSaveGameNode *quickSaveSlot = nullptr; - + ~FSavegameManager(); private: int InsertSaveNode(FSaveGameNode *node); From ee6a90deece2c700f63d5ba5a421666b5ceb26bb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 16:40:32 +0100 Subject: [PATCH 030/207] - scriptified DLoadSaveMenu::Responder. - scriptified DSaveMenu. --- src/d_net.cpp | 5 +- src/g_game.cpp | 14 +- src/menu/loadsavemenu.cpp | 293 ++++---------------- src/version.h | 3 - wadsrc/static/zscript/menu/loadsavemenu.txt | 164 ++++++++++- 5 files changed, 217 insertions(+), 262 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 0985cf41c9..a480ae0ae7 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -73,7 +73,7 @@ EXTERN_CVAR (Int, autosavecount) #define SIMULATEERRORS 0 extern BYTE *demo_p; // [RH] Special "ticcmds" get recorded in demos -extern char savedescription[SAVESTRINGSIZE]; +extern FString savedescription; extern FString savegamefile; extern short consistancy[MAXPLAYERS][BACKUPTICS]; @@ -2418,8 +2418,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) savegamefile = s; delete[] s; s = ReadString (stream); - memset (savedescription, 0, sizeof(savedescription)); - strncpy (savedescription, s, sizeof(savedescription)); + savedescription = s; if (player != consoleplayer) { // Paths sent over the network will be valid for the system that sent diff --git a/src/g_game.cpp b/src/g_game.cpp index 1c6c4cca9b..e5a48c245e 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -226,7 +226,7 @@ int mousex; int mousey; FString savegamefile; -char savedescription[SAVESTRINGSIZE]; +FString savedescription; // [RH] Name of screenshot file to generate (usually NULL) FString shotfile; @@ -1081,7 +1081,7 @@ void G_Ticker () G_DoSaveGame (true, savegamefile, savedescription); gameaction = ga_nothing; savegamefile = ""; - savedescription[0] = '\0'; + savedescription = ""; break; case ga_autosave: G_DoAutoSave (); @@ -2068,8 +2068,7 @@ void G_SaveGame (const char *filename, const char *description) else { savegamefile = filename; - strncpy (savedescription, description, sizeof(savedescription)-1); - savedescription[sizeof(savedescription)-1] = '\0'; + savedescription = description; sendsave = true; } } @@ -2119,7 +2118,7 @@ extern void P_CalcHeight (player_t *); void G_DoAutoSave () { - char description[SAVESTRINGSIZE]; + FString description; FString file; // Keep up to four autosaves at a time UCVarValue num; @@ -2147,10 +2146,7 @@ void G_DoAutoSave () } readableTime = myasctime (); - strcpy (description, "Autosave "); - strncpy (description+9, readableTime+4, 12); - description[9+12] = 0; - + description.Format("Autosave %.12s", readableTime + 4); G_DoSaveGame (false, file, description); } diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index b8989d2fa6..4bfc8c50e3 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -49,6 +49,8 @@ #include "serializer.h" #include "resourcefiles/resourcefile.h" +// Save name length limit for old binary formats. +#define OLDSAVESTRINGSIZE 24 //============================================================================= // @@ -229,7 +231,7 @@ void FSavegameManager::ReadSaveStrings() { PNGHandle *png; char sig[16]; - char title[SAVESTRINGSIZE + 1]; + char title[OLDSAVESTRINGSIZE + 1]; bool oldVer = true; bool addIt = false; bool missing = false; @@ -241,7 +243,7 @@ void FSavegameManager::ReadSaveStrings() // Old savegame versions are always added to the menu so // the user can easily delete them if desired. - title[SAVESTRINGSIZE] = 0; + title[OLDSAVESTRINGSIZE] = 0; if (nullptr != (png = M_VerifyPNG(file))) @@ -250,9 +252,9 @@ void FSavegameManager::ReadSaveStrings() if (ver != nullptr) { // An old version - if (!M_GetPNGText(png, "Title", title, SAVESTRINGSIZE)) + if (!M_GetPNGText(png, "Title", title, OLDSAVESTRINGSIZE)) { - strncpy(title, I_FindName(&c_file), SAVESTRINGSIZE); + strncpy(title, I_FindName(&c_file), OLDSAVESTRINGSIZE); } addIt = true; delete[] ver; @@ -267,7 +269,7 @@ void FSavegameManager::ReadSaveStrings() if (strncmp(sig, "ZDOOMSAVE", 9) == 0) { - if (fread(title, 1, SAVESTRINGSIZE, file) == SAVESTRINGSIZE) + if (fread(title, 1, OLDSAVESTRINGSIZE, file) == OLDSAVESTRINGSIZE) { addIt = true; } @@ -275,7 +277,7 @@ void FSavegameManager::ReadSaveStrings() else { memcpy(title, sig, 16); - if (fread(title + 16, 1, SAVESTRINGSIZE - 16, file) == SAVESTRINGSIZE - 16 && + if (fread(title + 16, 1, OLDSAVESTRINGSIZE - 16, file) == OLDSAVESTRINGSIZE - 16 && fread(sig, 1, 16, file) == 16 && strncmp(sig, "ZDOOMSAVE", 9) == 0) { @@ -416,6 +418,15 @@ void FSavegameManager::DoSave(int Selected, const char *savegamestring) V_SetBorderNeedRefresh(); } +DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_INT(sel); + PARAM_STRING(name); + self->DoSave(sel, name); + return 0; +} + //============================================================================= // // @@ -435,7 +446,7 @@ unsigned FSavegameManager::ExtractSaveData(int index) } else { - index = LastAccessed + 1; + index = LastAccessed < 0? 0 : LastAccessed; } } @@ -538,6 +549,13 @@ void FSavegameManager::UnloadSaveData() SavePicData.Clear(); } +DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + self->UnloadSaveData(); + return 0; +} + //============================================================================= // // @@ -614,6 +632,15 @@ void FSavegameManager::SetFileInfo(int Selected) } } +DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_INT(i); + self->SetFileInfo(i); + return 0; +} + + //============================================================================= // // @@ -642,6 +669,13 @@ FSaveGameNode *FSavegameManager::GetSavegame(unsigned i) return SaveGames[i]; } +DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_INT(i); + ACTION_RETURN_POINTER(self->GetSavegame(i)); +} + //============================================================================= // // @@ -655,6 +689,13 @@ void FSavegameManager::InsertNewSaveNode() SaveGames.Insert(0, &NewSaveNode); } +DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + self->InsertNewSaveNode(); + return 0; +} + //============================================================================= // // @@ -671,7 +712,11 @@ bool FSavegameManager::RemoveNewSaveNode() return false; } - +DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + ACTION_RETURN_INT(self->RemoveNewSaveNode()); +} FSavegameManager savegameManager; @@ -712,7 +757,6 @@ public: int commentRight; int commentBottom; - // this needs to be kept in memory so that the texture can access it when it needs to. bool mEntering; DTextEnterMenu *mInput = nullptr; @@ -722,7 +766,6 @@ public: void Drawer (); bool MenuEvent (int mkey, bool fromcontroller); bool MouseEvent(int type, int x, int y); - bool Responder(event_t *ev); }; IMPLEMENT_CLASS(DLoadSaveMenu, false, false) @@ -745,7 +788,7 @@ DLoadSaveMenu::DLoadSaveMenu(DMenu *parent, DListMenuDescriptor *desc) savepicTop = 54*CleanYfac; savepicWidth = 216*screen->GetWidth()/640; savepicHeight = 135*screen->GetHeight()/400; - manager->WindowSize = savepicWidth; + manager->WindowSize = savepicWidth / CleanXfac; rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac; listboxLeft = savepicLeft + savepicWidth + 14; @@ -815,7 +858,7 @@ void DLoadSaveMenu::Drawer () V_DrawFrame (commentLeft, commentTop, commentWidth, commentHeight); screen->Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0); - // manager->DrawSaveComment(SmallFont, CR_GOLD, commentLeft, commentTop, CleanYfac); + manager->DrawSaveComment(SmallFont, CR_GOLD, commentLeft, commentTop, CleanYfac); // Draw file area V_DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); @@ -1008,232 +1051,6 @@ bool DLoadSaveMenu::MouseEvent(int type, int x, int y) return Super::MouseEvent(type, x, y); } -//============================================================================= -// -// -// -//============================================================================= - -bool DLoadSaveMenu::Responder (event_t *ev) -{ - if (ev->type == EV_GUI_Event) - { - if (ev->subtype == EV_GUI_KeyDown) - { - if ((unsigned)Selected < manager->SavegameCount()) - { - switch (ev->data1) - { - case GK_F1: - manager->SetFileInfo(Selected); - return true; - - case GK_DEL: - case '\b': - { - FString EndString; - EndString.Format("%s" TEXTCOLOR_WHITE "%s" TEXTCOLOR_NORMAL "?\n\n%s", - GStrings("MNU_DELETESG"), manager->GetSavegame(Selected)->SaveTitle.GetChars(), GStrings("PRESSYN")); - M_StartMessage (EndString, 0); - } - return true; - } - } - } - else if (ev->subtype == EV_GUI_WheelUp) - { - if (TopItem > 0) TopItem--; - return true; - } - else if (ev->subtype == EV_GUI_WheelDown) - { - if (TopItem < (int)manager->SavegameCount() - listboxRows) TopItem++; - return true; - } - } - return Super::Responder(ev); -} - - -//============================================================================= -// -// -// -//============================================================================= - -class DSaveMenu : public DLoadSaveMenu -{ - DECLARE_CLASS(DSaveMenu, DLoadSaveMenu) - -public: - - DSaveMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); - void OnDestroy() override; - bool Responder (event_t *ev); - bool MenuEvent (int mkey, bool fromcontroller); - -}; - -IMPLEMENT_CLASS(DSaveMenu, false, false) - - -//============================================================================= -// -// -// -//============================================================================= - -DSaveMenu::DSaveMenu(DMenu *parent, DListMenuDescriptor *desc) -: DLoadSaveMenu(parent, desc) -{ - manager->InsertNewSaveNode(); - TopItem = 0; - Selected = manager->ExtractSaveData (-1); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DSaveMenu::OnDestroy() -{ - if (manager->RemoveNewSaveNode()) - { - Selected--; - } - Super::OnDestroy(); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DSaveMenu::MenuEvent (int mkey, bool fromcontroller) -{ - if (Super::MenuEvent(mkey, fromcontroller)) - { - return true; - } - if (Selected == -1) - { - return false; - } - - if (mkey == MKEY_Enter) - { - const char *SavegameString = (Selected != 0)? manager->GetSavegame(Selected)->SaveTitle.GetChars() : ""; - mInput = new DTextEnterMenu(this, SavegameString, SAVESTRINGSIZE, 1, fromcontroller); - M_ActivateMenu(mInput); - mEntering = true; - } - else if (mkey == MKEY_Input) - { - mEntering = false; - manager->DoSave(Selected, mInput->GetText()); - mInput = nullptr; - } - else if (mkey == MKEY_Abort) - { - mEntering = false; - mInput = nullptr; - } - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DSaveMenu::Responder (event_t *ev) -{ - if (ev->subtype == EV_GUI_KeyDown) - { - if (Selected != -1) - { - switch (ev->data1) - { - case GK_DEL: - case '\b': - // cannot delete 'new save game' item - if (Selected == 0) return true; - break; - - case 'N': - Selected = TopItem = 0; - manager->UnloadSaveData (); - return true; - } - } - } - return Super::Responder(ev); -} - -//============================================================================= -// -// -// -//============================================================================= - -class DLoadMenu : public DLoadSaveMenu -{ - DECLARE_CLASS(DLoadMenu, DLoadSaveMenu) - -public: - - DLoadMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); - - bool MenuEvent (int mkey, bool fromcontroller); -}; - -IMPLEMENT_CLASS(DLoadMenu, false, false) - - -//============================================================================= -// -// -// -//============================================================================= - -DLoadMenu::DLoadMenu(DMenu *parent, DListMenuDescriptor *desc) -: DLoadSaveMenu(parent, desc) -{ - TopItem = 0; - Selected = manager->ExtractSaveData (-1); - -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DLoadMenu::MenuEvent (int mkey, bool fromcontroller) -{ - if (Super::MenuEvent(mkey, fromcontroller)) - { - return true; - } - if (Selected == -1 || manager->SavegameCount() == 0) - { - return false; - } - - if (mkey == MKEY_Enter) - { - manager->LoadSavegame(Selected); - return true; - } - return false; -} - - DEFINE_FIELD(FSaveGameNode, SaveTitle); DEFINE_FIELD(FSaveGameNode, Filename); DEFINE_FIELD(FSaveGameNode, bOldVersion); diff --git a/src/version.h b/src/version.h index e50bdfd8d8..ca7de97fef 100644 --- a/src/version.h +++ b/src/version.h @@ -100,7 +100,4 @@ const char *GetVersionString(); #endif -// The maximum length of one save game description for the menus. -#define SAVESTRINGSIZE 24 - #endif //__VERSION_H__ diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index 8700494120..a52c8191bd 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -1,5 +1,5 @@ /* -** loadsavemenu.cpp +** loacpp ** The load game and save game menus ** **--------------------------------------------------------------------------- @@ -49,20 +49,20 @@ struct SavegameManager native native SaveGameNode quickSaveSlot; //void ReadSaveStrings(); - //void UnloadSaveData(); + native void UnloadSaveData(); //int RemoveSaveSlot(int index); native void LoadSavegame(int Selected); - //void DoSave(int Selected, String savegamestring); + native void DoSave(int Selected, String savegamestring); native int ExtractSaveData(int index); //void ClearSaveStuff(); //bool DrawSavePic(int x, int y, int w, int h); //void DrawSaveComment(Font font, int cr, int x, int y, int scalefactor); - //void SetFileInfo(int Selected); + native void SetFileInfo(int Selected); native int SavegameCount(); - //SaveGameNode GetSavegame(int i); - //void InsertNewSaveNode(); - //bool RemoveNewSaveNode(); + native SaveGameNode GetSavegame(int i); + native void InsertNewSaveNode(); + native bool RemoveNewSaveNode(); } @@ -99,10 +99,156 @@ class LoadSaveMenu : ListMenu native native TextEnterMenu mInput; + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder (InputEventData ev) + { + if (ev.type == InputEventData.GUI_Event) + { + if (ev.subtype == InputEventData.GUI_KeyDown) + { + if (Selected < manager.SavegameCount()) + { + switch (ev.data1) + { + case UIEvent.Key_F1: + manager.SetFileInfo(Selected); + return true; + + case UIEvent.Key_DEL: + { + String EndString; + EndString = String.Format("%s%s%s%s?\n\n%s", Stringtable.Localize("$MNU_DELETESG"), TEXTCOLOR_WHITE, manager.GetSavegame(Selected).SaveTitle, TEXTCOLOR_NORMAL, Stringtable.Localize("$PRESSYN")); + StartMessage (EndString, 0); + } + return true; + } + } + } + else if (ev.subtype == InputEventData.GUI_WheelUp) + { + if (TopItem > 0) TopItem--; + return true; + } + else if (ev.subtype == InputEventData.GUI_WheelDown) + { + if (TopItem < manager.SavegameCount() - listboxRows) TopItem++; + return true; + } + } + return Super.Responder(ev); + } + + } -class SaveMenu : LoadSaveMenu native +class SaveMenu : LoadSaveMenu { + //============================================================================= + // + // + // + //============================================================================= + + override void Init(Menu parent, ListMenuDescriptor desc) + { + Super.Init(parent, desc); + manager.InsertNewSaveNode(); + TopItem = 0; + Selected = manager.ExtractSaveData (-1); + } + + //============================================================================= + // + // + // + //============================================================================= + + override void OnDestroy() + { + if (manager.RemoveNewSaveNode()) + { + Selected--; + } + Super.OnDestroy(); + } + + //============================================================================= + // + // + // + //============================================================================= + const SAVESTRINGSIZE = 32; + + override bool MenuEvent (int mkey, bool fromcontroller) + { + + if (Super.MenuEvent(mkey, fromcontroller)) + { + return true; + } + if (Selected == -1) + { + return false; + } + + if (mkey == MKEY_Enter) + { + String SavegameString = (Selected != 0)? manager.GetSavegame(Selected).SaveTitle : ""; + mInput = TextEnterMenu.Open(self, SavegameString, SAVESTRINGSIZE, 1, fromcontroller); + mInput.ActivateMenu(); + mEntering = true; + } + else if (mkey == MKEY_Input) + { + mEntering = false; + manager.DoSave(Selected, mInput.GetText()); + mInput = null; + } + else if (mkey == MKEY_Abort) + { + mEntering = false; + mInput = null; + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder (InputEventData ev) + { + if (ev.subtype == InputEventData.GUI_KeyDown) + { + if (Selected != -1) + { + switch (ev.data1) + { + case UIEvent.Key_DEL: + // cannot delete 'new save game' item + if (Selected == 0) return true; + break; + + case 78://'N': + Selected = TopItem = 0; + manager.UnloadSaveData (); + return true; + } + } + } + return Super.Responder(ev); + } + + + } //============================================================================= @@ -111,7 +257,7 @@ class SaveMenu : LoadSaveMenu native // //============================================================================= -class LoadMenu : LoadSaveMenu native +class LoadMenu : LoadSaveMenu { //============================================================================= // From 4a6d0f1fa5695bb9ef0129a1eb19c6f32dc93c95 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 17:35:01 +0100 Subject: [PATCH 031/207] - scriptified DLoadSaveMenu::MenuEvent. --- src/menu/loadsavemenu.cpp | 137 ++------------------ src/menu/menu.h | 2 +- wadsrc/static/zscript/menu/loadsavemenu.txt | 129 +++++++++++++++++- 3 files changed, 138 insertions(+), 130 deletions(-) diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 4bfc8c50e3..f085fa2522 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -105,6 +105,14 @@ int FSavegameManager::RemoveSaveSlot(int index) return index; } +DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_INT(sel); + ACTION_RETURN_INT(self->RemoveSaveSlot(sel)); +} + + //============================================================================= // // @@ -664,7 +672,7 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount) // //============================================================================= -FSaveGameNode *FSavegameManager::GetSavegame(unsigned i) +FSaveGameNode *FSavegameManager::GetSavegame(int i) { return SaveGames[i]; } @@ -764,8 +772,6 @@ public: void OnDestroy() override; void Drawer (); - bool MenuEvent (int mkey, bool fromcontroller); - bool MouseEvent(int type, int x, int y); }; IMPLEMENT_CLASS(DLoadSaveMenu, false, false) @@ -925,131 +931,6 @@ void DLoadSaveMenu::Drawer () } } -//============================================================================= -// -// -// -//============================================================================= - -bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) -{ - switch (mkey) - { - case MKEY_Up: - if (manager->SavegameCount() > 1) - { - if (Selected == -1) Selected = TopItem; - else - { - if (--Selected < 0) Selected = manager->SavegameCount()-1; - if (Selected < TopItem) TopItem = Selected; - else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); - } - manager->UnloadSaveData (); - manager->ExtractSaveData (Selected); - } - return true; - - case MKEY_Down: - if (manager->SavegameCount() > 1) - { - if (Selected == -1) Selected = TopItem; - else - { - if (unsigned(++Selected) >= manager->SavegameCount()) Selected = 0; - if (Selected < TopItem) TopItem = Selected; - else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); - } - manager->UnloadSaveData (); - manager->ExtractSaveData (Selected); - } - return true; - - case MKEY_PageDown: - if (manager->SavegameCount() > 1) - { - if (TopItem >= (int)manager->SavegameCount() - listboxRows) - { - TopItem = 0; - if (Selected != -1) Selected = 0; - } - else - { - TopItem = MIN(TopItem + listboxRows, manager->SavegameCount() - listboxRows); - if (TopItem > Selected && Selected != -1) Selected = TopItem; - } - manager->UnloadSaveData (); - manager->ExtractSaveData (Selected); - } - return true; - - case MKEY_PageUp: - if (manager->SavegameCount() > 1) - { - if (TopItem == 0) - { - TopItem = manager->SavegameCount() - listboxRows; - if (Selected != -1) Selected = TopItem; - } - else - { - TopItem = MAX(TopItem - listboxRows, 0); - if (Selected >= TopItem + listboxRows) Selected = TopItem; - } - manager->UnloadSaveData (); - manager->ExtractSaveData (Selected); - } - return true; - - case MKEY_Enter: - return false; // This event will be handled by the subclasses - - case MKEY_MBYes: - { - if ((unsigned)Selected < manager->SavegameCount()) - { - Selected = manager->RemoveSaveSlot (Selected); - } - return true; - } - - default: - return Super::MenuEvent(mkey, fromcontroller); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DLoadSaveMenu::MouseEvent(int type, int x, int y) -{ - if (x >= listboxLeft && x < listboxLeft + listboxWidth && - y >= listboxTop && y < listboxTop + listboxHeight) - { - int lineno = (y - listboxTop) / rowHeight; - - if (TopItem + lineno < (int)manager->SavegameCount()) - { - Selected = TopItem + lineno; - manager->UnloadSaveData (); - manager->ExtractSaveData (Selected); - if (type == MOUSE_Release) - { - if (MenuEvent(MKEY_Enter, true)) - { - return true; - } - } - } - else Selected = -1; - } - else Selected = -1; - - return Super::MouseEvent(type, x, y); -} DEFINE_FIELD(FSaveGameNode, SaveTitle); DEFINE_FIELD(FSaveGameNode, Filename); diff --git a/src/menu/menu.h b/src/menu/menu.h index 2241513cb2..dd06dc6058 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -100,7 +100,7 @@ public: void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor); void SetFileInfo(int Selected); unsigned SavegameCount(); - FSaveGameNode *GetSavegame(unsigned i); + FSaveGameNode *GetSavegame(int i); void InsertNewSaveNode(); bool RemoveNewSaveNode(); diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index a52c8191bd..b97042cf76 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -51,7 +51,7 @@ struct SavegameManager native //void ReadSaveStrings(); native void UnloadSaveData(); - //int RemoveSaveSlot(int index); + native int RemoveSaveSlot(int index); native void LoadSavegame(int Selected); native void DoSave(int Selected, String savegamestring); native int ExtractSaveData(int index); @@ -99,6 +99,133 @@ class LoadSaveMenu : ListMenu native native TextEnterMenu mInput; + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent (int mkey, bool fromcontroller) + { + switch (mkey) + { + case MKEY_Up: + if (manager.SavegameCount() > 1) + { + if (Selected == -1) Selected = TopItem; + else + { + if (--Selected < 0) Selected = manager.SavegameCount()-1; + if (Selected < TopItem) TopItem = Selected; + else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); + } + manager.UnloadSaveData (); + manager.ExtractSaveData (Selected); + } + return true; + + case MKEY_Down: + if (manager.SavegameCount() > 1) + { + if (Selected == -1) Selected = TopItem; + else + { + if (++Selected >= manager.SavegameCount()) Selected = 0; + if (Selected < TopItem) TopItem = Selected; + else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); + } + manager.UnloadSaveData (); + manager.ExtractSaveData (Selected); + } + return true; + + case MKEY_PageDown: + if (manager.SavegameCount() > 1) + { + if (TopItem >= manager.SavegameCount() - listboxRows) + { + TopItem = 0; + if (Selected != -1) Selected = 0; + } + else + { + TopItem = MIN(TopItem + listboxRows, manager.SavegameCount() - listboxRows); + if (TopItem > Selected && Selected != -1) Selected = TopItem; + } + manager.UnloadSaveData (); + manager.ExtractSaveData (Selected); + } + return true; + + case MKEY_PageUp: + if (manager.SavegameCount() > 1) + { + if (TopItem == 0) + { + TopItem = MAX(0, manager.SavegameCount() - listboxRows); + if (Selected != -1) Selected = TopItem; + } + else + { + TopItem = MAX(TopItem - listboxRows, 0); + if (Selected >= TopItem + listboxRows) Selected = TopItem; + } + manager.UnloadSaveData (); + manager.ExtractSaveData (Selected); + } + return true; + + case MKEY_Enter: + return false; // This event will be handled by the subclasses + + case MKEY_MBYes: + { + if (Selected < manager.SavegameCount()) + { + Selected = manager.RemoveSaveSlot (Selected); + } + return true; + } + + default: + return Super.MenuEvent(mkey, fromcontroller); + } + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + if (x >= listboxLeft && x < listboxLeft + listboxWidth && + y >= listboxTop && y < listboxTop + listboxHeight) + { + int lineno = (y - listboxTop) / rowHeight; + + if (TopItem + lineno < manager.SavegameCount()) + { + Selected = TopItem + lineno; + manager.UnloadSaveData (); + manager.ExtractSaveData (Selected); + if (type == MOUSE_Release) + { + if (MenuEvent(MKEY_Enter, true)) + { + return true; + } + } + } + else Selected = -1; + } + else Selected = -1; + + return Super.MouseEvent(type, x, y); + } + //============================================================================= // From e46d378fb293991bb6cd30d4982904dfd7ac537a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 17:51:40 +0100 Subject: [PATCH 032/207] - sciptified DLoadSaveMenu::Drawer. --- src/menu/loadsavemenu.cpp | 135 ++++---------------- wadsrc/static/zscript/menu/loadsavemenu.txt | 104 ++++++++++++++- 2 files changed, 124 insertions(+), 115 deletions(-) diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index f085fa2522..0f4fa56a9c 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -593,6 +593,16 @@ bool FSavegameManager::DrawSavePic(int x, int y, int w, int h) return true; } +DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_INT(x); + PARAM_INT(y); + PARAM_INT(w); + PARAM_INT(h); + ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h)); +} + //============================================================================= // // @@ -618,6 +628,18 @@ void FSavegameManager::DrawSaveComment(FFont *font, int cr, int x, int y, int sc CleanYfac = sy; } +DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSaveComment) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + PARAM_POINTER(fnt, FFont); + PARAM_INT(cr); + PARAM_INT(x); + PARAM_INT(y); + PARAM_INT(fac); + self->DrawSaveComment(fnt, cr, x, y, fac); + return 0; +} + //============================================================================= // @@ -770,8 +792,6 @@ public: DLoadSaveMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); void OnDestroy() override; - - void Drawer (); }; IMPLEMENT_CLASS(DLoadSaveMenu, false, false) @@ -820,117 +840,6 @@ void DLoadSaveMenu::OnDestroy() Super::OnDestroy(); } -//============================================================================= -// -// -// -//============================================================================= - -void DLoadSaveMenu::Drawer () -{ - Super::Drawer(); - - FSaveGameNode *node; - int i; - unsigned j; - bool didSeeSelected = false; - - // Draw picture area - if (gameaction == ga_loadgame || gameaction == ga_loadgamehidecon || gameaction == ga_savegame) - { - return; - } - - V_DrawFrame (savepicLeft, savepicTop, savepicWidth, savepicHeight); - if (!manager->DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight)) - { - screen->Clear (savepicLeft, savepicTop, - savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0); - - if (manager->SavegameCount() > 0) - { - const char *text = - (Selected == -1 || !manager->GetSavegame(Selected)->bOldVersion) - ? GStrings("MNU_NOPICTURE") : GStrings("MNU_DIFFVERSION"); - const int textlen = SmallFont->StringWidth (text)*CleanXfac; - - screen->DrawText (SmallFont, CR_GOLD, savepicLeft+(savepicWidth-textlen)/2, - savepicTop+(savepicHeight-rowHeight)/2, text, - DTA_CleanNoMove, true, TAG_DONE); - } - } - - // Draw comment area - V_DrawFrame (commentLeft, commentTop, commentWidth, commentHeight); - screen->Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0); - - manager->DrawSaveComment(SmallFont, CR_GOLD, commentLeft, commentTop, CleanYfac); - - // Draw file area - V_DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); - screen->Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0); - - if (manager->SavegameCount() == 0) - { - const char * text = GStrings("MNU_NOFILES"); - const int textlen = SmallFont->StringWidth (text)*CleanXfac; - - screen->DrawText (SmallFont, CR_GOLD, listboxLeft+(listboxWidth-textlen)/2, - listboxTop+(listboxHeight-rowHeight)/2, text, - DTA_CleanNoMove, true, TAG_DONE); - return; - } - - for (i = 0, j = TopItem; i < listboxRows && j < manager->SavegameCount(); i++,j++) - { - int color; - node = manager->GetSavegame(j); - if (node->bOldVersion) - { - color = CR_BLUE; - } - else if (node->bMissingWads) - { - color = CR_ORANGE; - } - else if ((int)j == Selected) - { - color = CR_WHITE; - } - else - { - color = CR_TAN; - } - - if ((int)j == Selected) - { - screen->Clear (listboxLeft, listboxTop+rowHeight*i, - listboxRight, listboxTop+rowHeight*(i+1), -1, - mEntering ? MAKEARGB(255,255,0,0) : MAKEARGB(255,0,0,255)); - didSeeSelected = true; - if (!mEntering) - { - screen->DrawText (SmallFont, color, - listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->SaveTitle.GetChars(), - DTA_CleanNoMove, true, TAG_DONE); - } - else - { - FString s = mInput->GetText() + SmallFont->GetCursor(); - screen->DrawText (SmallFont, CR_WHITE, - listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, s, - DTA_CleanNoMove, true, TAG_DONE); - } - } - else - { - screen->DrawText (SmallFont, color, - listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node->SaveTitle.GetChars(), - DTA_CleanNoMove, true, TAG_DONE); - } - } -} - DEFINE_FIELD(FSaveGameNode, SaveTitle); DEFINE_FIELD(FSaveGameNode, Filename); diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index b97042cf76..960d238eb4 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -56,8 +56,8 @@ struct SavegameManager native native void DoSave(int Selected, String savegamestring); native int ExtractSaveData(int index); //void ClearSaveStuff(); - //bool DrawSavePic(int x, int y, int w, int h); - //void DrawSaveComment(Font font, int cr, int x, int y, int scalefactor); + native bool DrawSavePic(int x, int y, int w, int h); + native void DrawSaveComment(Font font, int cr, int x, int y, int scalefactor); native void SetFileInfo(int Selected); native int SavegameCount(); native SaveGameNode GetSavegame(int i); @@ -99,6 +99,106 @@ class LoadSaveMenu : ListMenu native native TextEnterMenu mInput; + //============================================================================= + // + // + // + //============================================================================= + + override void Drawer () + { + Super.Drawer(); + + SaveGameNode node; + int i; + int j; + bool didSeeSelected = false; + + // Draw picture area + if (gameaction == ga_loadgame || gameaction == ga_loadgamehidecon || gameaction == ga_savegame) + { + return; + } + + Screen.DrawFrame (savepicLeft, savepicTop, savepicWidth, savepicHeight); + if (!manager.DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight)) + { + screen.Clear (savepicLeft, savepicTop, savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0); + + if (manager.SavegameCount() > 0) + { + String text = (Selected == -1 || !manager.GetSavegame(Selected).bOldVersion)? Stringtable.Localize("$MNU_NOPICTURE") : Stringtable.Localize("$MNU_DIFFVERSION"); + int textlen = SmallFont.StringWidth(text) * CleanXfac; + + screen.DrawText (SmallFont, Font.CR_GOLD, savepicLeft+(savepicWidth-textlen)/2, + savepicTop+(savepicHeight-rowHeight)/2, text, DTA_CleanNoMove, true); + } + } + + // Draw comment area + Screen.DrawFrame (commentLeft, commentTop, commentWidth, commentHeight); + screen.Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0); + + manager.DrawSaveComment(SmallFont, Font.CR_GOLD, commentLeft, commentTop, CleanYfac); + + // Draw file area + Screen.DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); + screen.Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0); + + if (manager.SavegameCount() == 0) + { + String text = Stringtable.Localize("$MNU_NOFILES"); + int textlen = SmallFont.StringWidth(text) * CleanXfac; + + screen.DrawText (SmallFont, Font.CR_GOLD, listboxLeft+(listboxWidth-textlen)/2, listboxTop+(listboxHeight-rowHeight)/2, text, DTA_CleanNoMove, true); + return; + } + + j = TopItem; + for (i = 0; i < listboxRows && j < manager.SavegameCount(); i++) + { + int colr; + node = manager.GetSavegame(j); + if (node.bOldVersion) + { + colr = Font.CR_BLUE; + } + else if (node.bMissingWads) + { + colr = Font.CR_ORANGE; + } + else if (j == Selected) + { + colr = Font.CR_WHITE; + } + else + { + colr = Font.CR_TAN; + } + + if (j == Selected) + { + screen.Clear (listboxLeft, listboxTop+rowHeight*i, listboxRight, listboxTop+rowHeight*(i+1), mEntering ? Color(255,255,0,0) : Color(255,0,0,255)); + didSeeSelected = true; + if (!mEntering) + { + screen.DrawText (SmallFont, colr, listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node.SaveTitle, DTA_CleanNoMove, true); + } + else + { + String s = mInput.GetText() .. SmallFont.GetCursor(); + screen.DrawText (SmallFont, Font.CR_WHITE, listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, s, DTA_CleanNoMove, true); + } + } + else + { + screen.DrawText (SmallFont, colr, listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node.SaveTitle, DTA_CleanNoMove, true); + } + j++; + } + } + + //============================================================================= // From 6a65f022572e740192c5e050d5103b1e3aeb4d01 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 18:01:24 +0100 Subject: [PATCH 033/207] - completed scriptification of LoadSaveMenu. --- src/menu/loadsavemenu.cpp | 126 +++----------------- wadsrc/static/zscript/menu/loadsavemenu.txt | 102 ++++++++++++---- 2 files changed, 94 insertions(+), 134 deletions(-) diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 0f4fa56a9c..fdca9abc81 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -72,6 +72,7 @@ FSavegameManager::~FSavegameManager() { ClearSaveGames(); } + //============================================================================= // // Save data maintenance @@ -313,6 +314,14 @@ void FSavegameManager::ReadSaveStrings() } } +DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + self->ReadSaveStrings(); + return 0; +} + + //============================================================================= // // @@ -579,6 +588,12 @@ void FSavegameManager::ClearSaveStuff() } } +DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); + self->ClearSaveStuff(); + return 0; +} //============================================================================= // @@ -751,94 +766,12 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode) FSavegameManager savegameManager; - - - -class DLoadSaveMenu : public DListMenu +DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager) { - DECLARE_CLASS(DLoadSaveMenu, DListMenu) - -public: - - FSavegameManager *manager; - - int Selected; - int TopItem; - - - int savepicLeft; - int savepicTop; - int savepicWidth; - int savepicHeight; - int rowHeight; - int listboxLeft; - int listboxTop; - int listboxWidth; - - int listboxRows; - int listboxHeight; - int listboxRight; - int listboxBottom; - - int commentLeft; - int commentTop; - int commentWidth; - int commentHeight; - int commentRight; - int commentBottom; - - bool mEntering; - DTextEnterMenu *mInput = nullptr; - - DLoadSaveMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); - void OnDestroy() override; -}; - -IMPLEMENT_CLASS(DLoadSaveMenu, false, false) - - - -//============================================================================= -// -// End of static savegame maintenance code -// -//============================================================================= - -DLoadSaveMenu::DLoadSaveMenu(DMenu *parent, DListMenuDescriptor *desc) -: DListMenu(parent, desc) -{ - manager = &savegameManager; - manager->ReadSaveStrings(); - - savepicLeft = 10; - savepicTop = 54*CleanYfac; - savepicWidth = 216*screen->GetWidth()/640; - savepicHeight = 135*screen->GetHeight()/400; - manager->WindowSize = savepicWidth / CleanXfac; - - rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac; - listboxLeft = savepicLeft + savepicWidth + 14; - listboxTop = savepicTop; - listboxWidth = screen->GetWidth() - listboxLeft - 10; - int listboxHeight1 = screen->GetHeight() - listboxTop - 10; - listboxRows = (listboxHeight1 - 1) / rowHeight; - listboxHeight = listboxRows * rowHeight + 1; - listboxRight = listboxLeft + listboxWidth; - listboxBottom = listboxTop + listboxHeight; - - commentLeft = savepicLeft; - commentTop = savepicTop + savepicHeight + 16; - commentWidth = savepicWidth; - commentHeight = (51+(screen->GetHeight()>200?10:0))*CleanYfac; - commentRight = commentLeft + commentWidth; - commentBottom = commentTop + commentHeight; + PARAM_PROLOGUE; + ACTION_RETURN_POINTER(&savegameManager); } -void DLoadSaveMenu::OnDestroy() -{ - manager->ClearSaveStuff (); - Super::OnDestroy(); -} DEFINE_FIELD(FSaveGameNode, SaveTitle); @@ -850,26 +783,3 @@ DEFINE_FIELD(FSaveGameNode, bNoDelete); DEFINE_FIELD(FSavegameManager, WindowSize); DEFINE_FIELD(FSavegameManager, quickSaveSlot); -DEFINE_FIELD(DLoadSaveMenu, manager); -DEFINE_FIELD(DLoadSaveMenu, Selected); -DEFINE_FIELD(DLoadSaveMenu, TopItem); -DEFINE_FIELD(DLoadSaveMenu, savepicLeft); -DEFINE_FIELD(DLoadSaveMenu, savepicTop); -DEFINE_FIELD(DLoadSaveMenu, savepicWidth); -DEFINE_FIELD(DLoadSaveMenu, savepicHeight); -DEFINE_FIELD(DLoadSaveMenu, rowHeight); -DEFINE_FIELD(DLoadSaveMenu, listboxLeft); -DEFINE_FIELD(DLoadSaveMenu, listboxTop); -DEFINE_FIELD(DLoadSaveMenu, listboxWidth); -DEFINE_FIELD(DLoadSaveMenu, listboxRows); -DEFINE_FIELD(DLoadSaveMenu, listboxHeight); -DEFINE_FIELD(DLoadSaveMenu, listboxRight); -DEFINE_FIELD(DLoadSaveMenu, listboxBottom); -DEFINE_FIELD(DLoadSaveMenu, commentLeft); -DEFINE_FIELD(DLoadSaveMenu, commentTop); -DEFINE_FIELD(DLoadSaveMenu, commentWidth); -DEFINE_FIELD(DLoadSaveMenu, commentHeight); -DEFINE_FIELD(DLoadSaveMenu, commentRight); -DEFINE_FIELD(DLoadSaveMenu, commentBottom); -DEFINE_FIELD(DLoadSaveMenu, mEntering); -DEFINE_FIELD(DLoadSaveMenu, mInput); diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index 960d238eb4..34d56f3745 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -48,14 +48,15 @@ struct SavegameManager native native int WindowSize; native SaveGameNode quickSaveSlot; - //void ReadSaveStrings(); + native static SavegameManager GetManager(); + native void ReadSaveStrings(); native void UnloadSaveData(); native int RemoveSaveSlot(int index); native void LoadSavegame(int Selected); native void DoSave(int Selected, String savegamestring); native int ExtractSaveData(int index); - //void ClearSaveStuff(); + native void ClearSaveStuff(); native bool DrawSavePic(int x, int y, int w, int h); native void DrawSaveComment(Font font, int cr, int x, int y, int scalefactor); native void SetFileInfo(int Selected); @@ -68,37 +69,86 @@ struct SavegameManager native -class LoadSaveMenu : ListMenu native +class LoadSaveMenu : ListMenu { - native SavegameManager manager; - native int TopItem; - native int Selected; + SavegameManager manager; + int TopItem; + int Selected; - native int savepicLeft; - native int savepicTop; - native int savepicWidth; - native int savepicHeight; - native int rowHeight; - native int listboxLeft; - native int listboxTop; - native int listboxWidth; + int savepicLeft; + int savepicTop; + int savepicWidth; + int savepicHeight; + int rowHeight; + int listboxLeft; + int listboxTop; + int listboxWidth; - native int listboxRows; - native int listboxHeight; - native int listboxRight; - native int listboxBottom; + int listboxRows; + int listboxHeight; + int listboxRight; + int listboxBottom; - native int commentLeft; - native int commentTop; - native int commentWidth; - native int commentHeight; - native int commentRight; - native int commentBottom; + int commentLeft; + int commentTop; + int commentWidth; + int commentHeight; + int commentRight; + int commentBottom; - native bool mEntering; - native TextEnterMenu mInput; + bool mEntering; + TextEnterMenu mInput; + + //============================================================================= + // + // + // + //============================================================================= + + override void Init(Menu parent, ListMenuDescriptor desc) + { + Super.Init(parent, desc); + manager = SavegameManager.GetManager(); + manager.ReadSaveStrings(); + + savepicLeft = 10; + savepicTop = 54*CleanYfac; + savepicWidth = 216*screen.GetWidth()/640; + savepicHeight = 135*screen.GetHeight()/400; + manager.WindowSize = savepicWidth / CleanXfac; + + rowHeight = (SmallFont.GetHeight() + 1) * CleanYfac; + listboxLeft = savepicLeft + savepicWidth + 14; + listboxTop = savepicTop; + listboxWidth = screen.GetWidth() - listboxLeft - 10; + int listboxHeight1 = screen.GetHeight() - listboxTop - 10; + listboxRows = (listboxHeight1 - 1) / rowHeight; + listboxHeight = listboxRows * rowHeight + 1; + listboxRight = listboxLeft + listboxWidth; + listboxBottom = listboxTop + listboxHeight; + + commentLeft = savepicLeft; + commentTop = savepicTop + savepicHeight + 16; + commentWidth = savepicWidth; + commentHeight = (51+(screen.GetHeight()>200?10:0))*CleanYfac; + commentRight = commentLeft + commentWidth; + commentBottom = commentTop + commentHeight; + } + + //============================================================================= + // + // + // + //============================================================================= + + override void OnDestroy() + { + manager.ClearSaveStuff (); + Super.OnDestroy(); + } + //============================================================================= // // From b7a5437af6eaf6f0c5d94cffe7c3fba7a5db8509 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 18:35:44 +0100 Subject: [PATCH 034/207] - scriptified parts of ListMenu. --- src/menu/listmenu.cpp | 162 +---------------- src/menu/menu.cpp | 36 +--- src/menu/menu.h | 9 - src/menu/menudef.cpp | 2 +- src/menu/playermenu.cpp | 20 +-- wadsrc/static/zscript/menu/listmenu.txt | 178 ++++++++++++++++++- wadsrc/static/zscript/menu/listmenuitems.txt | 2 +- 7 files changed, 190 insertions(+), 219 deletions(-) diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp index 18c627359d..beaa687f1e 100644 --- a/src/menu/listmenu.cpp +++ b/src/menu/listmenu.cpp @@ -115,167 +115,13 @@ DMenuItemBase *DListMenu::GetItem(FName name) return NULL; } -//============================================================================= -// -// -// -//============================================================================= - -bool DListMenu::Responder (event_t *ev) -{ - if (ev->type == EV_GUI_Event) - { - if (ev->subtype == EV_GUI_KeyDown) - { - int ch = tolower (ev->data1); - - for(unsigned i = mDesc->mSelectedItem + 1; i < mDesc->mItems.Size(); i++) - { - if (mDesc->mItems[i]->CheckHotkey(ch)) - { - mDesc->mSelectedItem = i; - S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - return true; - } - } - for(int i = 0; i < mDesc->mSelectedItem; i++) - { - if (mDesc->mItems[i]->CheckHotkey(ch)) - { - mDesc->mSelectedItem = i; - S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - return true; - } - } - } - } - return Super::Responder(ev); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DListMenu::MenuEvent (int mkey, bool fromcontroller) -{ - int oldSelect = mDesc->mSelectedItem; - int startedAt = mDesc->mSelectedItem; - if (startedAt < 0) startedAt = 0; - - switch (mkey) - { - case MKEY_Up: - do - { - if (--mDesc->mSelectedItem < 0) mDesc->mSelectedItem = mDesc->mItems.Size()-1; - } - while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt); - if (mDesc->mSelectedItem == startedAt) mDesc->mSelectedItem = oldSelect; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - return true; - - case MKEY_Down: - do - { - if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size()) mDesc->mSelectedItem = 0; - } - while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt); - if (mDesc->mSelectedItem == startedAt) mDesc->mSelectedItem = oldSelect; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - return true; - - case MKEY_Enter: - if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate()) - { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); - } - return true; - - default: - return Super::MenuEvent(mkey, fromcontroller); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DListMenu::MouseEvent(int type, int x, int y) -{ - int sel = -1; - - // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture - x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160; - y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100; - - if (mFocusControl != NULL) - { - mFocusControl->MouseEvent(type, x, y); - return true; - } - else - { - if ((mDesc->mWLeft <= 0 || x > mDesc->mWLeft) && - (mDesc->mWRight <= 0 || x < mDesc->mWRight)) - { - for(unsigned i=0;imItems.Size(); i++) - { - if (mDesc->mItems[i]->CheckCoordinate(x, y)) - { - if ((int)i != mDesc->mSelectedItem) - { - //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - } - mDesc->mSelectedItem = i; - mDesc->mItems[i]->MouseEvent(type, x, y); - return true; - } - } - } - } - mDesc->mSelectedItem = -1; - return Super::MouseEvent(type, x, y); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DListMenu::Ticker () -{ - Super::Ticker(); - for(unsigned i=0;imItems.Size(); i++) - { - mDesc->mItems[i]->Ticker(); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void DListMenu::Drawer () -{ - for(unsigned i=0;imItems.Size(); i++) - { - if (mDesc->mItems[i]->mEnabled) mDesc->mItems[i]->Drawer(mDesc->mSelectedItem == (int)i); - } - if (mDesc->mSelectedItem >= 0 && mDesc->mSelectedItem < (int)mDesc->mItems.Size()) - mDesc->mItems[mDesc->mSelectedItem]->DrawSelector(mDesc->mSelectOfsX, mDesc->mSelectOfsY, mDesc->mSelector); - Super::Drawer(); -} - //============================================================================= // // base class for menu items // //============================================================================= IMPLEMENT_CLASS(DMenuItemBase, false, false) + +DEFINE_FIELD(DListMenu, mDesc) +DEFINE_FIELD(DListMenu, mFocusControl) + diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index ee7d5cbdb1..dc7e021267 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -629,7 +629,7 @@ void M_SetMenu(FName menu, int param) if (cls == nullptr) cls = DefaultListMenuClass; if (cls == nullptr) cls = PClass::FindClass("ListMenu"); - DListMenu *newmenu = (DListMenu *)cls->CreateNew(); + DMenu *newmenu = (DMenu *)cls->CreateNew(); IFVIRTUALPTRNAME(newmenu, "ListMenu", Init) { VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld }; @@ -1220,9 +1220,6 @@ DEFINE_FIELD(DMenuItemBase, mYpos) DEFINE_FIELD(DMenuItemBase, mAction) DEFINE_FIELD(DMenuItemBase, mEnabled) -DEFINE_FIELD(DListMenu, mDesc) -DEFINE_FIELD(DListMenu, mFocusControl) - DEFINE_FIELD(DListMenuDescriptor, mItems) DEFINE_FIELD(DListMenuDescriptor, mSelectedItem) DEFINE_FIELD(DListMenuDescriptor, mSelectOfsX) @@ -1344,15 +1341,6 @@ void DMenuItemBase::Ticker() } } -void DMenuItemBase::Drawer(bool selected) -{ - IFVIRTUAL(DMenuItemBase, Drawer) - { - VMValue params[] = { (DObject*)this, selected }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr); - } -} - bool DMenuItemBase::Selectable() { IFVIRTUAL(DMenuItemBase, Selectable) @@ -1534,25 +1522,3 @@ int DMenuItemBase::Draw(DOptionMenuDescriptor *desc, int y, int indent, bool sel } return false; } - -void DMenuItemBase::DrawSelector(int xofs, int yofs, FTextureID tex) -{ - if (tex.isNull()) - { - if ((DMenu::MenuTime % 8) < 6) - { - screen->DrawText(ConFont, OptionSettings.mFontColorSelection, - (mXpos + xofs - 160) * CleanXfac + screen->GetWidth() / 2, - (mYpos + yofs - 100) * CleanYfac + screen->GetHeight() / 2, - "\xd", - DTA_CellX, 8 * CleanXfac, - DTA_CellY, 8 * CleanYfac, - TAG_DONE); - } - } - else - { - screen->DrawTexture(TexMan(tex), mXpos + xofs, mYpos + yofs, DTA_Clean, true, TAG_DONE); - } -} - diff --git a/src/menu/menu.h b/src/menu/menu.h index dd06dc6058..e197a62ef5 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -319,7 +319,6 @@ public: bool CheckCoordinate(int x, int y); void Ticker(); - void Drawer(bool selected); bool Selectable(); bool Activate(); FName GetAction(int *pparam); @@ -338,9 +337,6 @@ public: int GetY() { return mYpos; } int GetX() { return mXpos; } void SetX(int x) { mXpos = x; } - - void DrawSelector(int xofs, int yofs, FTextureID tex); - }; //============================================================================= @@ -361,11 +357,6 @@ public: DListMenu(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL); virtual void Init(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL); DMenuItemBase *GetItem(FName name); - bool Responder (event_t *ev); - bool MenuEvent (int mkey, bool fromcontroller); - bool MouseEvent(int type, int x, int y); - void Ticker (); - void Drawer (); void SetFocus(DMenuItemBase *fc) { mFocusControl = fc; diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 8afed617e4..252533091e 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -294,7 +294,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) { sc.MustGetString(); PClass *cls = PClass::FindClass(sc.String); - if (cls == nullptr || !cls->IsDescendantOf(RUNTIME_CLASS(DListMenu))) + if (cls == nullptr || !cls->IsDescendantOf("ListMenu")) { sc.ScriptError("Unknown menu class '%s'", sc.String); } diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 519af0a9d7..c900cc4a79 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -61,7 +61,7 @@ EXTERN_CVAR(Bool, cl_run) DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(r); PARAM_INT(g); PARAM_INT(b); @@ -86,7 +86,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_STRING(s); const char *pp = s; FString command("name \""); @@ -116,7 +116,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(sel); if (self == DMenu::CurrentMenu) { @@ -136,7 +136,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(sel); PARAM_POINTER(cls, FPlayerClass); if (self == DMenu::CurrentMenu) @@ -156,7 +156,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(sel); if (self == DMenu::CurrentMenu) { @@ -174,7 +174,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_FLOAT(val); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -192,7 +192,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(val); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -210,7 +210,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -228,7 +228,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) @@ -246,7 +246,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged) DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged) { - PARAM_SELF_PROLOGUE(DListMenu); + PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. if (self == DMenu::CurrentMenu) diff --git a/wadsrc/static/zscript/menu/listmenu.txt b/wadsrc/static/zscript/menu/listmenu.txt index d920dc26c4..2aacbb94c4 100644 --- a/wadsrc/static/zscript/menu/listmenu.txt +++ b/wadsrc/static/zscript/menu/listmenu.txt @@ -76,6 +76,12 @@ class ListMenu : Menu native } } + //============================================================================= + // + // + // + //============================================================================= + MenuItemBase GetItem(Name name) { for(int i = 0; i < mDesc.mItems.Size(); i++) @@ -86,12 +92,173 @@ class ListMenu : Menu native return NULL; } - //bool Responder (InputEventData ev); - //bool MenuEvent (int mkey, bool fromcontroller); - //bool MouseEvent(int type, int x, int y); - //void Ticker (); - //void Drawer (); + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder (InputEventData ev) + { + if (ev.type == InputEventData.GUI_Event) + { + if (ev.subtype == InputEventData.GUI_KeyDown) + { + // tolower + int ch = ev.data1; + ch = ch >= 65 && ch <91? ch + 32 : ch; + + for(int i = mDesc.mSelectedItem + 1; i < mDesc.mItems.Size(); i++) + { + if (mDesc.mItems[i].CheckHotkey(ch)) + { + mDesc.mSelectedItem = i; + MenuSound("menu/cursor"); + return true; + } + } + for(int i = 0; i < mDesc.mSelectedItem; i++) + { + if (mDesc.mItems[i].CheckHotkey(ch)) + { + mDesc.mSelectedItem = i; + MenuSound("menu/cursor"); + return true; + } + } + } + } + return Super.Responder(ev); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent (int mkey, bool fromcontroller) + { + int oldSelect = mDesc.mSelectedItem; + int startedAt = mDesc.mSelectedItem; + if (startedAt < 0) startedAt = 0; + + switch (mkey) + { + case MKEY_Up: + do + { + if (--mDesc.mSelectedItem < 0) mDesc.mSelectedItem = mDesc.mItems.Size()-1; + } + while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt); + if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect; + MenuSound("menu/cursor"); + return true; + + case MKEY_Down: + do + { + if (++mDesc.mSelectedItem >= mDesc.mItems.Size()) mDesc.mSelectedItem = 0; + } + while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt); + if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect; + MenuSound("menu/cursor"); + return true; + + case MKEY_Enter: + if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate()) + { + MenuSound("menu/choose"); + } + return true; + + default: + return Super.MenuEvent(mkey, fromcontroller); + } + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + int sel = -1; + + // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture + x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160; + y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100; + + if (mFocusControl != NULL) + { + mFocusControl.MouseEvent(type, x, y); + return true; + } + else + { + if ((mDesc.mWLeft <= 0 || x > mDesc.mWLeft) && + (mDesc.mWRight <= 0 || x < mDesc.mWRight)) + { + for(int i=0;i= 0 && mDesc.mSelectedItem < mDesc.mItems.Size()) + mDesc.mItems[mDesc.mSelectedItem].DrawSelector(mDesc.mSelectOfsX, mDesc.mSelectOfsY, mDesc.mSelector); + Super.Drawer(); + } + //============================================================================= + // + // + // + //============================================================================= + override void SetFocus(MenuItemBase fc) { mFocusControl = fc; @@ -106,3 +273,4 @@ class ListMenu : Menu native } } + diff --git a/wadsrc/static/zscript/menu/listmenuitems.txt b/wadsrc/static/zscript/menu/listmenuitems.txt index 8920e617bd..e3eec6dd18 100644 --- a/wadsrc/static/zscript/menu/listmenuitems.txt +++ b/wadsrc/static/zscript/menu/listmenuitems.txt @@ -52,7 +52,7 @@ class ListMenuItem : MenuItemBase } else { - screen.DrawTexture (tex, mXpos + xofs, mYpos + yofs, DTA_Clean, true); + screen.DrawTexture (tex, true, mXpos + xofs, mYpos + yofs, DTA_Clean, true); } } } From 1b4c9e13b839dfd5ce070c41821f694d7e486d9c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 19:11:53 +0100 Subject: [PATCH 035/207] - cleaned out some cruft from the menu code, now that ListMenu is fully scripted. --- src/CMakeLists.txt | 1 - src/menu/joystickmenu.cpp | 2 +- src/menu/listmenu.cpp | 127 --------------- src/menu/menu.cpp | 150 +----------------- src/menu/menu.h | 48 ------ src/menu/menudef.cpp | 3 +- src/menu/optionmenu.cpp | 28 +--- wadsrc/static/zscript/menu/listmenu.txt | 8 +- wadsrc/static/zscript/menu/menu.txt | 1 - wadsrc/static/zscript/menu/optionmenu.txt | 40 ++++- .../static/zscript/menu/optionmenuitems.txt | 4 +- 11 files changed, 47 insertions(+), 365 deletions(-) delete mode 100644 src/menu/listmenu.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b673b2c20e..04f2d0cd9f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -845,7 +845,6 @@ set( FASTMATH_PCH_SOURCES intermission/intermission.cpp intermission/intermission_parse.cpp menu/joystickmenu.cpp - menu/listmenu.cpp menu/loadsavemenu.cpp menu/menu.cpp menu/menudef.cpp diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index 9b16b90f41..8813dcaa7f 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -186,7 +186,7 @@ void UpdateJoystickMenu(IJoystickConfig *selected) { opt->mSelectedItem = opt->mItems.Size() - 1; } - opt->CalcIndent(); + //opt->CalcIndent(); // If the joystick config menu is open, close it if the device it's open for is gone. if (DMenu::CurrentMenu != nullptr && (DMenu::CurrentMenu->IsKindOf("JoystickConfigMenu"))) diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp deleted file mode 100644 index beaa687f1e..0000000000 --- a/src/menu/listmenu.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* -** listmenu.cpp -** A simple menu consisting of a list of items -** -**--------------------------------------------------------------------------- -** Copyright 2010 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "v_video.h" -#include "v_font.h" -#include "cmdlib.h" -#include "gstrings.h" -#include "g_level.h" -#include "gi.h" -#include "d_gui.h" -#include "d_event.h" -#include "menu/menu.h" - -IMPLEMENT_CLASS(DListMenu, false, false) - -IMPLEMENT_POINTERS_START(DListMenu) -IMPLEMENT_POINTER(mFocusControl) -IMPLEMENT_POINTERS_END - -//============================================================================= -// -// -// -//============================================================================= - -DListMenu::DListMenu(DMenu *parent, DListMenuDescriptor *desc) -: DMenu(parent) -{ - mDesc = NULL; - if (desc != NULL) Init(parent, desc); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DListMenu::Init(DMenu *parent, DListMenuDescriptor *desc) -{ - mParentMenu = parent; - GC::WriteBarrier(this, parent); - mDesc = desc; - if (desc->mCenter) - { - int center = 160; - for(unsigned i=0;imItems.Size(); i++) - { - int xpos = mDesc->mItems[i]->GetX(); - int width = mDesc->mItems[i]->GetWidth(); - int curx = mDesc->mSelectOfsX; - - if (width > 0 && mDesc->mItems[i]->Selectable()) - { - int left = 160 - (width - curx) / 2 - curx; - if (left < center) center = left; - } - } - for(unsigned i=0;imItems.Size(); i++) - { - int width = mDesc->mItems[i]->GetWidth(); - - if (width > 0) - { - mDesc->mItems[i]->SetX(center); - } - } - } -} - -//============================================================================= -// -// -// -//============================================================================= - -DMenuItemBase *DListMenu::GetItem(FName name) -{ - for(unsigned i=0;imItems.Size(); i++) - { - FName nm = mDesc->mItems[i]->GetAction(NULL); - if (nm == name) return mDesc->mItems[i]; - } - return NULL; -} - -//============================================================================= -// -// base class for menu items -// -//============================================================================= -IMPLEMENT_CLASS(DMenuItemBase, false, false) - -DEFINE_FIELD(DListMenu, mDesc) -DEFINE_FIELD(DListMenu, mFocusControl) - diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index dc7e021267..e61ac896c0 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -444,21 +444,6 @@ DEFINE_ACTION_FUNCTION(DMenu, Close) return 0; } -DEFINE_ACTION_FUNCTION(DMenu, GetItem) -{ - PARAM_SELF_PROLOGUE(DMenu); - PARAM_NAME(name); - ACTION_RETURN_OBJECT(self->GetItem(name)); -} - -DEFINE_ACTION_FUNCTION(DOptionMenuDescriptor, GetItem) -{ - PARAM_SELF_PROLOGUE(DOptionMenuDescriptor); - PARAM_NAME(name); - ACTION_RETURN_OBJECT(self->GetItem(name)); -} - - bool DMenu::DimAllowed() { return true; @@ -1319,41 +1304,6 @@ DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, con return (DMenuItemBase*)p; } -bool DMenuItemBase::CheckCoordinate(int x, int y) -{ - IFVIRTUAL(DMenuItemBase, CheckCoordinate) - { - VMValue params[] = { (DObject*)this, x, y }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return !!retval; - } - return false; -} - -void DMenuItemBase::Ticker() -{ - IFVIRTUAL(DMenuItemBase, Ticker) - { - VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr); - } -} - -bool DMenuItemBase::Selectable() -{ - IFVIRTUAL(DMenuItemBase, Selectable) - { - VMValue params[] = { (DObject*)this }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return !!retval; - } - return false; -} - bool DMenuItemBase::Activate() { IFVIRTUAL(DMenuItemBase, Activate) @@ -1366,18 +1316,6 @@ bool DMenuItemBase::Activate() } return false; } -FName DMenuItemBase::GetAction(int *pparam) -{ - IFVIRTUAL(DMenuItemBase, GetAction) - { - VMValue params[] = { (DObject*)this }; - int retval[2]; - VMReturn ret[2]; ret[0].IntAt(&retval[0]); ret[1].IntAt(&retval[1]); - GlobalVMStack.Call(func, params, countof(params), ret, 2, nullptr); - return ENamedName(retval[0]); - } - return NAME_None; -} bool DMenuItemBase::SetString(int i, const char *s) { @@ -1435,90 +1373,4 @@ bool DMenuItemBase::GetValue(int i, int *pvalue) return false; } - -void DMenuItemBase::Enable(bool on) -{ - IFVIRTUAL(DMenuItemBase, Enable) - { - VMValue params[] = { (DObject*)this, on }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr); - } -} - -bool DMenuItemBase::MenuEvent(int mkey, bool fromcontroller) -{ - IFVIRTUAL(DMenuItemBase, MenuEvent) - { - VMValue params[] = { (DObject*)this, mkey, fromcontroller }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return !!retval; - } - return false; -} - -bool DMenuItemBase::MouseEvent(int type, int x, int y) -{ - IFVIRTUAL(DMenuItemBase, MouseEvent) - { - VMValue params[] = { (DObject*)this, type, x, y }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return !!retval; - } - return false; -} - -bool DMenuItemBase::CheckHotkey(int c) -{ - IFVIRTUAL(DMenuItemBase, CheckHotkey) - { - VMValue params[] = { (DObject*)this, c }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return !!retval; - } - return false; -} - -int DMenuItemBase::GetWidth() -{ - IFVIRTUAL(DMenuItemBase, GetWidth) - { - VMValue params[] = { (DObject*)this }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return retval; - } - return false; -} - -int DMenuItemBase::GetIndent() -{ - IFVIRTUAL(DMenuItemBase, GetIndent) - { - VMValue params[] = { (DObject*)this }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return retval; - } - return false; -} - -int DMenuItemBase::Draw(DOptionMenuDescriptor *desc, int y, int indent, bool selected) -{ - IFVIRTUAL(DMenuItemBase, Draw) - { - VMValue params[] = { (DObject*)this, desc, y, indent, selected }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); - return retval; - } - return false; -} +IMPLEMENT_CLASS(DMenuItemBase, false, false) diff --git a/src/menu/menu.h b/src/menu/menu.h index e197a62ef5..9ca7a6f312 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -286,8 +286,6 @@ public: virtual bool CheckFocus(DMenuItemBase *fc) { return false; } virtual void ReleaseFocus() {} - virtual DMenuItemBase *GetItem(FName name) { return nullptr; } - bool CallResponder(event_t *ev); bool CallMenuEvent(int mkey, bool fromcontroller); bool CallMouseEvent(int type, int x, int y); @@ -317,61 +315,15 @@ public: FNameNoInit mAction; bool mEnabled; - bool CheckCoordinate(int x, int y); - void Ticker(); - bool Selectable(); bool Activate(); - FName GetAction(int *pparam); bool SetString(int i, const char *s); bool GetString(int i, char *s, int len); bool SetValue(int i, int value); bool GetValue(int i, int *pvalue); - void Enable(bool on); - bool MenuEvent (int mkey, bool fromcontroller); - bool MouseEvent(int type, int x, int y); - bool CheckHotkey(int c); - int GetWidth(); - int GetIndent(); - int Draw(DOptionMenuDescriptor *desc, int y, int indent, bool selected); void OffsetPositionY(int ydelta) { mYpos += ydelta; } int GetY() { return mYpos; } - int GetX() { return mXpos; } - void SetX(int x) { mXpos = x; } }; -//============================================================================= -// -// list menu class runs a menu described by a DListMenuDescriptor -// -//============================================================================= - -class DListMenu : public DMenu -{ - DECLARE_CLASS(DListMenu, DMenu) - HAS_OBJECT_POINTERS; -public: - - DListMenuDescriptor *mDesc; - DMenuItemBase *mFocusControl; - - DListMenu(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL); - virtual void Init(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL); - DMenuItemBase *GetItem(FName name); - void SetFocus(DMenuItemBase *fc) - { - mFocusControl = fc; - } - bool CheckFocus(DMenuItemBase *fc) - { - return mFocusControl == fc; - } - void ReleaseFocus() - { - mFocusControl = NULL; - } -}; - - //============================================================================= // // diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 252533091e..2f5c2603d0 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -868,7 +868,6 @@ static void ParseOptionMenu(FScanner &sc) ParseOptionMenuBody(sc, desc); ReplaceMenu(sc, desc); - if (desc->mIndent == 0) desc->CalcIndent(); } @@ -1340,7 +1339,7 @@ void M_StartupSkillMenu(FGameStartup *gs) // Delete previous contents for(unsigned i=0; imItems.Size(); i++) { - FName n = ld->mItems[i]->GetAction(nullptr); + FName n = ld->mItems[i]->mAction; if (n == NAME_Startgame || n == NAME_StartgameConfirm) { ld->mItems.Resize(i); diff --git a/src/menu/optionmenu.cpp b/src/menu/optionmenu.cpp index acbb3c58e9..87f0adcf12 100644 --- a/src/menu/optionmenu.cpp +++ b/src/menu/optionmenu.cpp @@ -49,32 +49,6 @@ #include "menu/menu.h" -//============================================================================= -// -// -// -//============================================================================= - -void DOptionMenuDescriptor::CalcIndent() -{ - // calculate the menu indent - int widest = 0, thiswidth; - - for (unsigned i = 0; i < mItems.Size(); i++) - { - thiswidth = mItems[i]->GetIndent(); - if (thiswidth > widest) widest = thiswidth; - } - mIndent = widest + 4; -} - -DEFINE_ACTION_FUNCTION(DOptionMenuDescriptor, CalcIndent) -{ - PARAM_SELF_PROLOGUE(DOptionMenuDescriptor); - self->CalcIndent(); - return 0; -} - //============================================================================= // // @@ -85,7 +59,7 @@ DMenuItemBase *DOptionMenuDescriptor::GetItem(FName name) { for(unsigned i=0;iGetAction(NULL); + FName nm = mItems[i]->mAction; if (nm == name) return mItems[i]; } return NULL; diff --git a/wadsrc/static/zscript/menu/listmenu.txt b/wadsrc/static/zscript/menu/listmenu.txt index 2aacbb94c4..db1a4a19c1 100644 --- a/wadsrc/static/zscript/menu/listmenu.txt +++ b/wadsrc/static/zscript/menu/listmenu.txt @@ -40,10 +40,10 @@ class ListMenuDescriptor : MenuDescriptor native // //============================================================================= -class ListMenu : Menu native +class ListMenu : Menu { - native ListMenuDescriptor mDesc; - native MenuItemBase mFocusControl; + ListMenuDescriptor mDesc; + MenuItemBase mFocusControl; virtual void Init(Menu parent = NULL, ListMenuDescriptor desc = NULL) { @@ -82,7 +82,7 @@ class ListMenu : Menu native // //============================================================================= - MenuItemBase GetItem(Name name) + ListMenuItem GetItem(Name name) { for(int i = 0; i < mDesc.mItems.Size(); i++) { diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 1640e9d357..103d751049 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -111,7 +111,6 @@ class Menu : Object native native virtual void Ticker(); native virtual void Drawer(); native void Close(); - native MenuItemBase GetItem(Name n); native void ActivateMenu(); static void MenuSound(Sound snd) diff --git a/wadsrc/static/zscript/menu/optionmenu.txt b/wadsrc/static/zscript/menu/optionmenu.txt index 5b06f30206..c6f0247a76 100644 --- a/wadsrc/static/zscript/menu/optionmenu.txt +++ b/wadsrc/static/zscript/menu/optionmenu.txt @@ -56,8 +56,6 @@ class OptionMenuDescriptor : MenuDescriptor native native int mPosition; native bool mDontDim; - native void CalcIndent(); - native OptionMenuItem GetItem(Name iname); void Reset() { // Reset the default settings (ignore all other values in the struct) @@ -66,6 +64,25 @@ class OptionMenuDescriptor : MenuDescriptor native mIndent = 0; mDontDim = 0; } + + //============================================================================= + // + // + // + //============================================================================= + + void CalcIndent() + { + // calculate the menu indent + int widest = 0, thiswidth; + + for (int i = 0; i < mItems.Size(); i++) + { + thiswidth = mItems[i].GetIndent(); + if (thiswidth > widest) widest = thiswidth; + } + mIndent = widest + 4; + } } @@ -88,10 +105,27 @@ class OptionMenu : Menu mParentMenu = parent; mDesc = desc; if (mDesc != NULL && mDesc.mSelectedItem == -1) mDesc.mSelectedItem = FirstSelectable(); - + mDesc.CalcIndent(); } + //============================================================================= + // + // + // + //============================================================================= + + OptionMenuItem GetItem(Name name) + { + for(int i = 0; i < mDesc.mItems.Size(); i++) + { + Name nm = mDesc.mItems[i].GetAction(); + if (nm == name) return mDesc.mItems[i]; + } + return NULL; + } + + //============================================================================= // // diff --git a/wadsrc/static/zscript/menu/optionmenuitems.txt b/wadsrc/static/zscript/menu/optionmenuitems.txt index 4d61edcd0a..9ac3083724 100644 --- a/wadsrc/static/zscript/menu/optionmenuitems.txt +++ b/wadsrc/static/zscript/menu/optionmenuitems.txt @@ -136,7 +136,7 @@ class OptionMenuItemCommand : OptionMenuItemSubmenu // don't execute if no menu is active if (m == null) return false; // don't execute if this item cannot be found in the current menu. - if (m.mDesc.GetItem(mAction) != self) return false; + if (m.GetItem(mAction) != self) return false; Menu.MenuSound("menu/choose"); DoCommand(mAction); return true; @@ -388,7 +388,7 @@ class EnterKey : Menu let parent = OptionMenu(mParentMenu); if (parent != null) { - let it = parent.mDesc.GetItem('Controlmessage'); + let it = parent.GetItem('Controlmessage'); if (it != null) { it.SetValue(0, which); From 06141338f11c9c6c0212e0de01a026646f3a41a3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 19:19:14 +0100 Subject: [PATCH 036/207] - made DMenu's static variables regular global variables because that class is going to go completely scripted soon. --- src/c_cvars.cpp | 6 ++-- src/c_dispatch.cpp | 2 +- src/menu/joystickmenu.cpp | 6 ++-- src/menu/menu.cpp | 76 +++++++++++++++++++-------------------- src/menu/menu.h | 6 ++-- src/menu/menudef.cpp | 2 +- src/menu/messagebox.cpp | 18 +++++----- src/menu/playermenu.cpp | 20 +++++------ src/p_conversation.cpp | 12 +++---- 9 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index cd48e304ec..6430d95ad5 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -207,7 +207,7 @@ DEFINE_ACTION_FUNCTION(_CVar, SetInt) { // Only menus are allowed to change CVARs. PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - if (!(self->GetFlags() & CVAR_MOD) && DMenu::CurrentMenu == nullptr) return 0; + if (!(self->GetFlags() & CVAR_MOD) && CurrentMenu == nullptr) return 0; PARAM_INT(val); UCVarValue v; v.Int = val; @@ -219,7 +219,7 @@ DEFINE_ACTION_FUNCTION(_CVar, SetFloat) { // Only menus are allowed to change CVARs. PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - if (!(self->GetFlags() & CVAR_MOD) && DMenu::CurrentMenu == nullptr) return 0; + if (!(self->GetFlags() & CVAR_MOD) && CurrentMenu == nullptr) return 0; PARAM_FLOAT(val); UCVarValue v; v.Float = (float)val; @@ -231,7 +231,7 @@ DEFINE_ACTION_FUNCTION(_CVar, SetString) { // Only menus are allowed to change CVARs. PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar); - if (!(self->GetFlags() & CVAR_MOD) && DMenu::CurrentMenu == nullptr) return 0; + if (!(self->GetFlags() & CVAR_MOD) && CurrentMenu == nullptr) return 0; PARAM_STRING(val); UCVarValue v; v.String = val.GetChars(); diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 3439034958..184f33adb1 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -666,7 +666,7 @@ void C_DoCommand (const char *cmd, int keynum) // This is only accessible to the special menu item to run CCMDs. DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand) { - if (DMenu::CurrentMenu == nullptr) return 0; + if (CurrentMenu == nullptr) return 0; PARAM_PROLOGUE; PARAM_STRING(cmd); C_DoCommand(cmd); diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index 8813dcaa7f..59b3ad9903 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -189,9 +189,9 @@ void UpdateJoystickMenu(IJoystickConfig *selected) //opt->CalcIndent(); // If the joystick config menu is open, close it if the device it's open for is gone. - if (DMenu::CurrentMenu != nullptr && (DMenu::CurrentMenu->IsKindOf("JoystickConfigMenu"))) + if (CurrentMenu != nullptr && (CurrentMenu->IsKindOf("JoystickConfigMenu"))) { - auto p = DMenu::CurrentMenu->PointerVar("mJoy"); + auto p = CurrentMenu->PointerVar("mJoy"); if (p != nullptr) { unsigned i; @@ -204,7 +204,7 @@ void UpdateJoystickMenu(IJoystickConfig *selected) } if (i == Joysticks.Size()) { - DMenu::CurrentMenu->Close(); + CurrentMenu->Close(); } } } diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index e61ac896c0..57a609b06d 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -69,18 +69,16 @@ CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE) CVAR(Int, m_use_mouse, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -DMenu *DMenu::CurrentMenu; DEFINE_ACTION_FUNCTION(DMenu, GetCurrentMenu) { - ACTION_RETURN_OBJECT(DMenu::CurrentMenu); + ACTION_RETURN_OBJECT(CurrentMenu); } -int DMenu::MenuTime; DEFINE_ACTION_FUNCTION(DMenu, MenuTime) { - ACTION_RETURN_INT(DMenu::MenuTime); + ACTION_RETURN_INT(MenuTime); } FGameStartup GameStartupInfo; @@ -92,6 +90,8 @@ bool MenuButtonOrigin[NUM_MKEYS]; int BackbuttonTime; float BackbuttonAlpha; static bool MenuEnabled = true; +DMenu *CurrentMenu; +int MenuTime; void M_InitVideoModes(); extern PClass *DefaultListMenuClass; @@ -140,7 +140,7 @@ void M_MarkMenus() { GC::Mark(pair->Value); } - GC::Mark(DMenu::CurrentMenu); + GC::Mark(CurrentMenu); } //============================================================================ // @@ -237,7 +237,7 @@ bool DMenu::MenuEvent (int mkey, bool fromcontroller) { Close(); S_Sound (CHAN_VOICE | CHAN_UI, - DMenu::CurrentMenu != nullptr? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE); + CurrentMenu != nullptr? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE); return true; } } @@ -272,13 +272,13 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) void DMenu::Close () { - if (DMenu::CurrentMenu == nullptr) return; // double closing can happen in the save menu. - assert(DMenu::CurrentMenu == this); - DMenu::CurrentMenu = mParentMenu; + if (CurrentMenu == nullptr) return; // double closing can happen in the save menu. + assert(CurrentMenu == this); + CurrentMenu = mParentMenu; Destroy(); - if (DMenu::CurrentMenu != nullptr) + if (CurrentMenu != nullptr) { - GC::WriteBarrier(DMenu::CurrentMenu); + GC::WriteBarrier(CurrentMenu); } else { @@ -401,7 +401,7 @@ void DMenu::CallTicker() void DMenu::Drawer () { - if (this == DMenu::CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) + if (this == CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) { FTexture *tex = TexMan(gameinfo.mBackButton); int w = tex->GetScaledWidth() * CleanXfac; @@ -471,7 +471,7 @@ bool DMenu::TranslateKeyboardEvents() void M_StartControlPanel (bool makeSound) { // intro might call this repeatedly - if (DMenu::CurrentMenu != nullptr) + if (CurrentMenu != nullptr) return; ResetButtonStates (); @@ -503,9 +503,9 @@ void M_StartControlPanel (bool makeSound) void M_ActivateMenu(DMenu *menu) { if (menuactive == MENU_Off) menuactive = MENU_On; - if (DMenu::CurrentMenu != nullptr) DMenu::CurrentMenu->ReleaseCapture(); - DMenu::CurrentMenu = menu; - GC::WriteBarrier(DMenu::CurrentMenu); + if (CurrentMenu != nullptr) CurrentMenu->ReleaseCapture(); + CurrentMenu = menu; + GC::WriteBarrier(CurrentMenu); } DEFINE_ACTION_FUNCTION(DMenu, ActivateMenu) @@ -617,7 +617,7 @@ void M_SetMenu(FName menu, int param) DMenu *newmenu = (DMenu *)cls->CreateNew(); IFVIRTUALPTRNAME(newmenu, "ListMenu", Init) { - VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld }; + VMValue params[3] = { newmenu, CurrentMenu, ld }; GlobalVMStack.Call(func, params, 3, nullptr, 0); } M_ActivateMenu(newmenu); @@ -633,7 +633,7 @@ void M_SetMenu(FName menu, int param) DMenu *newmenu = (DMenu*)cls->CreateNew(); IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init) { - VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld }; + VMValue params[3] = { newmenu, CurrentMenu, ld }; GlobalVMStack.Call(func, params, 3, nullptr, 0); } M_ActivateMenu(newmenu); @@ -648,7 +648,7 @@ void M_SetMenu(FName menu, int param) if (menuclass->IsDescendantOf(RUNTIME_CLASS(DMenu))) { DMenu *newmenu = (DMenu*)menuclass->CreateNew(); - newmenu->mParentMenu = DMenu::CurrentMenu; + newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); return; } @@ -684,7 +684,7 @@ bool M_Responder (event_t *ev) return false; } - if (DMenu::CurrentMenu != nullptr && menuactive != MENU_Off) + if (CurrentMenu != nullptr && menuactive != MENU_Off) { // There are a few input sources we are interested in: // @@ -719,9 +719,9 @@ bool M_Responder (event_t *ev) } // pass everything else on to the current menu - return DMenu::CurrentMenu->CallResponder(ev); + return CurrentMenu->CallResponder(ev); } - else if (DMenu::CurrentMenu->TranslateKeyboardEvents()) + else if (CurrentMenu->TranslateKeyboardEvents()) { ch = ev->data1; keyup = ev->subtype == EV_GUI_KeyUp; @@ -740,7 +740,7 @@ bool M_Responder (event_t *ev) default: if (!keyup) { - return DMenu::CurrentMenu->CallResponder(ev); + return CurrentMenu->CallResponder(ev); } break; } @@ -823,11 +823,11 @@ bool M_Responder (event_t *ev) { MenuButtonTickers[mkey] = KEY_REPEAT_DELAY; } - DMenu::CurrentMenu->CallMenuEvent(mkey, fromcontroller); + CurrentMenu->CallMenuEvent(mkey, fromcontroller); return true; } } - return DMenu::CurrentMenu->CallResponder(ev) || !keyup; + return CurrentMenu->CallResponder(ev) || !keyup; } else if (MenuEnabled) { @@ -868,10 +868,10 @@ bool M_Responder (event_t *ev) void M_Ticker (void) { - DMenu::MenuTime++; - if (DMenu::CurrentMenu != nullptr && menuactive != MENU_Off) + MenuTime++; + if (CurrentMenu != nullptr && menuactive != MENU_Off) { - DMenu::CurrentMenu->CallTicker(); + CurrentMenu->CallTicker(); for (int i = 0; i < NUM_MKEYS; ++i) { @@ -880,7 +880,7 @@ void M_Ticker (void) if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0) { MenuButtonTickers[i] = KEY_REPEAT_RATE; - DMenu::CurrentMenu->CallMenuEvent(i, MenuButtonOrigin[i]); + CurrentMenu->CallMenuEvent(i, MenuButtonOrigin[i]); } } } @@ -920,14 +920,14 @@ void M_Drawer (void) } - if (DMenu::CurrentMenu != nullptr && menuactive != MENU_Off) + if (CurrentMenu != nullptr && menuactive != MENU_Off) { - if (DMenu::CurrentMenu->DimAllowed()) + if (CurrentMenu->DimAllowed()) { screen->Dim(fade); V_SetBorderNeedRefresh(); } - DMenu::CurrentMenu->CallDrawer(); + CurrentMenu->CallDrawer(); } } @@ -940,10 +940,10 @@ void M_Drawer (void) void M_ClearMenus () { M_DemoNoPlay = false; - if (DMenu::CurrentMenu != nullptr) + if (CurrentMenu != nullptr) { - DMenu::CurrentMenu->Destroy(); - DMenu::CurrentMenu = nullptr; + CurrentMenu->Destroy(); + CurrentMenu = nullptr; } V_SetBorderNeedRefresh(); menuactive = MENU_Off; @@ -1181,11 +1181,11 @@ CCMD(reset2saved) // This really should be in the script but we can't do scripted CCMDs yet. CCMD(undocolorpic) { - if (DMenu::CurrentMenu != NULL) + if (CurrentMenu != NULL) { - IFVIRTUALPTR(DMenu::CurrentMenu, DMenu, ResetColor) + IFVIRTUALPTR(CurrentMenu, DMenu, ResetColor) { - VMValue params[] = { (DObject*)DMenu::CurrentMenu }; + VMValue params[] = { (DObject*)CurrentMenu }; GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr); } } diff --git a/src/menu/menu.h b/src/menu/menu.h index 9ca7a6f312..fba7541133 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -107,6 +107,9 @@ public: }; extern FSavegameManager savegameManager; +class DMenu; +extern DMenu *CurrentMenu; +extern int MenuTime; //============================================================================= // @@ -267,9 +270,6 @@ public: BACKBUTTON_TIME = 4*TICRATE }; - static DMenu *CurrentMenu; - static int MenuTime; - TObjPtr mParentMenu; DMenu(DMenu *parent = NULL); diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 2f5c2603d0..f9ecbd808e 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -147,7 +147,7 @@ static void DeinitMenus() } MenuDescriptors.Clear(); OptionValues.Clear(); - DMenu::CurrentMenu = nullptr; + CurrentMenu = nullptr; savegameManager.ClearSaveGames(); } diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index b1d6025555..af2cb9b3d6 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -139,7 +139,7 @@ void DMessageBoxMenu::OnDestroy() void DMessageBoxMenu::CloseSound() { S_Sound (CHAN_VOICE | CHAN_UI, - DMenu::CurrentMenu != NULL? "menu/backup" : "menu/dismiss", snd_menuvolume, ATTN_NONE); + CurrentMenu != NULL? "menu/backup" : "menu/dismiss", snd_menuvolume, ATTN_NONE); } //============================================================================= @@ -212,7 +212,7 @@ void DMessageBoxMenu::Drawer () if (messageSelection >= 0) { - if ((DMenu::MenuTime%8) < 6) + if ((MenuTime%8) < 6) { screen->DrawText(ConFont, OptionSettings.mFontColorSelection, (150 - 160) * CleanXfac + screen->GetWidth() / 2, @@ -431,7 +431,7 @@ CCMD (menu_quit) { // F10 M_StartControlPanel (true); DMenu *newmenu = new DQuitMenu(false); - newmenu->mParentMenu = DMenu::CurrentMenu; + newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); } @@ -511,7 +511,7 @@ CCMD (menu_endgame) //M_StartControlPanel (true); S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); DMenu *newmenu = new DEndGameMenu(false); - newmenu->mParentMenu = DMenu::CurrentMenu; + newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); } @@ -607,7 +607,7 @@ CCMD (quicksave) S_Sound(CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); DMenu *newmenu = new DQuickSaveMenu(false); - newmenu->mParentMenu = DMenu::CurrentMenu; + newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); } @@ -702,7 +702,7 @@ CCMD (quickload) M_StartControlPanel(true); DMenu *newmenu = new DQuickLoadMenu(false); - newmenu->mParentMenu = DMenu::CurrentMenu; + newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); } @@ -714,13 +714,13 @@ CCMD (quickload) void M_StartMessage(const char *message, int messagemode, FName action) { - if (DMenu::CurrentMenu == NULL) + if (CurrentMenu == NULL) { // only play a sound if no menu was active before M_StartControlPanel(menuactive == MENU_Off); } - DMenu *newmenu = new DMessageBoxMenu(DMenu::CurrentMenu, message, messagemode, false, action); - newmenu->mParentMenu = DMenu::CurrentMenu; + DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, message, messagemode, false, action); + newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); } diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index c900cc4a79..c730f2d813 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -66,7 +66,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged) PARAM_INT(g); PARAM_INT(b); // only allow if the menu is active to prevent abuse. - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { char command[24]; players[consoleplayer].userinfo.ColorChanged(MAKERGB(r, g, b)); @@ -91,7 +91,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged) const char *pp = s; FString command("name \""); - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { // Escape any backslashes or quotation marks before sending the name to the console. for (auto p = pp; *p != '\0'; ++p) @@ -118,7 +118,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged) { PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(sel); - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { players[consoleplayer].userinfo.ColorSetChanged(sel); char command[24]; @@ -139,7 +139,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged) PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(sel); PARAM_POINTER(cls, FPlayerClass); - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel - 1); cvar_set("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(cls->Type).GetChars()); @@ -158,7 +158,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged) { PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(sel); - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { players[consoleplayer].userinfo.SkinNumChanged(sel); cvar_set("skin", Skins[sel].Name); @@ -177,7 +177,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged) PARAM_SELF_PROLOGUE(DMenu); PARAM_FLOAT(val); // only allow if the menu is active to prevent abuse. - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { autoaim = float(val); } @@ -195,7 +195,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged) PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(val); // only allow if the menu is active to prevent abuse. - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { team = val == 0 ? TEAM_NONE : val - 1; } @@ -213,7 +213,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged) PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { cvar_set("gender", v == 0 ? "male" : v == 1 ? "female" : "other"); } @@ -231,7 +231,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged) PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { neverswitchonpickup = !!v; } @@ -249,7 +249,7 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged) PARAM_SELF_PROLOGUE(DMenu); PARAM_INT(v); // only allow if the menu is active to prevent abuse. - if (self == DMenu::CurrentMenu) + if (self == CurrentMenu) { cl_run = !!v; } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 54be79e3ca..0133ca961e 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1097,7 +1097,7 @@ public: if (response == mSelection+1) { - int color = ((DMenu::MenuTime%8) < 4) || DMenu::CurrentMenu != this ? CR_RED:CR_GREY; + int color = ((MenuTime%8) < 4) || CurrentMenu != this ? CR_RED:CR_GREY; x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; int yy = (y + fontheight/2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2; @@ -1135,9 +1135,9 @@ void P_FreeStrifeConversations () ClassRoots.Clear(); PrevNode = NULL; - if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu))) + if (CurrentMenu != NULL && CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu))) { - DMenu::CurrentMenu->Close(); + CurrentMenu->Close(); } } @@ -1482,10 +1482,10 @@ void P_ConversationCommand (int netcode, int pnum, BYTE **stream) // The conversation menus are normally closed by the menu code, but that // doesn't happen during demo playback, so we need to do it here. - if (demoplayback && DMenu::CurrentMenu != NULL && - DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu))) + if (demoplayback && CurrentMenu != NULL && + CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu))) { - DMenu::CurrentMenu->Close(); + CurrentMenu->Close(); } if (netcode == DEM_CONVREPLY) { From 0c41a9dee7e9c2f3068540f49b2cd261a904ef0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 20:12:06 +0100 Subject: [PATCH 037/207] - scriptified DTextEnterMenu::Drawer. --- src/menu/menu.h | 2 - src/menu/menuinput.cpp | 115 ++----------------- src/v_video.cpp | 14 +++ wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/menu/textentermenu.txt | 91 ++++++++++++++- 5 files changed, 113 insertions(+), 110 deletions(-) diff --git a/src/menu/menu.h b/src/menu/menu.h index fba7541133..3924ab869e 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -373,11 +373,9 @@ public: // [TP] Added allowcolors DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors = false); - void Drawer (); bool MenuEvent (int mkey, bool fromcontroller); bool Responder(event_t *ev); bool MouseEvent(int type, int x, int y); - FString GetText(); }; diff --git a/src/menu/menuinput.cpp b/src/menu/menuinput.cpp index 9a0b717b51..f880fabfd5 100644 --- a/src/menu/menuinput.cpp +++ b/src/menu/menuinput.cpp @@ -61,8 +61,6 @@ static const char InputGridChars[INPUTGRID_WIDTH * INPUTGRID_HEIGHT] = CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -DEFINE_FIELD(DTextEnterMenu, mInputGridOkay) - //============================================================================= // // @@ -91,24 +89,6 @@ DTextEnterMenu::DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen AllowColors = allowcolors; // [TP] } -//============================================================================= -// -// -// -//============================================================================= - -FString DTextEnterMenu::GetText() -{ - return mEnterString; -} - -//============================================================================= -// -// -// -//============================================================================= - - //============================================================================= // // @@ -294,88 +274,6 @@ bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller) return false; } -//============================================================================= -// -// -// -//============================================================================= - -void DTextEnterMenu::Drawer () -{ - mParentMenu->CallDrawer(); - if (mInputGridOkay) - { - const int cell_width = 18 * CleanXfac; - const int cell_height = 12 * CleanYfac; - const int top_padding = cell_height / 2 - SmallFont->GetHeight() * CleanYfac / 2; - - // Darken the background behind the character grid. - // Unless we frame it with a border, I think it looks better to extend the - // background across the full width of the screen. - screen->Dim(0, 0.8f, - 0 /*screen->GetWidth()/2 - 13 * cell_width / 2*/, - screen->GetHeight() - INPUTGRID_HEIGHT * cell_height, - screen->GetWidth() /*13 * cell_width*/, - INPUTGRID_HEIGHT * cell_height); - - if (InputGridX >= 0 && InputGridY >= 0) - { - // Highlight the background behind the selected character. - screen->Dim(MAKERGB(255,248,220), 0.6f, - InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2, - InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight(), - cell_width, cell_height); - } - - for (int y = 0; y < INPUTGRID_HEIGHT; ++y) - { - const int yy = y * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight(); - for (int x = 0; x < INPUTGRID_WIDTH; ++x) - { - int width; - const int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2; - const int ch = InputGridChars[y * INPUTGRID_WIDTH + x]; - FTexture *pic = SmallFont->GetChar(ch, &width); - EColorRange color; - - // The highlighted character is yellow; the rest are dark gray. - color = (x == InputGridX && y == InputGridY) ? CR_YELLOW : CR_DARKGRAY; - - if (pic != NULL) - { - // Draw a normal character. - screen->DrawChar(SmallFont, color, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding, ch, DTA_CleanNoMove, true, TAG_DONE); - } - else if (ch == ' ') - { - FRemapTable *remap = SmallFont->GetColorTranslation(color); - // Draw the space as a box outline. We also draw it 50% wider than it really is. - const int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4; - const int x2 = x1 + width * 3 * CleanXfac / 2; - const int y1 = yy + top_padding; - const int y2 = y1 + SmallFont->GetHeight() * CleanYfac; - const int palentry = remap->Remap[remap->NumEntries * 2 / 3]; - const uint32 palcolor = remap->Palette[remap->NumEntries * 2 / 3]; - screen->Clear(x1, y1, x2, y1+CleanYfac, palentry, palcolor); // top - screen->Clear(x1, y2, x2, y2+CleanYfac, palentry, palcolor); // bottom - screen->Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palentry, palcolor); // left - screen->Clear(x2-CleanXfac, y1+CleanYfac, x2, y2, palentry, palcolor); // right - } - else if (ch == '\b' || ch == 0) - { - // Draw the backspace and end "characters". - const char *const str = ch == '\b' ? "BS" : "ED"; - screen->DrawText(SmallFont, color, - xx + cell_width/2 - SmallFont->StringWidth(str)*CleanXfac/2, - yy + top_padding, str, DTA_CleanNoMove, true, TAG_DONE); - } - } - } - } - Super::Drawer(); -} - - DEFINE_ACTION_FUNCTION(DTextEnterMenu, Open) { PARAM_PROLOGUE; @@ -389,8 +287,11 @@ DEFINE_ACTION_FUNCTION(DTextEnterMenu, Open) ACTION_RETURN_OBJECT(m); } -DEFINE_ACTION_FUNCTION(DTextEnterMenu, GetText) -{ - PARAM_SELF_PROLOGUE(DTextEnterMenu); - ACTION_RETURN_STRING(self->GetText()); -} +DEFINE_FIELD(DTextEnterMenu, mEnterString); +DEFINE_FIELD(DTextEnterMenu, mEnterSize); +DEFINE_FIELD(DTextEnterMenu, mEnterPos); +DEFINE_FIELD(DTextEnterMenu, mSizeMode); // 1: size is length in chars. 2: also check string width +DEFINE_FIELD(DTextEnterMenu, mInputGridOkay); +DEFINE_FIELD(DTextEnterMenu, InputGridX); +DEFINE_FIELD(DTextEnterMenu, InputGridY); +DEFINE_FIELD(DTextEnterMenu, AllowColors); diff --git a/src/v_video.cpp b/src/v_video.cpp index 6d5913ce14..aca00cfb37 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -398,6 +398,20 @@ void DCanvas::Dim (PalEntry color, float damount, int x1, int y1, int w, int h) } } +DEFINE_ACTION_FUNCTION(_Screen, Dim) +{ + PARAM_PROLOGUE; + PARAM_INT(color); + PARAM_FLOAT(amount); + PARAM_INT(x1); + PARAM_INT(y1); + PARAM_INT(w); + PARAM_INT(h); + screen->Dim(color, float(amount), x1, y1, w, h); + return 0; +} + + //========================================================================== // // DCanvas :: GetScreenshotBuffer diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 6c5d671dee..43d1df05a4 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -162,6 +162,7 @@ struct Screen native native static int GetWidth(); native static int GetHeight(); native static void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1); + native static void Dim(Color col, double amount, int x, int y, int w, int h); native static void DrawHUDTexture(TextureID tex, double x, double y); native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...); diff --git a/wadsrc/static/zscript/menu/textentermenu.txt b/wadsrc/static/zscript/menu/textentermenu.txt index 7974a62bd0..c99285145a 100644 --- a/wadsrc/static/zscript/menu/textentermenu.txt +++ b/wadsrc/static/zscript/menu/textentermenu.txt @@ -2,14 +2,103 @@ // This is only the parts that are needed to make the menu fully work right now. More to come later. class TextEnterMenu : Menu native { + const INPUTGRID_WIDTH = 13; + const INPUTGRID_HEIGHT = 5; + + const Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-=.,!?@'\":;[]()<>^#$%&*/_ \b"; + + native String mEnterString; + native int mEnterSize; + native int mEnterPos; + native int mSizeMode; // 1: size is length in chars. 2: also check string width native bool mInputGridOkay; + native int InputGridX; + native int InputGridY; + native bool AllowColors; native static TextEnterMenu Open(Menu parent, String text, int maxlen, int sizemode, bool fromcontroller); - native String GetText(); + String GetText() + { + return mEnterString; + } + override bool TranslateKeyboardEvents() { return mInputGridOkay; } + + //============================================================================= + // + // + // + //============================================================================= + + override void Drawer () + { + mParentMenu.Drawer(); + if (mInputGridOkay) + { + String InputGridChars = Chars; + int cell_width = 18 * CleanXfac; + int cell_height = 12 * CleanYfac; + int top_padding = cell_height / 2 - SmallFont.GetHeight() * CleanYfac / 2; + + // Darken the background behind the character grid. + screen.Dim(0, 0.8, 0, screen.GetHeight() - INPUTGRID_HEIGHT * cell_height, screen.GetWidth(), INPUTGRID_HEIGHT * cell_height); + + if (InputGridX >= 0 && InputGridY >= 0) + { + // Highlight the background behind the selected character. + screen.Dim(Color(255,248,220), 0.6, + InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2, + InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen.GetHeight(), + cell_width, cell_height); + } + + for (int y = 0; y < INPUTGRID_HEIGHT; ++y) + { + int yy = y * cell_height - INPUTGRID_HEIGHT * cell_height + screen.GetHeight(); + for (int x = 0; x < INPUTGRID_WIDTH; ++x) + { + int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2; + int ch = InputGridChars.CharCodeAt(y * INPUTGRID_WIDTH + x); + int width = SmallFont.GetCharWidth(ch); + + // The highlighted character is yellow; the rest are dark gray. + int colr = (x == InputGridX && y == InputGridY) ? Font.CR_YELLOW : Font.CR_DARKGRAY; + Color palcolor = (x == InputGridX && y == InputGridY) ? Color(160, 120, 0) : Color(120, 120, 120); + + if (ch > 32) + { + // Draw a normal character. + screen.DrawChar(SmallFont, colr, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding, ch, DTA_CleanNoMove, true); + } + else if (ch == 32) + { + // Draw the space as a box outline. We also draw it 50% wider than it really is. + int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4; + int x2 = x1 + width * 3 * CleanXfac / 2; + int y1 = yy + top_padding; + int y2 = y1 + SmallFont.GetHeight() * CleanYfac; + screen.Clear(x1, y1, x2, y1+CleanYfac, palcolor); // top + screen.Clear(x1, y2, x2, y2+CleanYfac, palcolor); // bottom + screen.Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palcolor); // left + screen.Clear(x2-CleanXfac, y1+CleanYfac, x2, y2, palcolor); // right + } + else if (ch == 8 || ch == 0) + { + // Draw the backspace and end "characters". + String str = ch == 8 ? "BS" : "ED"; + screen.DrawText(SmallFont, colr, + xx + cell_width/2 - SmallFont.StringWidth(str)*CleanXfac/2, + yy + top_padding, str, DTA_CleanNoMove, true); + } + } + } + } + Super.Drawer(); + } + } \ No newline at end of file From f5a0f6b3bf21302ead0e30fec7b8bc51fca790ba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 21:18:23 +0100 Subject: [PATCH 038/207] - almost done with TextEnterMenu. --- src/menu/menu.cpp | 2 + src/menu/menu.h | 15 +- src/menu/menuinput.cpp | 241 +------------------ src/scripting/thingdef_data.cpp | 13 +- src/scripting/vm/vm.h | 2 + wadsrc/static/zscript/base.txt | 3 +- wadsrc/static/zscript/menu/menu.txt | 2 + wadsrc/static/zscript/menu/textentermenu.txt | 233 +++++++++++++++++- 8 files changed, 255 insertions(+), 256 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 57a609b06d..50e07f5b24 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -1195,6 +1195,8 @@ CCMD(undocolorpic) DEFINE_FIELD(DMenu, mParentMenu) +DEFINE_FIELD(DMenu, mMouseCapture); +DEFINE_FIELD(DMenu, mBackbuttonSelected); DEFINE_FIELD(DMenuDescriptor, mMenuName) DEFINE_FIELD(DMenuDescriptor, mNetgameMessage) diff --git a/src/menu/menu.h b/src/menu/menu.h index 3924ab869e..c9307a0efa 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -253,9 +253,7 @@ class DMenu : public DObject DECLARE_CLASS (DMenu, DObject) HAS_OBJECT_POINTERS -protected: - bool mMouseCapture; - bool mBackbuttonSelected; + public: enum @@ -271,6 +269,8 @@ public: }; TObjPtr mParentMenu; + bool mMouseCapture; + bool mBackbuttonSelected; DMenu(DMenu *parent = NULL); virtual bool Responder (event_t *ev); @@ -354,7 +354,7 @@ extern FOptionMap OptionValues; class DTextEnterMenu : public DMenu { - DECLARE_ABSTRACT_CLASS(DTextEnterMenu, DMenu) + DECLARE_CLASS(DTextEnterMenu, DMenu) public: FString mEnterString; @@ -370,12 +370,7 @@ public: bool AllowColors; - // [TP] Added allowcolors - DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors = false); - - bool MenuEvent (int mkey, bool fromcontroller); - bool Responder(event_t *ev); - bool MouseEvent(int type, int x, int y); + DTextEnterMenu() {} }; diff --git a/src/menu/menuinput.cpp b/src/menu/menuinput.cpp index f880fabfd5..404b955a06 100644 --- a/src/menu/menuinput.cpp +++ b/src/menu/menuinput.cpp @@ -44,249 +44,10 @@ // [TP] New #includes #include "v_text.h" -IMPLEMENT_CLASS(DTextEnterMenu, true, false) - -#define INPUTGRID_WIDTH 13 -#define INPUTGRID_HEIGHT 5 - -// Heretic and Hexen do not, by default, come with glyphs for all of these -// characters. Oh well. Doom and Strife do. -static const char InputGridChars[INPUTGRID_WIDTH * INPUTGRID_HEIGHT] = - "ABCDEFGHIJKLM" - "NOPQRSTUVWXYZ" - "0123456789+-=" - ".,!?@'\":;[]()" - "<>^#$%&*/_ \b"; - +IMPLEMENT_CLASS(DTextEnterMenu, false, false) CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -//============================================================================= -// -// -// -//============================================================================= - -// [TP] Added allowcolors -DTextEnterMenu::DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors) -: DMenu(parent) -{ - mEnterString = textbuffer; - mEnterSize = maxlen < 0 ? UINT_MAX : unsigned(maxlen); - mSizeMode = sizemode; - mInputGridOkay = showgrid || m_showinputgrid; - if (mEnterString.IsNotEmpty()) - { - InputGridX = INPUTGRID_WIDTH - 1; - InputGridY = INPUTGRID_HEIGHT - 1; - } - else - { - // If we are naming a new save, don't start the cursor on "end". - InputGridX = 0; - InputGridY = 0; - } - AllowColors = allowcolors; // [TP] -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DTextEnterMenu::Responder(event_t *ev) -{ - if (ev->type == EV_GUI_Event) - { - // Save game and player name string input - if (ev->subtype == EV_GUI_Char) - { - mInputGridOkay = false; - if (mEnterString.Len() < mEnterSize && - (mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8)) - { - mEnterString.AppendFormat("%c", (char)ev->data1); - } - return true; - } - char ch = (char)ev->data1; - if ((ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) && ch == '\b') - { - if (mEnterString.IsNotEmpty()) - { - mEnterString.Truncate(mEnterString.Len() - 1); - } - } - else if (ev->subtype == EV_GUI_KeyDown) - { - if (ch == GK_ESCAPE) - { - DMenu *parent = mParentMenu; - Close(); - parent->CallMenuEvent(MKEY_Abort, false); - return true; - } - else if (ch == '\r') - { - if (mEnterString.IsNotEmpty()) - { - // [TP] If we allow color codes, colorize the string now. - if (AllowColors) - mEnterString = strbin1(mEnterString); - - DMenu *parent = mParentMenu; - parent->CallMenuEvent(MKEY_Input, false); - Close(); - return true; - } - } - } - if (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) - { - return true; - } - } - return Super::Responder(ev); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DTextEnterMenu::MouseEvent(int type, int x, int y) -{ - const int cell_width = 18 * CleanXfac; - const int cell_height = 12 * CleanYfac; - const int screen_y = screen->GetHeight() - INPUTGRID_HEIGHT * cell_height; - const int screen_x = (screen->GetWidth() - INPUTGRID_WIDTH * cell_width) / 2; - - if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y) - { - InputGridX = (x - screen_x) / cell_width; - InputGridY = (y - screen_y) / cell_height; - if (type == DMenu::MOUSE_Release) - { - if (CallMenuEvent(MKEY_Enter, true)) - { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); - if (m_use_mouse == 2) InputGridX = InputGridY = -1; - return true; - } - } - } - else - { - InputGridX = InputGridY = -1; - } - return Super::MouseEvent(type, x, y); -} - - - -//============================================================================= -// -// -// -//============================================================================= - -bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller) -{ - if (key == MKEY_Back) - { - mParentMenu->CallMenuEvent(MKEY_Abort, false); - return Super::MenuEvent(key, fromcontroller); - } - if (fromcontroller) - { - mInputGridOkay = true; - } - - if (mInputGridOkay) - { - int ch; - - if (InputGridX == -1 || InputGridY == -1) - { - InputGridX = InputGridY = 0; - } - switch (key) - { - case MKEY_Down: - InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT; - return true; - - case MKEY_Up: - InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT; - return true; - - case MKEY_Right: - InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH; - return true; - - case MKEY_Left: - InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH; - return true; - - case MKEY_Clear: - if (mEnterString.IsNotEmpty()) - { - mEnterString.Truncate(mEnterString.Len() - 1); - } - return true; - - case MKEY_Enter: - assert(unsigned(InputGridX) < INPUTGRID_WIDTH && unsigned(InputGridY) < INPUTGRID_HEIGHT); - if (mInputGridOkay) - { - ch = InputGridChars[InputGridX + InputGridY * INPUTGRID_WIDTH]; - if (ch == 0) // end - { - if (mEnterString.IsNotEmpty()) - { - DMenu *parent = mParentMenu; - Close(); - parent->CallMenuEvent(MKEY_Input, false); - return true; - } - } - else if (ch == '\b') // bs - { - if (mEnterString.IsNotEmpty()) - { - mEnterString.Truncate(mEnterString.Len() - 1); - } - } - else if (mEnterString.Len() < mEnterSize && - (mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8)) - { - mEnterString += char(ch); - } - } - return true; - - default: - break; // Keep GCC quiet - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(DTextEnterMenu, Open) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(parent, DMenu); - PARAM_STRING(text); - PARAM_INT(maxlen); - PARAM_INT(sizemode); - PARAM_BOOL(fromcontroller); - auto m = new DTextEnterMenu(parent, text.GetChars(), maxlen, sizemode, fromcontroller, false); - M_ActivateMenu(m); - ACTION_RETURN_OBJECT(m); -} - DEFINE_FIELD(DTextEnterMenu, mEnterString); DEFINE_FIELD(DTextEnterMenu, mEnterSize); DEFINE_FIELD(DTextEnterMenu, mEnterPos); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 4fb167f561..986f0f1f2c 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1213,10 +1213,12 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid) ACTION_RETURN_STRING(s); } -DEFINE_ACTION_FUNCTION(FStringStruct, Len) +DEFINE_ACTION_FUNCTION(FStringStruct, Truncate) { PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_INT((int)self->Len()); + PARAM_UINT(len); + self->Truncate(len); + return 0; } // CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. @@ -1239,3 +1241,10 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt) ACTION_RETURN_INT(0); ACTION_RETURN_INT((*self)[pos]); } + +DEFINE_ACTION_FUNCTION(FStringStruct, Filter) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_STRING(strbin1(*self)); +} + diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index aa191c34ef..de51327164 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -8,6 +8,8 @@ #include "doomerrors.h" #include "memarena.h" +class DObject; + extern FMemArena ClassDataAllocator; #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 43d1df05a4..9ae86abb5a 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -578,9 +578,10 @@ struct StringStruct native native void Replace(String pattern, String replacement); native String Mid(int pos = 0, int len = 2147483647); - native int Len(); + native void Truncate(int newlen); native String CharAt(int pos); native int CharCodeAt(int pos); + native String Filter(); } class Floor : Thinker native diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 103d751049..2f5d9454a0 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -87,6 +87,8 @@ class Menu : Object native }; native Menu mParentMenu; + native bool mMouseCapture; + native bool mBackbuttonSelected; void Init(Menu parent) { diff --git a/wadsrc/static/zscript/menu/textentermenu.txt b/wadsrc/static/zscript/menu/textentermenu.txt index c99285145a..c48f6854fd 100644 --- a/wadsrc/static/zscript/menu/textentermenu.txt +++ b/wadsrc/static/zscript/menu/textentermenu.txt @@ -16,9 +16,47 @@ class TextEnterMenu : Menu native native int InputGridY; native bool AllowColors; - native static TextEnterMenu Open(Menu parent, String text, int maxlen, int sizemode, bool fromcontroller); - - + //============================================================================= + // + // + // + //============================================================================= + + // [TP] Added allowcolors + private void Init(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors) + { + Super.init(parent); + mEnterString = textbuffer; + mEnterSize = maxlen < 0 ? 0x7fffffff : maxlen; + mSizeMode = sizemode; + mInputGridOkay = showgrid || m_showinputgrid; + if (mEnterString.Length() > 0) + { + InputGridX = INPUTGRID_WIDTH - 1; + InputGridY = INPUTGRID_HEIGHT - 1; + } + else + { + // If we are naming a new save, don't start the cursor on "end". + InputGridX = 0; + InputGridY = 0; + } + AllowColors = allowcolors; // [TP] + } + + static TextEnterMenu Open(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid = false, bool allowcolors = false) + { + let me = new("TextEnterMenu"); + me.Init(parent, textbuffer, maxlen, sizemode, showgrid, allowcolors); + return me; + } + + //============================================================================= + // + // + // + //============================================================================= + String GetText() { return mEnterString; @@ -29,6 +67,195 @@ class TextEnterMenu : Menu native return mInputGridOkay; } + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder(InputEventData ev) + { + if (ev.type == InputEventData.GUI_Event) + { + // Save game and player name string input + if (ev.subtype == InputEventData.GUI_Char) + { + mInputGridOkay = false; + if (mEnterString.Length() < mEnterSize && + (mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8)) + { + mEnterString.AppendFormat("%c", ev.data1); + } + return true; + } + int ch = ev.data1; + if ((ev.subtype == InputEventData.GUI_KeyDown || ev.subtype == InputEventData.GUI_KeyRepeat) && ch == 8) + { + if (mEnterString.Length() > 0) + { + mEnterString.Truncate(mEnterString.Length() - 1); + } + } + else if (ev.subtype == InputEventData.GUI_KeyDown) + { + if (ch == UIEvent.Key_ESCAPE) + { + Menu parent = mParentMenu; + Close(); + parent.MenuEvent(MKEY_Abort, false); + return true; + } + else if (ch == 13) + { + if (mEnterString.Length() > 0) + { + // [TP] If we allow color codes, colorize the string now. + if (AllowColors) + mEnterString = mEnterString.Filter(); + + Menu parent = mParentMenu; + parent.MenuEvent(MKEY_Input, false); + Close(); + return true; + } + } + } + if (ev.subtype == InputEventData.GUI_KeyDown || ev.subtype == InputEventData.GUI_KeyRepeat) + { + return true; + } + } + return Super.Responder(ev); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + if (mMouseCapture || m_use_mouse == 1) + { + int cell_width = 18 * CleanXfac; + int cell_height = 12 * CleanYfac; + int screen_y = screen.GetHeight() - INPUTGRID_HEIGHT * cell_height; + int screen_x = (screen.GetWidth() - INPUTGRID_WIDTH * cell_width) / 2; + + if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y) + { + InputGridX = (x - screen_x) / cell_width; + InputGridY = (y - screen_y) / cell_height; + if (type == MOUSE_Release) + { + if (MenuEvent(MKEY_Enter, true)) + { + MenuSound("menu/choose"); + if (m_use_mouse == 2) InputGridX = InputGridY = -1; + return true; + } + } + } + else + { + InputGridX = InputGridY = -1; + } + } + return Super.MouseEvent(type, x, y); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent (int key, bool fromcontroller) + { + String InputGridChars = Chars; + if (key == MKEY_Back) + { + mParentMenu.MenuEvent(MKEY_Abort, false); + return Super.MenuEvent(key, fromcontroller); + } + if (fromcontroller) + { + mInputGridOkay = true; + } + + if (mInputGridOkay) + { + int ch; + + if (InputGridX == -1 || InputGridY == -1) + { + InputGridX = InputGridY = 0; + } + switch (key) + { + case MKEY_Down: + InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT; + return true; + + case MKEY_Up: + InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT; + return true; + + case MKEY_Right: + InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH; + return true; + + case MKEY_Left: + InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH; + return true; + + case MKEY_Clear: + if (mEnterString.Length() > 0) + { + mEnterString.Truncate(mEnterString.Length() - 1); + } + return true; + + case MKEY_Enter: + if (mInputGridOkay) + { + String c = InputGridChars.CharAt(InputGridX + InputGridY * INPUTGRID_WIDTH); + int ch = c.CharCodeAt(0); + if (ch == 0) // end + { + if (mEnterString.Length() > 0) + { + Menu parent = mParentMenu; + Close(); + parent.MenuEvent(MKEY_Input, false); + return true; + } + } + else if (ch == 8) // bs + { + if (mEnterString.Length() > 0) + { + mEnterString.Truncate(mEnterString.Length() - 1); + } + } + else if (mEnterString.Length() < mEnterSize && + (mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8)) + { + mEnterString = mEnterString .. c; + } + } + return true; + + default: + break; // Keep GCC quiet + } + } + return false; + } + + //============================================================================= // // From de1e7661ebd16517d1329f3c67f6ae5b80fb36e9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 21:25:19 +0100 Subject: [PATCH 039/207] - removed all native remnants of TextEnterMenu. --- src/CMakeLists.txt | 1 - src/menu/menu.cpp | 1 + src/menu/menu.h | 26 +-------- src/menu/menuinput.cpp | 58 -------------------- wadsrc/static/zscript/menu/textentermenu.txt | 54 ++++++++++++++---- 5 files changed, 46 insertions(+), 94 deletions(-) delete mode 100644 src/menu/menuinput.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04f2d0cd9f..7619c6334f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -848,7 +848,6 @@ set( FASTMATH_PCH_SOURCES menu/loadsavemenu.cpp menu/menu.cpp menu/menudef.cpp - menu/menuinput.cpp menu/messagebox.cpp menu/optionmenu.cpp menu/playermenu.cpp diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 50e07f5b24..54615f4e71 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -63,6 +63,7 @@ CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE) +CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE) diff --git a/src/menu/menu.h b/src/menu/menu.h index c9307a0efa..415e3dff67 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -348,34 +348,10 @@ extern FOptionMap OptionValues; //============================================================================= // -// Input some text +// // //============================================================================= -class DTextEnterMenu : public DMenu -{ - DECLARE_CLASS(DTextEnterMenu, DMenu) - -public: - FString mEnterString; - unsigned int mEnterSize; - unsigned int mEnterPos; - int mSizeMode; // 1: size is length in chars. 2: also check string width - bool mInputGridOkay; - - int InputGridX; - int InputGridY; - - // [TP] - bool AllowColors; - - - DTextEnterMenu() {} -}; - - - - struct event_t; void M_EnableMenu (bool on) ; bool M_Responder (event_t *ev); diff --git a/src/menu/menuinput.cpp b/src/menu/menuinput.cpp deleted file mode 100644 index 404b955a06..0000000000 --- a/src/menu/menuinput.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -** menuinput.cpp -** The string input code -** -**--------------------------------------------------------------------------- -** Copyright 2001-2010 Randy Heit -** Copyright 2010 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "menu/menu.h" -#include "v_video.h" -#include "c_cvars.h" -#include "d_event.h" -#include "d_gui.h" -#include "v_font.h" -#include "v_palette.h" -#include "cmdlib.h" -// [TP] New #includes -#include "v_text.h" - -IMPLEMENT_CLASS(DTextEnterMenu, false, false) - -CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -DEFINE_FIELD(DTextEnterMenu, mEnterString); -DEFINE_FIELD(DTextEnterMenu, mEnterSize); -DEFINE_FIELD(DTextEnterMenu, mEnterPos); -DEFINE_FIELD(DTextEnterMenu, mSizeMode); // 1: size is length in chars. 2: also check string width -DEFINE_FIELD(DTextEnterMenu, mInputGridOkay); -DEFINE_FIELD(DTextEnterMenu, InputGridX); -DEFINE_FIELD(DTextEnterMenu, InputGridY); -DEFINE_FIELD(DTextEnterMenu, AllowColors); diff --git a/wadsrc/static/zscript/menu/textentermenu.txt b/wadsrc/static/zscript/menu/textentermenu.txt index c48f6854fd..356eba1e60 100644 --- a/wadsrc/static/zscript/menu/textentermenu.txt +++ b/wadsrc/static/zscript/menu/textentermenu.txt @@ -1,20 +1,54 @@ +/* +** menuinput.cpp +** The string input code +** +**--------------------------------------------------------------------------- +** Copyright 2001-2010 Randy Heit +** Copyright 2010-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ -// This is only the parts that are needed to make the menu fully work right now. More to come later. -class TextEnterMenu : Menu native + +class TextEnterMenu : Menu { const INPUTGRID_WIDTH = 13; const INPUTGRID_HEIGHT = 5; const Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-=.,!?@'\":;[]()<>^#$%&*/_ \b"; - native String mEnterString; - native int mEnterSize; - native int mEnterPos; - native int mSizeMode; // 1: size is length in chars. 2: also check string width - native bool mInputGridOkay; - native int InputGridX; - native int InputGridY; - native bool AllowColors; + String mEnterString; + int mEnterSize; + int mEnterPos; + int mSizeMode; // 1: size is length in chars. 2: also check string width + bool mInputGridOkay; + int InputGridX; + int InputGridY; + bool AllowColors; //============================================================================= // From 6e0e2b24579747ec64fe52562fffa16ca30c02f9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 22:07:28 +0100 Subject: [PATCH 040/207] - replaced all subclasses of DMessageBoxMenu with a callback option and lambdas to reduce the amount of menu code to port over. Now this is only one class. --- src/menu/menu.cpp | 5 + src/menu/messagebox.cpp | 289 ++++++++-------------------------------- 2 files changed, 57 insertions(+), 237 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 54615f4e71..6569c00c78 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -588,6 +588,11 @@ void M_SetMenu(FName menu, int param) M_InitVideoModes(); break; + case NAME_Quitmenu: + // The separate menu class no longer exists but the name still needs support for existing mods. + C_DoCommand("menu_quit"); + return; + } // End of special checks diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index af2cb9b3d6..7d6312df85 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -58,12 +58,13 @@ class DMessageBoxMenu : public DMenu int messageSelection; int mMouseLeft, mMouseRight, mMouseY; FName mAction; + void (*Handler)(); public: - DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None); + DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None, void (*hnd)() = nullptr); void OnDestroy() override; - void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false); + void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false, void(*hnd)() = nullptr); void Drawer(); bool Responder(event_t *ev); bool MenuEvent(int mkey, bool fromcontroller); @@ -80,7 +81,7 @@ IMPLEMENT_CLASS(DMessageBoxMenu, false, false) // //============================================================================= -DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action) +DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action, void (*hnd)()) : DMenu(parent) { mAction = action; @@ -91,7 +92,7 @@ DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int message int mr2 = 170 + SmallFont->StringWidth(GStrings["TXT_NO"]); mMouseRight = MAX(mr1, mr2); - Init(parent, message, messagemode, playsound); + Init(parent, message, messagemode, playsound, hnd); } //============================================================================= @@ -100,7 +101,7 @@ DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int message // //============================================================================= -void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, bool playsound) +void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, bool playsound, void (*hnd)()) { mParentMenu = parent; if (message != NULL) @@ -115,6 +116,7 @@ void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, S_StopSound (CHAN_VOICE); S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", snd_menuvolume, ATTN_NONE); } + Handler = hnd; } //============================================================================= @@ -150,7 +152,16 @@ void DMessageBoxMenu::CloseSound() void DMessageBoxMenu::HandleResult(bool res) { - if (mParentMenu != NULL) + if (Handler != nullptr) + { + if (res) Handler(); + else + { + Close(); + CloseSound(); + } + } + else if (mParentMenu != NULL) { if (mMessageMode == 0) { @@ -344,156 +355,51 @@ bool DMessageBoxMenu::MouseEvent(int type, int x, int y) } } -//============================================================================= -// -// -// -//============================================================================= //============================================================================= // // // //============================================================================= -class DQuitMenu : public DMessageBoxMenu -{ - DECLARE_CLASS(DQuitMenu, DMessageBoxMenu) +CCMD (menu_quit) +{ // F10 + M_StartControlPanel (true); -public: - - DQuitMenu(bool playsound = false); - virtual void HandleResult(bool res); -}; - -IMPLEMENT_CLASS(DQuitMenu, false, false) - -//============================================================================= -// -// -// -//============================================================================= - -DQuitMenu::DQuitMenu(bool playsound) -{ int messageindex = gametic % gameinfo.quitmessages.Size(); FString EndString; const char *msg = gameinfo.quitmessages[messageindex]; - if (msg[0] == '$') + if (msg[0] == '$') { if (msg[1] == '*') { - EndString = GStrings(msg+2); + EndString = GStrings(msg + 2); } else { - EndString.Format("%s\n\n%s", GStrings(msg+1), GStrings("DOSY")); + EndString.Format("%s\n\n%s", GStrings(msg + 1), GStrings("DOSY")); } } else EndString = gameinfo.quitmessages[messageindex]; - Init(NULL, EndString, 0, playsound); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DQuitMenu::HandleResult(bool res) -{ - if (res) + DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, EndString, 0, false, NAME_None, []() { if (!netgame) { if (gameinfo.quitSound.IsNotEmpty()) { - S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE); - I_WaitVBL (105); + S_Sound(CHAN_VOICE | CHAN_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE); + I_WaitVBL(105); } } ST_Endoom(); - } - else - { - Close(); - CloseSound(); - } -} + }); -//============================================================================= -// -// -// -//============================================================================= -CCMD (menu_quit) -{ // F10 - M_StartControlPanel (true); - DMenu *newmenu = new DQuitMenu(false); - newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); } -//============================================================================= -// -// -// -//============================================================================= -//============================================================================= -// -// -// -//============================================================================= - -class DEndGameMenu : public DMessageBoxMenu -{ - DECLARE_CLASS(DEndGameMenu, DMessageBoxMenu) - -public: - - DEndGameMenu(bool playsound = false); - virtual void HandleResult(bool res); -}; - -IMPLEMENT_CLASS(DEndGameMenu, false, false) - -//============================================================================= -// -// -// -//============================================================================= - -DEndGameMenu::DEndGameMenu(bool playsound) -{ - Init(NULL, GStrings(netgame ? "NETEND" : "ENDGAME"), 0, playsound); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DEndGameMenu::HandleResult(bool res) -{ - if (res) - { - M_ClearMenus (); - if (!netgame) - { - D_StartTitle (); - } - } - else - { - Close(); - CloseSound(); - } -} - //============================================================================= // // @@ -510,67 +416,18 @@ CCMD (menu_endgame) //M_StartControlPanel (true); S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); - DMenu *newmenu = new DEndGameMenu(false); - newmenu->mParentMenu = CurrentMenu; - M_ActivateMenu(newmenu); -} -//============================================================================= -// -// -// -//============================================================================= -//============================================================================= -// -// -// -//============================================================================= - -class DQuickSaveMenu : public DMessageBoxMenu -{ - DECLARE_CLASS(DQuickSaveMenu, DMessageBoxMenu) - -public: - - DQuickSaveMenu(bool playsound = false); - virtual void HandleResult(bool res); -}; - -IMPLEMENT_CLASS(DQuickSaveMenu, false, false) - -//============================================================================= -// -// -// -//============================================================================= - -DQuickSaveMenu::DQuickSaveMenu(bool playsound) -{ - FString tempstring; - - tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars()); - Init(NULL, tempstring, 0, playsound); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DQuickSaveMenu::HandleResult(bool res) -{ - if (res) + FString tempstring = GStrings(netgame ? "NETEND" : "ENDGAME"); + DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() { - G_SaveGame (savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); M_ClearMenus(); - } - else - { - Close(); - CloseSound(); - } + if (!netgame) + { + D_StartTitle(); + } + }); + + M_ActivateMenu(newmenu); } //============================================================================= @@ -606,67 +463,18 @@ CCMD (quicksave) } S_Sound(CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); - DMenu *newmenu = new DQuickSaveMenu(false); - newmenu->mParentMenu = CurrentMenu; - M_ActivateMenu(newmenu); -} -//============================================================================= -// -// -// -//============================================================================= -//============================================================================= -// -// -// -//============================================================================= - -class DQuickLoadMenu : public DMessageBoxMenu -{ - DECLARE_CLASS(DQuickLoadMenu, DMessageBoxMenu) - -public: - - DQuickLoadMenu(bool playsound = false); - virtual void HandleResult(bool res); -}; - -IMPLEMENT_CLASS(DQuickLoadMenu, false, false) - -//============================================================================= -// -// -// -//============================================================================= - -DQuickLoadMenu::DQuickLoadMenu(bool playsound) -{ FString tempstring; + tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars()); - tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars()); - Init(NULL, tempstring, 0, playsound); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DQuickLoadMenu::HandleResult(bool res) -{ - if (res) + DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() { - G_LoadGame (savegameManager.quickSaveSlot->Filename.GetChars()); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); + G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); + S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); M_ClearMenus(); - } - else - { - Close(); - CloseSound(); - } + }); + + M_ActivateMenu(newmenu); } //============================================================================= @@ -699,10 +507,17 @@ CCMD (quickload) G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); return; } + FString tempstring; + tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars()); M_StartControlPanel(true); - DMenu *newmenu = new DQuickLoadMenu(false); - newmenu->mParentMenu = CurrentMenu; + + DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() + { + G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); + S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); + M_ClearMenus(); + }); M_ActivateMenu(newmenu); } From aabcc1f92e3fb2e811887738fca9d41724009cd4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 23:05:01 +0100 Subject: [PATCH 041/207] - scriptified the input functions of DMessageBoxMenu. --- src/menu/messagebox.cpp | 187 ++---------------- src/scripting/vm/vm.h | 2 + wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/menu/messagebox.txt | 221 ++++++++++++++++++++++ 4 files changed, 241 insertions(+), 170 deletions(-) create mode 100644 wadsrc/static/zscript/menu/messagebox.txt diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index 7d6312df85..e4f9c1cf66 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -52,7 +52,7 @@ EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd] class DMessageBoxMenu : public DMenu { DECLARE_CLASS(DMessageBoxMenu, DMenu) - +public: FBrokenLines *mMessage; int mMessageMode; int messageSelection; @@ -66,11 +66,6 @@ public: void OnDestroy() override; void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false, void(*hnd)() = nullptr); void Drawer(); - bool Responder(event_t *ev); - bool MenuEvent(int mkey, bool fromcontroller); - bool MouseEvent(int type, int x, int y); - void CloseSound(); - virtual void HandleResult(bool res); }; IMPLEMENT_CLASS(DMessageBoxMenu, false, false) @@ -138,54 +133,6 @@ void DMessageBoxMenu::OnDestroy() // //============================================================================= -void DMessageBoxMenu::CloseSound() -{ - S_Sound (CHAN_VOICE | CHAN_UI, - CurrentMenu != NULL? "menu/backup" : "menu/dismiss", snd_menuvolume, ATTN_NONE); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMessageBoxMenu::HandleResult(bool res) -{ - if (Handler != nullptr) - { - if (res) Handler(); - else - { - Close(); - CloseSound(); - } - } - else if (mParentMenu != NULL) - { - if (mMessageMode == 0) - { - if (mAction == NAME_None) - { - mParentMenu->CallMenuEvent(res? MKEY_MBYes : MKEY_MBNo, false); - Close(); - } - else - { - Close(); - if (res) M_SetMenu(mAction, -1); - } - CloseSound(); - } - } -} - -//============================================================================= -// -// -// -//============================================================================= - void DMessageBoxMenu::Drawer () { int i, y; @@ -237,122 +184,13 @@ void DMessageBoxMenu::Drawer () } } -//============================================================================= -// -// -// -//============================================================================= - -bool DMessageBoxMenu::Responder(event_t *ev) +typedef void(*hfunc)(); +DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler) { - if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_KeyDown) - { - if (mMessageMode == 0) - { - int ch = tolower(ev->data1); - if (ch == 'n' || ch == ' ') - { - HandleResult(false); - return true; - } - else if (ch == 'y') - { - HandleResult(true); - return true; - } - } - else - { - Close(); - return true; - } - return false; - } - else if (ev->type == EV_KeyDown) - { - Close(); - return true; - } - return Super::Responder(ev); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DMessageBoxMenu::MenuEvent(int mkey, bool fromcontroller) -{ - if (mMessageMode == 0) - { - if (mkey == MKEY_Up || mkey == MKEY_Down) - { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - messageSelection = !messageSelection; - return true; - } - else if (mkey == MKEY_Enter) - { - // 0 is yes, 1 is no - HandleResult(!messageSelection); - return true; - } - else if (mkey == MKEY_Back) - { - HandleResult(false); - return true; - } - return false; - } - else - { - Close(); - CloseSound(); - return true; - } -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DMessageBoxMenu::MouseEvent(int type, int x, int y) -{ - if (mMessageMode == 1) - { - if (type == MOUSE_Click) - { - return MenuEvent(MKEY_Enter, true); - } - return false; - } - else - { - int sel = -1; - int fh = SmallFont->GetHeight() + 1; - - // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture - x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160; - y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100; - - if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + 2 * fh) - { - sel = y >= mMouseY + fh; - } - if (sel != -1 && sel != messageSelection) - { - //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - } - messageSelection = sel; - if (type == MOUSE_Release) - { - return MenuEvent(MKEY_Enter, true); - } - return true; - } + PARAM_PROLOGUE; + PARAM_POINTERTYPE(Handler, hfunc); + Handler(); + return 0; } //============================================================================= @@ -547,4 +385,13 @@ DEFINE_ACTION_FUNCTION(DMenu, StartMessage) PARAM_NAME_DEF(action); M_StartMessage(msg, mode, action); return 0; -} \ No newline at end of file +} + + +DEFINE_FIELD(DMessageBoxMenu, mMessageMode); +DEFINE_FIELD(DMessageBoxMenu, messageSelection); +DEFINE_FIELD(DMessageBoxMenu, mMouseLeft); +DEFINE_FIELD(DMessageBoxMenu, mMouseRight); +DEFINE_FIELD(DMessageBoxMenu, mMouseY); +DEFINE_FIELD(DMessageBoxMenu, mAction); +DEFINE_FIELD(DMessageBoxMenu, Handler); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index de51327164..cda7a1c584 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1030,6 +1030,7 @@ void NullParam(const char *varname); #define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass()); #define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass()); #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; +#define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a; #define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); #define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); @@ -1074,6 +1075,7 @@ void NullParam(const char *varname); #define PARAM_STATE(x) ++paramnum; PARAM_STATE_AT(paramnum,x) #define PARAM_STATE_ACTION(x) ++paramnum; PARAM_STATE_ACTION_AT(paramnum,x) #define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type) +#define PARAM_POINTERTYPE(x,type) ++paramnum; PARAM_POINTERTYPE_AT(paramnum,x,type) #define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type) #define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base) #define PARAM_POINTER_NOT_NULL(x,type) ++paramnum; PARAM_POINTER_NOT_NULL_AT(paramnum,x,type) diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 419adfe76e..2bd535d77a 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -9,6 +9,7 @@ #include "zscript/menu/menuitembase.txt" #include "zscript/menu/menu.txt" +#include "zscript/menu/messagebox.txt" #include "zscript/menu/listmenu.txt" #include "zscript/menu/listmenuitems.txt" #include "zscript/menu/optionmenu.txt" diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt new file mode 100644 index 0000000000..f0b08eb729 --- /dev/null +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -0,0 +1,221 @@ +/* +** messagebox.cpp +** Confirmation, notification screns +** +**--------------------------------------------------------------------------- +** Copyright 2010-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +class MessageBoxMenu : Menu native +{ + native voidptr Handler; + native int mMessageMode; + native int messageSelection; + native int mMouseLeft, mMouseRight, mMouseY; + native Name mAction; + + native static void CallHandler(voidptr hnd); + + + //============================================================================= + // + // + // + //============================================================================= + + protected void CloseSound() + { + MenuSound (GetCurrentMenu() != NULL? "menu/backup" : "menu/dismiss"); + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual void HandleResult(bool res) + { + if (Handler != null) + { + if (res) + { + CallHandler(Handler); + } + else + { + Close(); + CloseSound(); + } + } + else if (mParentMenu != NULL) + { + if (mMessageMode == 0) + { + if (mAction == 'None') + { + mParentMenu.MenuEvent(res? MKEY_MBYes : MKEY_MBNo, false); + Close(); + } + else + { + Close(); + if (res) SetMenu(mAction, -1); + } + CloseSound(); + } + } + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder(InputEventData ev) + { + if (ev.type == InputEventData.GUI_Event && ev.subtype == InputEventData.GUI_KeyDown) + { + if (mMessageMode == 0) + { + // tolower + int ch = ev.data1; + ch = ch >= 65 && ch <91? ch + 32 : ch; + + if (ch == 78 /*'n'*/ || ch == 32) + { + HandleResult(false); + return true; + } + else if (ch == 89 /*'y'*/) + { + HandleResult(true); + return true; + } + } + else + { + Close(); + return true; + } + return false; + } + else if (ev.type == InputEventData.KeyDown) + { + Close(); + return true; + } + return Super.Responder(ev); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent(int mkey, bool fromcontroller) + { + if (mMessageMode == 0) + { + if (mkey == MKEY_Up || mkey == MKEY_Down) + { + MenuSound("menu/cursor"); + messageSelection = !messageSelection; + return true; + } + else if (mkey == MKEY_Enter) + { + // 0 is yes, 1 is no + HandleResult(!messageSelection); + return true; + } + else if (mkey == MKEY_Back) + { + HandleResult(false); + return true; + } + return false; + } + else + { + Close(); + CloseSound(); + return true; + } + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + if (mMessageMode == 1) + { + if (type == MOUSE_Click) + { + return MenuEvent(MKEY_Enter, true); + } + return false; + } + else + { + int sel = -1; + int fh = SmallFont.GetHeight() + 1; + + // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture + x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160; + y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100; + + if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + 2 * fh) + { + sel = y >= mMouseY + fh; + } + if (sel != -1 && sel != messageSelection) + { + //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); + } + messageSelection = sel; + if (type == MOUSE_Release) + { + return MenuEvent(MKEY_Enter, true); + } + return true; + } + } + + +} + + + From 62b594a4990f91e58141d5255898c3732d3a87dc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 23:18:55 +0100 Subject: [PATCH 042/207] - DMessageBoxMenu::Drawer scriptified. --- src/menu/messagebox.cpp | 102 ++++++---------------- wadsrc/static/zscript/menu/messagebox.txt | 61 +++++++++++++ 2 files changed, 89 insertions(+), 74 deletions(-) diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index e4f9c1cf66..078d7f31ef 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -47,13 +47,34 @@ #include "g_game.h" +class DBrokenLines : public DObject +{ + DECLARE_ABSTRACT_CLASS(DBrokenLines, DObject) + +public: + FBrokenLines *mBroken; + unsigned int mCount; + + DBrokenLines(FBrokenLines *broken, unsigned int count) + { + mBroken = broken; + mCount = count; + } + + void OnDestroy() override + { + V_FreeBrokenLines(mBroken); + } +}; + + EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd] class DMessageBoxMenu : public DMenu { DECLARE_CLASS(DMessageBoxMenu, DMenu) public: - FBrokenLines *mMessage; + DBrokenLines *mMessage; int mMessageMode; int messageSelection; int mMouseLeft, mMouseRight, mMouseY; @@ -63,9 +84,7 @@ public: public: DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None, void (*hnd)() = nullptr); - void OnDestroy() override; void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false, void(*hnd)() = nullptr); - void Drawer(); }; IMPLEMENT_CLASS(DMessageBoxMenu, false, false) @@ -102,7 +121,11 @@ void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, if (message != NULL) { if (*message == '$') message = GStrings(message+1); - mMessage = V_BreakLines(SmallFont, 300, message); + unsigned count; + auto Message = V_BreakLines(SmallFont, 300, message, true, &count); + mMessage = new DBrokenLines(Message, count); + GC::WriteBarrier(mMessage); + mMessage->ObjectFlags |= OF_Fixed; } else mMessage = NULL; mMessageMode = messagemode; @@ -114,76 +137,6 @@ void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, Handler = hnd; } -//============================================================================= -// -// -// -//============================================================================= - -void DMessageBoxMenu::OnDestroy() -{ - if (mMessage != NULL) V_FreeBrokenLines(mMessage); - mMessage = NULL; - Super::OnDestroy(); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMessageBoxMenu::Drawer () -{ - int i, y; - PalEntry fade = 0; - - int fontheight = SmallFont->GetHeight(); - //V_SetBorderNeedRefresh(); - //ST_SetNeedRefresh(); - - y = 100; - - if (mMessage != NULL) - { - for (i = 0; mMessage[i].Width >= 0; i++) - y -= SmallFont->GetHeight () / 2; - - for (i = 0; mMessage[i].Width >= 0; i++) - { - screen->DrawText (SmallFont, CR_UNTRANSLATED, 160 - mMessage[i].Width/2, y, mMessage[i].Text, - DTA_Clean, true, TAG_DONE); - y += fontheight; - } - } - - if (mMessageMode == 0) - { - y += fontheight; - mMouseY = y; - screen->DrawText(SmallFont, - messageSelection == 0? OptionSettings.mFontColorSelection : OptionSettings.mFontColor, - 160, y, GStrings["TXT_YES"], DTA_Clean, true, TAG_DONE); - screen->DrawText(SmallFont, - messageSelection == 1? OptionSettings.mFontColorSelection : OptionSettings.mFontColor, - 160, y + fontheight + 1, GStrings["TXT_NO"], DTA_Clean, true, TAG_DONE); - - if (messageSelection >= 0) - { - if ((MenuTime%8) < 6) - { - screen->DrawText(ConFont, OptionSettings.mFontColorSelection, - (150 - 160) * CleanXfac + screen->GetWidth() / 2, - (y + (fontheight + 1) * messageSelection - 100 + fontheight/2 - 5) * CleanYfac + screen->GetHeight() / 2, - "\xd", - DTA_CellX, 8 * CleanXfac, - DTA_CellY, 8 * CleanYfac, - TAG_DONE); - } - } - } -} - typedef void(*hfunc)(); DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler) { @@ -395,3 +348,4 @@ DEFINE_FIELD(DMessageBoxMenu, mMouseRight); DEFINE_FIELD(DMessageBoxMenu, mMouseY); DEFINE_FIELD(DMessageBoxMenu, mAction); DEFINE_FIELD(DMessageBoxMenu, Handler); +DEFINE_FIELD(DMessageBoxMenu, mMessage); diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt index f0b08eb729..f6ad0c639f 100644 --- a/wadsrc/static/zscript/menu/messagebox.txt +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -34,6 +34,7 @@ class MessageBoxMenu : Menu native { + native BrokenLines mMessage; native voidptr Handler; native int mMessageMode; native int messageSelection; @@ -43,6 +44,66 @@ class MessageBoxMenu : Menu native native static void CallHandler(voidptr hnd); + //============================================================================= + // + // + // + //============================================================================= + + override void OnDestroy() + { + mMessage.Destroy(); // explicitly free the strings now. + Super.OnDestroy(); + } + + //============================================================================= + // + // + // + //============================================================================= + + override void Drawer () + { + int i, y; + + int fontheight = SmallFont.GetHeight(); + + y = 100; + + if (mMessage != NULL) + { + int c = mMessage.Count(); + for (i = 0; i < c; i++) + y -= SmallFont.GetHeight () / 2; + + for (i = 0; i < c; i++) + { + screen.DrawText (SmallFont, Font.CR_UNTRANSLATED, 160 - mMessage.StringWidth(i)/2, y, mMessage.StringAt(i), DTA_Clean, true); + y += fontheight; + } + } + + if (mMessageMode == 0) + { + y += fontheight; + mMouseY = y; + screen.DrawText(SmallFont, messageSelection == 0? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, 160, y, Stringtable.Localize("$TXT_YES"), DTA_Clean, true); + screen.DrawText(SmallFont, messageSelection == 1? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, 160, y + fontheight + 1, Stringtable.Localize("$TXT_NO"), DTA_Clean, true); + + if (messageSelection >= 0) + { + if ((MenuTime() % 8) < 6) + { + screen.DrawText(ConFont, OptionMenuSettings.mFontColorSelection, + (150 - 160) * CleanXfac + screen.GetWidth() / 2, + (y + (fontheight + 1) * messageSelection - 100 + fontheight/2 - 5) * CleanYfac + screen.GetHeight() / 2, + "\xd", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); + } + } + } + } + + //============================================================================= // // From e46571c192e568a773be8887b2e3ad515853c217 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Feb 2017 23:39:02 +0100 Subject: [PATCH 043/207] - DMessageBoxMenu is fully scriptified. --- src/menu/messagebox.cpp | 126 ++++------------------ wadsrc/static/zscript/base.txt | 16 +-- wadsrc/static/zscript/menu/messagebox.txt | 53 +++++---- 3 files changed, 62 insertions(+), 133 deletions(-) diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index 078d7f31ef..8cbaa3e241 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -46,97 +46,8 @@ #include "c_dispatch.h" #include "g_game.h" - -class DBrokenLines : public DObject -{ - DECLARE_ABSTRACT_CLASS(DBrokenLines, DObject) - -public: - FBrokenLines *mBroken; - unsigned int mCount; - - DBrokenLines(FBrokenLines *broken, unsigned int count) - { - mBroken = broken; - mCount = count; - } - - void OnDestroy() override - { - V_FreeBrokenLines(mBroken); - } -}; - - EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd] -class DMessageBoxMenu : public DMenu -{ - DECLARE_CLASS(DMessageBoxMenu, DMenu) -public: - DBrokenLines *mMessage; - int mMessageMode; - int messageSelection; - int mMouseLeft, mMouseRight, mMouseY; - FName mAction; - void (*Handler)(); - -public: - - DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None, void (*hnd)() = nullptr); - void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false, void(*hnd)() = nullptr); -}; - -IMPLEMENT_CLASS(DMessageBoxMenu, false, false) - -//============================================================================= -// -// -// -//============================================================================= - -DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action, void (*hnd)()) -: DMenu(parent) -{ - mAction = action; - messageSelection = 0; - mMouseLeft = 140; - mMouseY = INT_MIN; - int mr1 = 170 + SmallFont->StringWidth(GStrings["TXT_YES"]); - int mr2 = 170 + SmallFont->StringWidth(GStrings["TXT_NO"]); - mMouseRight = MAX(mr1, mr2); - - Init(parent, message, messagemode, playsound, hnd); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, bool playsound, void (*hnd)()) -{ - mParentMenu = parent; - if (message != NULL) - { - if (*message == '$') message = GStrings(message+1); - unsigned count; - auto Message = V_BreakLines(SmallFont, 300, message, true, &count); - mMessage = new DBrokenLines(Message, count); - GC::WriteBarrier(mMessage); - mMessage->ObjectFlags |= OF_Fixed; - } - else mMessage = NULL; - mMessageMode = messagemode; - if (playsound) - { - S_StopSound (CHAN_VOICE); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", snd_menuvolume, ATTN_NONE); - } - Handler = hnd; -} - typedef void(*hfunc)(); DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler) { @@ -152,6 +63,23 @@ DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler) // //============================================================================= +DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr) +{ + auto c = PClass::FindClass("MessageBoxMenu"); + auto p = c->CreateNew(); + VMValue params[] = { p, parent, FString(message), messagemode, playsound, action.GetIndex(), handler }; + + auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); + GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + return (DMenu*)p; +} + +//============================================================================= +// +// +// +//============================================================================= + CCMD (menu_quit) { // F10 M_StartControlPanel (true); @@ -172,7 +100,7 @@ CCMD (menu_quit) } else EndString = gameinfo.quitmessages[messageindex]; - DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, EndString, 0, false, NAME_None, []() + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, EndString, 0, false, NAME_None, []() { if (!netgame) { @@ -209,7 +137,7 @@ CCMD (menu_endgame) S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); FString tempstring = GStrings(netgame ? "NETEND" : "ENDGAME"); - DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() { M_ClearMenus(); if (!netgame) @@ -258,7 +186,7 @@ CCMD (quicksave) FString tempstring; tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars()); - DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() { G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars()); S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); @@ -303,7 +231,7 @@ CCMD (quickload) M_StartControlPanel(true); - DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() { G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); @@ -325,7 +253,7 @@ void M_StartMessage(const char *message, int messagemode, FName action) // only play a sound if no menu was active before M_StartControlPanel(menuactive == MENU_Off); } - DMenu *newmenu = new DMessageBoxMenu(CurrentMenu, message, messagemode, false, action); + DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, message, messagemode, false, action); newmenu->mParentMenu = CurrentMenu; M_ActivateMenu(newmenu); } @@ -339,13 +267,3 @@ DEFINE_ACTION_FUNCTION(DMenu, StartMessage) M_StartMessage(msg, mode, action); return 0; } - - -DEFINE_FIELD(DMessageBoxMenu, mMessageMode); -DEFINE_FIELD(DMessageBoxMenu, messageSelection); -DEFINE_FIELD(DMessageBoxMenu, mMouseLeft); -DEFINE_FIELD(DMessageBoxMenu, mMouseRight); -DEFINE_FIELD(DMessageBoxMenu, mMouseY); -DEFINE_FIELD(DMessageBoxMenu, mAction); -DEFINE_FIELD(DMessageBoxMenu, Handler); -DEFINE_FIELD(DMessageBoxMenu, mMessage); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 9ae86abb5a..47dad06bef 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -171,13 +171,6 @@ struct Screen native native static void DrawFrame(int x, int y, int w, int h); } -class BrokenLines : Object native -{ - native int Count(); - native int StringWidth(int line); - native String StringAt(int line); -} - struct Font native { enum EColorRange @@ -248,7 +241,7 @@ struct Font native native static int FindFontColor(Name color); native static Font FindFont(Name fontname); native static Font GetFont(Name fontname); - native static BrokenLines BreakLines(String text, int maxlen); + native BrokenLines BreakLines(String text, int maxlen); } struct Translation @@ -332,6 +325,13 @@ class Object native virtual void OnDestroy() {} } +class BrokenLines : Object native +{ + native int Count(); + native int StringWidth(int line); + native String StringAt(int line); +} + class Thinker : Object native { enum EStatnums diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt index f6ad0c639f..deb73046e2 100644 --- a/wadsrc/static/zscript/menu/messagebox.txt +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -32,14 +32,14 @@ ** */ -class MessageBoxMenu : Menu native +class MessageBoxMenu : Menu { - native BrokenLines mMessage; - native voidptr Handler; - native int mMessageMode; - native int messageSelection; - native int mMouseLeft, mMouseRight, mMouseY; - native Name mAction; + BrokenLines mMessage; + voidptr Handler; + int mMessageMode; + int messageSelection; + int mMouseLeft, mMouseRight, mMouseY; + Name mAction; native static void CallHandler(voidptr hnd); @@ -50,12 +50,26 @@ class MessageBoxMenu : Menu native // //============================================================================= - override void OnDestroy() + void Init(Menu parent, String message, int messagemode, bool playsound = false, Name cmd = 'None', voidptr native_handler = null) { - mMessage.Destroy(); // explicitly free the strings now. - Super.OnDestroy(); + Super.Init(parent); + mAction = cmd; + messageSelection = 0; + mMouseLeft = 140; + mMouseY = 0x80000000; + int mr1 = 170 + SmallFont.StringWidth(Stringtable.Localize("$TXT_YES")); + int mr2 = 170 + SmallFont.StringWidth(Stringtable.Localize("TXT_NO")); + mMouseRight = MAX(mr1, mr2); + mParentMenu = parent; + mMessage = SmallFont.BreakLines(message, 300); + mMessageMode = messagemode; + if (playsound) + { + MenuSound ("menu/prompt"); + } + Handler = native_handler; } - + //============================================================================= // // @@ -70,17 +84,14 @@ class MessageBoxMenu : Menu native y = 100; - if (mMessage != NULL) - { - int c = mMessage.Count(); - for (i = 0; i < c; i++) - y -= SmallFont.GetHeight () / 2; + int c = mMessage.Count(); + for (i = 0; i < c; i++) + y -= SmallFont.GetHeight () / 2; - for (i = 0; i < c; i++) - { - screen.DrawText (SmallFont, Font.CR_UNTRANSLATED, 160 - mMessage.StringWidth(i)/2, y, mMessage.StringAt(i), DTA_Clean, true); - y += fontheight; - } + for (i = 0; i < c; i++) + { + screen.DrawText (SmallFont, Font.CR_UNTRANSLATED, 160 - mMessage.StringWidth(i)/2, y, mMessage.StringAt(i), DTA_Clean, true); + y += fontheight; } if (mMessageMode == 0) From 2440951811050685ca1e88280692edc6848012f7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 00:08:30 +0100 Subject: [PATCH 044/207] -scriptified the ReadThis screen. --- src/CMakeLists.txt | 1 - src/g_level.cpp | 2 + src/g_levellocals.h | 1 + src/g_mapinfo.cpp | 1 + src/gi.cpp | 1 + src/menu/readthis.cpp | 149 ------------------------ src/scripting/thingdef_data.cpp | 5 +- wadsrc/static/zscript.txt | 1 + wadsrc/static/zscript/base.txt | 2 + wadsrc/static/zscript/menu/readthis.txt | 124 ++++++++++++++++++++ 10 files changed, 136 insertions(+), 151 deletions(-) delete mode 100644 src/menu/readthis.cpp create mode 100644 wadsrc/static/zscript/menu/readthis.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7619c6334f..c5149121c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -851,7 +851,6 @@ set( FASTMATH_PCH_SOURCES menu/messagebox.cpp menu/optionmenu.cpp menu/playermenu.cpp - menu/readthis.cpp menu/videomenu.cpp oplsynth/fmopl.cpp oplsynth/mlopl.cpp diff --git a/src/g_level.cpp b/src/g_level.cpp index 0842f3ec84..eafdd7209b 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1461,6 +1461,7 @@ void G_InitLevelLocals () level.LevelName = level.info->LookupLevelName(); level.NextMap = info->NextMap; level.NextSecretMap = info->NextSecretMap; + level.F1Pic = info->F1Pic; compatflags.Callback(); compatflags2.Callback(); @@ -1909,6 +1910,7 @@ DEFINE_FIELD(FLevelLocals, LevelName) DEFINE_FIELD(FLevelLocals, MapName) DEFINE_FIELD(FLevelLocals, NextMap) DEFINE_FIELD(FLevelLocals, NextSecretMap) +DEFINE_FIELD(FLevelLocals, F1Pic) DEFINE_FIELD(FLevelLocals, maptype) DEFINE_FIELD(FLevelLocals, Music) DEFINE_FIELD(FLevelLocals, musicorder) diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 357e2e1545..1b3d1dba2d 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -25,6 +25,7 @@ struct FLevelLocals FString MapName; // the lump name (E1M1, MAP01, etc) FString NextMap; // go here when using the regular exit FString NextSecretMap; // map to go to when used secret exit + FString F1Pic; EMapType maptype; TStaticArray vertexes; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 6f26363371..f83e18ece4 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1970,6 +1970,7 @@ static void ClearMapinfo() DefaultSkill = -1; DeinitIntermissions(); level.info = NULL; + level.F1Pic = ""; } //========================================================================== diff --git a/src/gi.cpp b/src/gi.cpp index b05000d01b..247036ea7a 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -51,6 +51,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, infoPages) const char *GameNames[17] = diff --git a/src/menu/readthis.cpp b/src/menu/readthis.cpp deleted file mode 100644 index 06d4620da1..0000000000 --- a/src/menu/readthis.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* -** readthis.cpp -** Help screens -** -**--------------------------------------------------------------------------- -** Copyright 2001-2010 Randy Heit -** Copyright 2010 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "menu/menu.h" -#include "v_video.h" -#include "g_level.h" -#include "gi.h" -#include "g_levellocals.h" -#include "textures/textures.h" - -class DReadThisMenu : public DMenu -{ - DECLARE_CLASS(DReadThisMenu, DMenu) - int mScreen; - int mInfoTic; - -public: - - DReadThisMenu(DMenu *parent = NULL); - void Drawer(); - bool MenuEvent(int mkey, bool fromcontroller); - bool DimAllowed () { return false; } - bool MouseEvent(int type, int x, int y); -}; - -IMPLEMENT_CLASS(DReadThisMenu, false, false) - -//============================================================================= -// -// Read This Menus -// -//============================================================================= - -DReadThisMenu::DReadThisMenu(DMenu *parent) -: DMenu(parent) -{ - mScreen = 1; - mInfoTic = gametic; -} - - -//============================================================================= -// -// -// -//============================================================================= - -void DReadThisMenu::Drawer() -{ - FTexture *tex = NULL, *prevpic = NULL; - double alpha; - - // Did the mapper choose a custom help page via MAPINFO? - if ((level.info != NULL) && level.info->F1Pic.Len() != 0) - { - tex = TexMan.FindTexture(level.info->F1Pic); - mScreen = 1; - } - - if (tex == NULL) - { - tex = TexMan[gameinfo.infoPages[mScreen-1].GetChars()]; - } - - if (mScreen > 1) - { - prevpic = TexMan[gameinfo.infoPages[mScreen-2].GetChars()]; - } - - screen->Dim(0, 1.0, 0,0, SCREENWIDTH, SCREENHEIGHT); - alpha = MIN((gametic - mInfoTic) * (3. / TICRATE), 1.); - if (alpha < 1. && prevpic != NULL) - { - screen->DrawTexture (prevpic, 0, 0, DTA_Fullscreen, true, TAG_DONE); - } - screen->DrawTexture (tex, 0, 0, DTA_Fullscreen, true, DTA_Alpha, alpha, TAG_DONE); - -} - - -//============================================================================= -// -// -// -//============================================================================= - -bool DReadThisMenu::MenuEvent(int mkey, bool fromcontroller) -{ - if (mkey == MKEY_Enter) - { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); - mScreen++; - mInfoTic = gametic; - if ((level.info != NULL && level.info->F1Pic.Len() != 0) || mScreen > int(gameinfo.infoPages.Size())) - { - Close(); - } - return true; - } - else return Super::MenuEvent(mkey, fromcontroller); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DReadThisMenu::MouseEvent(int type, int x, int y) -{ - if (type == MOUSE_Click) - { - return MenuEvent(MKEY_Enter, true); - } - return false; -} - diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 986f0f1f2c..3808194e1e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -906,7 +906,10 @@ void InitThingdef() fieldptr = new PField("OptionMenuSettings", NewStruct("FOptionMenuSettings", nullptr), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&OptionSettings); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); - + fieldptr = new PField("gametic", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gametic); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' // is to create a static variable from it and reference that in the script. Yuck!!! diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 2bd535d77a..cbe913fa36 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -22,6 +22,7 @@ #include "zscript/menu/playercontrols.txt" #include "zscript/menu/textentermenu.txt" #include "zscript/menu/videomenu.txt" +#include "zscript/menu/readthis.txt" #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt" diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 47dad06bef..fcad86814e 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -299,6 +299,7 @@ struct GameInfoStruct native native String ArmorIcon2; native int gametype; native bool norandomplayerclass; + native Array infoPages; } class Object native @@ -436,6 +437,7 @@ struct LevelLocals native native readonly String MapName; native String NextMap; native String NextSecretMap; + native String F1Pic; native readonly int maptype; native readonly String Music; native readonly int musicorder; diff --git a/wadsrc/static/zscript/menu/readthis.txt b/wadsrc/static/zscript/menu/readthis.txt new file mode 100644 index 0000000000..a3db8a8a7d --- /dev/null +++ b/wadsrc/static/zscript/menu/readthis.txt @@ -0,0 +1,124 @@ +/* +** readthis.cpp +** Help screens +** +**--------------------------------------------------------------------------- +** Copyright 2001-2010 Randy Heit +** Copyright 2010 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +class ReadThisMenu : Menu +{ + int mScreen; + int mInfoTic; + + //============================================================================= + // + // + // + //============================================================================= + + override void Drawer() + { + double alpha; + TextureID tex, prevpic; + + if (mScreen == 0) + { + mScreen = 1; + mInfoTic = gametic; + } + + // Did the mapper choose a custom help page via MAPINFO? + if (level.F1Pic.Length() != 0) + { + tex = TexMan.CheckForTexture(level.F1Pic, TexMan.Type_MiscPatch); + mScreen = 1; + } + + if (!tex.IsValid()) + { + tex = TexMan.CheckForTexture(gameinfo.infoPages[mScreen-1], TexMan.Type_MiscPatch); + } + + if (mScreen > 1) + { + prevpic = TexMan.CheckForTexture(gameinfo.infoPages[mScreen-2], TexMan.Type_MiscPatch); + } + + screen.Dim(0, 1.0, 0,0, screen.GetWidth(), screen.GetHeight()); + alpha = MIN((gametic - mInfoTic) * (3. / Thinker.TICRATE), 1.); + if (alpha < 1. && prevpic.IsValid()) + { + screen.DrawTexture (prevpic, false, 0, 0, DTA_Fullscreen, true); + } + else alpha = 1; + screen.DrawTexture (tex, false, 0, 0, DTA_Fullscreen, true, DTA_Alpha, alpha); + + } + + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent(int mkey, bool fromcontroller) + { + if (mkey == MKEY_Enter) + { + MenuSound("menu/choose"); + mScreen++; + mInfoTic = gametic; + if (level.F1Pic.Length() != 0 || mScreen > gameinfo.infoPages.Size()) + { + Close(); + } + return true; + } + else return Super.MenuEvent(mkey, fromcontroller); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + if (type == MOUSE_Click) + { + return MenuEvent(MKEY_Enter, true); + } + return false; + } + +} \ No newline at end of file From b1a79414140b6281e5a9eb8282b469c0a8a3e3a8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 01:11:52 +0100 Subject: [PATCH 045/207] - some preparations of the Strife dialogue data to make it usable for ZScript, most importantly this means to replace all const char * with FString. --- src/p_conversation.cpp | 39 +++++++++++++++++---------------------- src/p_conversation.h | 15 ++++++++------- src/p_usdf.cpp | 19 ++++++++++--------- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 0133ca961e..3977d6a01f 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -347,7 +347,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker } // Convert the rest of the data to our own internal format. - node->Dialogue = ncopystring (speech.Dialogue); + node->Dialogue = speech.Dialogue; // The speaker's portrait, if any. speech.Dialogue[0] = 0; //speech.Backdrop[8] = 0; @@ -360,7 +360,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker // The speaker's name, if any. speech.Sound[0] = 0; //speech.Name[16] = 0; - node->SpeakerName = ncopystring(speech.Name); + node->SpeakerName = speech.Name; // The item the speaker should drop when killed. node->DropType = dyn_cast(GetStrifeType(speech.DropType)); @@ -422,7 +422,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker } // Convert the rest of the data to our own internal format. - node->Dialogue = ncopystring (speech.Dialogue); + node->Dialogue = speech.Dialogue; // The Teaser version doesn't have portraits. node->Backdrop.SetInvalid(); @@ -440,7 +440,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker // The speaker's name, if any. speech.Dialogue[0] = 0; //speech.Name[16] = 0; - node->SpeakerName = ncopystring (speech.Name); + node->SpeakerName = speech.Name; // The item the speaker should drop when killed. node->DropType = dyn_cast(GetStrifeType (speech.DropType)); @@ -505,7 +505,7 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) // The message to record in the log for this reply. reply->LogNumber = rsp->Log; - reply->LogString = NULL; + reply->LogString = ""; // The item to receive when this reply is used. reply->GiveType = dyn_cast(GetStrifeType (rsp->GiveType)); @@ -520,31 +520,32 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->ItemCheck[k].Item = inv; reply->ItemCheck[k].Amount = rsp->Count[k]; } + reply->PrintAmount = reply->ItemCheck[0].Amount; reply->ItemCheckRequire.Clear(); reply->ItemCheckExclude.Clear(); // If the first item check has a positive amount required, then // add that to the reply string. Otherwise, use the reply as-is. - reply->Reply = copystring (rsp->Reply); + reply->Reply = rsp->Reply; reply->NeedsGold = (rsp->Count[0] > 0); // QuickYes messages are shown when you meet the item checks. // QuickNo messages are shown when you don't. if (rsp->Yes[0] == '_' && rsp->Yes[1] == 0) { - reply->QuickYes = NULL; + reply->QuickYes = ""; } else { - reply->QuickYes = ncopystring (rsp->Yes); + reply->QuickYes = rsp->Yes; } if (reply->ItemCheck[0].Item != 0) { - reply->QuickNo = ncopystring (rsp->No); + reply->QuickNo = rsp->No; } else { - reply->QuickNo = NULL; + reply->QuickNo = ""; } reply->Next = *replyptr; *replyptr = reply; @@ -560,9 +561,6 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) FStrifeDialogueNode::~FStrifeDialogueNode () { - if (SpeakerName != NULL) delete[] SpeakerName; - if (Dialogue != NULL) delete[] Dialogue; - if (Goodbye != nullptr) delete[] Goodbye; FStrifeDialogueReply *tokill = Children; while (tokill != NULL) { @@ -580,9 +578,6 @@ FStrifeDialogueNode::~FStrifeDialogueNode () FStrifeDialogueReply::~FStrifeDialogueReply () { - if (Reply != NULL) delete[] Reply; - if (QuickYes != NULL) delete[] QuickYes; - if (QuickNo != NULL) delete[] QuickNo; } //============================================================================ @@ -672,7 +667,7 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE) static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player) { - if (reply->Reply == nullptr) + if (reply->Reply.IsEmpty()) return true; int i; @@ -772,7 +767,7 @@ public: ReplyText = GStrings(ReplyText + 1); } FString ReplyString = ReplyText; - if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->ItemCheck[0].Amount); + if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->PrintAmount); FBrokenLines *ReplyLines = V_BreakLines (SmallFont, 320-50-10, ReplyString); @@ -785,7 +780,7 @@ public: V_FreeBrokenLines (ReplyLines); } const char *goodbyestr = CurNode->Goodbye; - if (goodbyestr == nullptr) + if (*goodbyestr == 0) { char goodbye[25]; mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1 + (pr_randomspeech() % NUM_RANDOM_GOODBYES)); @@ -1012,7 +1007,7 @@ public: linesize = 10 * CleanYfac; // Who is talking to you? - if (CurNode->SpeakerName != NULL) + if (CurNode->SpeakerName.IsNotEmpty()) { speakerName = CurNode->SpeakerName; if (speakerName[0] == '$') speakerName = GStrings(speakerName+1); @@ -1315,7 +1310,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply if (!CheckStrifeItem(player, reply->ItemCheck[i].Item, reply->ItemCheck[i].Amount)) { // No, you don't. Say so and let the NPC animate negatively. - if (reply->QuickNo && isconsole) + if (reply->QuickNo.IsNotEmpty() && isconsole) { TerminalResponse(reply->QuickNo); } @@ -1396,7 +1391,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } // Update the quest log, if needed. - if (reply->LogString != NULL) + if (reply->LogString.IsNotEmpty()) { const char *log = reply->LogString; if (log[0] == '$') diff --git a/src/p_conversation.h b/src/p_conversation.h index 8771d95aef..c10c4c6972 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -26,11 +26,11 @@ struct FStrifeDialogueNode int ItemCheckNode; // index into StrifeDialogues PClassActor *SpeakerType; - char *SpeakerName; + FString SpeakerName; FSoundID SpeakerVoice; FTextureID Backdrop; - char *Dialogue; - char *Goodbye = nullptr; // must init to null for binary scripts to work as intended + FString Dialogue; + FString Goodbye; // must init to null for binary scripts to work as intended FStrifeDialogueReply *Children; }; @@ -44,15 +44,16 @@ struct FStrifeDialogueReply PClassActor *GiveType; int ActionSpecial; int Args[5]; + int PrintAmount; TArray ItemCheck; TArray ItemCheckRequire; TArray ItemCheckExclude; - char *Reply; - char *QuickYes; + FString Reply; + FString QuickYes; + FString QuickNo; + FString LogString; int NextNode; // index into StrifeDialogues int LogNumber; - char *LogString; - char *QuickNo; bool NeedsGold; }; diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index f4ebe5ebd3..b8e290deb4 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -232,20 +232,21 @@ class USDFParser : public UDMFParserBase // Todo: Finalize if (reply->ItemCheck.Size() > 0) { - if (reply->ItemCheck[0].Amount <= 0) reply->NeedsGold = false; + reply->PrintAmount = reply->ItemCheck[0].Amount; + if (reply->PrintAmount <= 0) reply->NeedsGold = false; } - reply->Reply = ncopystring(ReplyString); - reply->QuickYes = ncopystring(QuickYes); + reply->Reply = ReplyString; + reply->QuickYes = QuickYes; if (reply->ItemCheck.Size() > 0 && reply->ItemCheck[0].Item != NULL) { - reply->QuickNo = ncopystring(QuickNo); + reply->QuickNo = QuickNo; } else { - reply->QuickNo = NULL; + reply->QuickNo = ""; } - reply->LogString = ncopystring(LogString); + reply->LogString = LogString; if(!closeDialog) reply->NextNode *= -1; return true; } @@ -373,9 +374,9 @@ class USDFParser : public UDMFParserBase } } } - node->SpeakerName = ncopystring(SpeakerName); - node->Dialogue = ncopystring(Dialogue); - node->Goodbye = ncopystring(Goodbye); + node->SpeakerName = SpeakerName; + node->Dialogue = Dialogue; + node->Goodbye = Goodbye; return true; } From c0dd37e16eb0a7ce24d2ffbebed4f5c65bf91c0f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 01:14:31 +0100 Subject: [PATCH 046/207] - ncopystring is not needed anymore. --- src/cmdlib.cpp | 17 ----------------- src/cmdlib.h | 1 - 2 files changed, 18 deletions(-) diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index f7fb94510a..471c02cc8a 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -95,23 +95,6 @@ char *copystring (const char *s) return b; } -//============================================================================ -// -// ncopystring -// -// If the string has no content, returns NULL. Otherwise, returns a copy. -// -//============================================================================ - -char *ncopystring (const char *string) -{ - if (string == NULL || string[0] == 0) - { - return NULL; - } - return copystring (string); -} - //========================================================================== // // ReplaceString diff --git a/src/cmdlib.h b/src/cmdlib.h index 6e9fcd622f..7af4e630b5 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -38,7 +38,6 @@ int ParseHex(const char *str, FScriptPosition *sc = nullptr); bool IsNum (const char *str); // [RH] added char *copystring(const char *s); -char *ncopystring(const char *s); void ReplaceString (char **ptr, const char *str); bool CheckWildcards (const char *pattern, const char *text); From 033792078cd904d79c0d1ca0a31db10626d1a145 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 19 Feb 2017 11:31:58 +0200 Subject: [PATCH 047/207] Fixed compilation with GCC/Clang src/menu/messagebox.cpp:70:95: error: no viable conversion from 'hfunc' (aka 'void (*)()') to 'VMValue' --- src/menu/messagebox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index 8cbaa3e241..795bb60e4d 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -67,7 +67,7 @@ DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, { auto c = PClass::FindClass("MessageBoxMenu"); auto p = c->CreateNew(); - VMValue params[] = { p, parent, FString(message), messagemode, playsound, action.GetIndex(), handler }; + VMValue params[] = { p, parent, FString(message), messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); From 8db1646056e3960e74ed04a4900311599d2c9ff0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 10:33:10 +0100 Subject: [PATCH 048/207] - fixed: Strife dialogues remembered the last menu's selection index, but with the possibility of changing sets of replies between calls of the same dialogue it should be the reply's index in the list of replies that gets remembered. --- src/p_conversation.cpp | 86 ++++++++++++++++------- wadsrc/static/zscript/menu/messagebox.txt | 2 +- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 3977d6a01f..ae120182ce 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -113,6 +113,7 @@ static int ConversationMenuY; static int ConversationPauseTic; static bool ShowGold; +static int StaticLastReply; static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool include, int type); static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeakerType); @@ -689,6 +690,27 @@ static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player) return false; } +static void SendConversationReply(int node, int reply) +{ + switch (node) + { + case -1: + Net_WriteByte(DEM_CONVNULL); + break; + + case -2: + Net_WriteByte(DEM_CONVCLOSE); + break; + + default: + Net_WriteByte(DEM_CONVREPLY); + Net_WriteWord(node); + Net_WriteByte(reply); + break; + } + StaticLastReply = reply; +} + //============================================================================ // // The conversation menu @@ -699,6 +721,7 @@ class DConversationMenu : public DMenu { DECLARE_CLASS(DConversationMenu, DMenu) +public: FString mSpeaker; FBrokenLines *mDialogueLines; TArray mResponseLines; @@ -707,9 +730,7 @@ class DConversationMenu : public DMenu FStrifeDialogueNode *mCurNode; int mYpos; player_t *mPlayer; - -public: - static int mSelection; + int mSelection; //============================================================================= // @@ -717,7 +738,7 @@ public: // //============================================================================= - DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player) + DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player, int activereply) { mCurNode = CurNode; mPlayer = player; @@ -750,15 +771,20 @@ public: toSay = "."; } mDialogueLines = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay); + mSelection = -1; FStrifeDialogueReply *reply; + int r = -1; int i,j; for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next) { + r++; if (ShouldSkipReply(reply, mPlayer)) { continue; } + if (activereply == r) mSelection = i - 1; + mShowGold |= reply->NeedsGold; const char *ReplyText = reply->Reply; @@ -776,9 +802,14 @@ public: { mResponseLines.Push(ReplyLines[j].Text); } + ++i; V_FreeBrokenLines (ReplyLines); } + if (mSelection == -1) + { + mSelection = r < activereply ? r + 1 : 0; + } const char *goodbyestr = CurNode->Goodbye; if (*goodbyestr == 0) { @@ -841,6 +872,25 @@ public: return false; } + int GetReplyNum() + { + assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size()); + assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode); + + // This is needed because mSelection represents the replies currently being displayed which will + // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] + FStrifeDialogueReply *reply = mCurNode->Children; + int replynum = mSelection; + for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next) + { + if (ShouldSkipReply(reply, mPlayer)) + replynum++; + else + i++; + } + return replynum; + } + //============================================================================= // // @@ -870,36 +920,21 @@ public: } else if (mkey == MKEY_Back) { - Net_WriteByte (DEM_CONVNULL); + SendConversationReply(-1, GetReplyNum()); Close(); return true; } else if (mkey == MKEY_Enter) { + int replynum = GetReplyNum(); if ((unsigned)mSelection >= mResponses.Size()) { - Net_WriteByte(DEM_CONVCLOSE); + SendConversationReply(-1, replynum); } else { - assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size()); - assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode); - - // This is needed because mSelection represents the replies currently being displayed which will - // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] - FStrifeDialogueReply *reply = mCurNode->Children; - int replynum = mSelection; - for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next) - { - if (ShouldSkipReply(reply, mPlayer)) - replynum++; - else - i++; - } // Send dialogue and reply numbers across the wire. - Net_WriteByte(DEM_CONVREPLY); - Net_WriteWord(mCurNode->ThisNodeNum); - Net_WriteByte(replynum); + SendConversationReply(mCurNode->ThisNodeNum, replynum); } Close(); return true; @@ -1108,7 +1143,6 @@ public: }; IMPLEMENT_CLASS(DConversationMenu, true, false) -int DConversationMenu::mSelection; // needs to be preserved if the same dialogue is restarted //============================================================================ @@ -1228,12 +1262,12 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM); } - DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player); + DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player, StaticLastReply); if (CurNode != PrevNode) { // Only reset the selection if showing a different menu. - DConversationMenu::mSelection = 0; + StaticLastReply = 0; PrevNode = CurNode; } diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt index deb73046e2..d952985462 100644 --- a/wadsrc/static/zscript/menu/messagebox.txt +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -58,7 +58,7 @@ class MessageBoxMenu : Menu mMouseLeft = 140; mMouseY = 0x80000000; int mr1 = 170 + SmallFont.StringWidth(Stringtable.Localize("$TXT_YES")); - int mr2 = 170 + SmallFont.StringWidth(Stringtable.Localize("TXT_NO")); + int mr2 = 170 + SmallFont.StringWidth(Stringtable.Localize("$TXT_NO")); mMouseRight = MAX(mr1, mr2); mParentMenu = parent; mMessage = SmallFont.BreakLines(message, 300); From 129787546df64e12ef3e1be805dc69bf76236e59 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 10:46:53 +0100 Subject: [PATCH 049/207] - transitioned the Conversation menu from FBrokenLines to DBrokenLines so that the internal representation matches scriptable types. --- src/p_conversation.cpp | 46 ++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index ae120182ce..9dc0d4ae60 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -711,6 +711,28 @@ static void SendConversationReply(int node, int reply) StaticLastReply = reply; } + +// Needed for the conversion process. +class DBrokenLines : public DObject +{ + DECLARE_ABSTRACT_CLASS(DBrokenLines, DObject) + +public: + FBrokenLines *mBroken; + unsigned int mCount; + + DBrokenLines(FBrokenLines *broken, unsigned int count) + { + mBroken = broken; + mCount = count; + } + + void OnDestroy() override + { + V_FreeBrokenLines(mBroken); + } +}; + //============================================================================ // // The conversation menu @@ -723,7 +745,7 @@ class DConversationMenu : public DMenu public: FString mSpeaker; - FBrokenLines *mDialogueLines; + DBrokenLines *mDialogueLines; TArray mResponseLines; TArray mResponses; bool mShowGold; @@ -770,7 +792,10 @@ public: { toSay = "."; } - mDialogueLines = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay); + unsigned int count; + auto bl = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay, true, &count); + mDialogueLines = new DBrokenLines(bl, count); + mSelection = -1; FStrifeDialogueReply *reply; @@ -833,11 +858,8 @@ public: mResponseLines.Push(FString(goodbyestr)); // Determine where the top of the reply list should be positioned. - i = OptionSettings.mLinespacing; - mYpos = MIN (140, 192 - mResponseLines.Size() * i); - for (i = 0; mDialogueLines[i].Width >= 0; ++i) - { } - i = 44 + i * 10; + mYpos = MIN (140, 192 - mResponseLines.Size() * OptionSettings.mLinespacing); + i = 44 + count * (OptionSettings.mLinespacing + 2); if (mYpos - 100 < i - screen->GetHeight() / CleanYfac / 2) { mYpos = i - screen->GetHeight() / CleanYfac / 2 + 100; @@ -861,7 +883,7 @@ public: void OnDestroy() override { - V_FreeBrokenLines(mDialogueLines); + mDialogueLines->Destroy(); mDialogueLines = NULL; I_SetMusicVolume (1.f); Super::OnDestroy(); @@ -1055,9 +1077,7 @@ public: // Dim the screen behind the dialogue (but only if there is no backdrop). if (!CurNode->Backdrop.isValid()) { - int i; - for (i = 0; mDialogueLines[i].Width >= 0; ++i) - { } + int i = mDialogueLines->mCount; screen->Dim (0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200, 308 * screen->GetWidth() / 320 - 14 * screen->GetWidth () / 320, speakerName == NULL ? linesize * i + 6 * CleanYfac @@ -1078,9 +1098,9 @@ public: y += linesize * 3 / 2; } x = 24 * screen->GetWidth() / 320; - for (int i = 0; mDialogueLines[i].Width >= 0; ++i) + for (int i = 0; i < mDialogueLines->mCount; ++i) { - screen->DrawText (SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines[i].Text, + screen->DrawText (SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines->mBroken[i].Text, DTA_CleanNoMove, true, TAG_DONE); y += linesize; } From c4a90f39afb4af38f7586b1841f77bf7947334fd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 11:49:59 +0100 Subject: [PATCH 050/207] - split up DConversationMenu::Drawer for future flexibility. - fixed: The in-conversation gold display did not work because it relied on an unused global variable. --- src/p_conversation.cpp | 216 ++++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 80 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 9dc0d4ae60..3250651d1a 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -112,7 +112,6 @@ static FDialogueMap ClassRoots; static int ConversationMenuY; static int ConversationPauseTic; -static bool ShowGold; static int StaticLastReply; static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool include, int type); @@ -1026,91 +1025,121 @@ public: //============================================================================ // - // DrawConversationMenu + // Draw the backdrop, returns true if the text background should be dimmed // //============================================================================ - void Drawer() + virtual bool DrawBackdrop() { - const char *speakerName; - int x, y, linesize; - int width, fontheight; - - player_t *cp = &players[consoleplayer]; - - assert (mDialogueLines != NULL); - assert (mCurNode != NULL); - - FStrifeDialogueNode *CurNode = mCurNode; - - if (CurNode == NULL) + if (mCurNode->Backdrop.isValid()) { - Close (); - return; + screen->DrawTexture(TexMan(mCurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE); + return false; } + return true; + } - // [CW] Freeze the game depending on MAPINFO options. - if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE)) - { - menuactive = MENU_On; - } + //============================================================================ + // + // Draw the speaker text + // + //============================================================================ - if (CurNode->Backdrop.isValid()) - { - screen->DrawTexture (TexMan(CurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE); - } - x = 16 * screen->GetWidth() / 320; - y = 16 * screen->GetHeight() / 200; - linesize = 10 * CleanYfac; + virtual void DrawSpeakerText(bool dimbg) + { + FString speakerName; + int x = 16 * screen->GetWidth() / 320; + int y = 16 * screen->GetHeight() / 200; + int linesize = (OptionSettings.mLinespacing+2) * CleanYfac; // Who is talking to you? - if (CurNode->SpeakerName.IsNotEmpty()) + if (mCurNode->SpeakerName.IsNotEmpty()) { - speakerName = CurNode->SpeakerName; - if (speakerName[0] == '$') speakerName = GStrings(speakerName+1); + speakerName = mCurNode->SpeakerName; + if (speakerName[0] == '$') speakerName = GStrings(speakerName + 1); } else { - speakerName = cp->ConversationNPC->GetTag("Person"); + speakerName = players[consoleplayer].ConversationNPC->GetTag("Person"); } // Dim the screen behind the dialogue (but only if there is no backdrop). - if (!CurNode->Backdrop.isValid()) + if (dimbg) { int i = mDialogueLines->mCount; - screen->Dim (0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200, - 308 * screen->GetWidth() / 320 - 14 * screen->GetWidth () / 320, - speakerName == NULL ? linesize * i + 6 * CleanYfac - : linesize * i + 6 * CleanYfac + linesize * 3/2); + screen->Dim(0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200, + 308 * screen->GetWidth() / 320 - 14 * screen->GetWidth() / 320, + speakerName.IsEmpty() ? linesize * i + 6 * CleanYfac + : linesize * i + 6 * CleanYfac + linesize * 3 / 2); } - // Dim the screen behind the PC's choices. - - screen->Dim (0, 0.45f, (24-160) * CleanXfac + screen->GetWidth()/2, - (mYpos - 2 - 100) * CleanYfac + screen->GetHeight()/2, - 272 * CleanXfac, - MIN(mResponseLines.Size() * OptionSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); - - if (speakerName != NULL) + if (speakerName.IsNotEmpty()) { - screen->DrawText (SmallFont, CR_WHITE, x, y, speakerName, + screen->DrawText(SmallFont, CR_WHITE, x, y, speakerName, DTA_CleanNoMove, true, TAG_DONE); y += linesize * 3 / 2; } x = 24 * screen->GetWidth() / 320; for (int i = 0; i < mDialogueLines->mCount; ++i) { - screen->DrawText (SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines->mBroken[i].Text, + screen->DrawText(SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines->mBroken[i].Text, DTA_CleanNoMove, true, TAG_DONE); y += linesize; } + } - if (ShowGold) + + virtual void DrawReplies() + { + // Dim the screen behind the PC's choices. + screen->Dim(0, 0.45f, (24 - 160) * CleanXfac + screen->GetWidth() / 2, + (mYpos - 2 - 100) * CleanYfac + screen->GetHeight() / 2, + 272 * CleanXfac, + MIN(mResponseLines.Size() * OptionSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); + + int y = mYpos; + int fontheight = OptionSettings.mLinespacing; + + int response = 0; + for (unsigned i = 0; i < mResponseLines.Size(); i++, y += fontheight) + { + int width = SmallFont->StringWidth(mResponseLines[i]); + int x = 64; + + screen->DrawText(SmallFont, CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true, TAG_DONE); + + if (i == mResponses[response]) + { + char tbuf[16]; + + response++; + mysnprintf(tbuf, countof(tbuf), "%d.", response); + x = 50 - SmallFont->StringWidth(tbuf); + screen->DrawText(SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE); + + if (response == mSelection + 1) + { + int color = ((MenuTime % 8) < 4) || CurrentMenu != this ? CR_RED : CR_GREY; + + x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; + int yy = (y + fontheight / 2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2; + screen->DrawText(ConFont, color, x, yy, "\xd", + DTA_CellX, 8 * CleanXfac, + DTA_CellY, 8 * CleanYfac, + TAG_DONE); + } + } + } + } + + virtual void DrawGold() + { + if (mShowGold) { auto cointype = PClass::FindActor("Coin"); if (cointype) { - AInventory *coin = cp->ConversationPC->FindInventory(cointype); + AInventory *coin = players[consoleplayer].ConversationPC->FindInventory(cointype); char goldstr[32]; mysnprintf(goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); @@ -1125,39 +1154,32 @@ public: } } - y = mYpos; - fontheight = OptionSettings.mLinespacing; + } - int response = 0; - for (unsigned i = 0; i < mResponseLines.Size(); i++, y += fontheight) + //============================================================================ + // + // DrawConversationMenu + // + //============================================================================ + + void Drawer() + { + if (mCurNode == NULL) { - width = SmallFont->StringWidth(mResponseLines[i]); - x = 64; - - screen->DrawText (SmallFont, CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true, TAG_DONE); - - if (i == mResponses[response]) - { - char tbuf[16]; - - response++; - mysnprintf (tbuf, countof(tbuf), "%d.", response); - x = 50 - SmallFont->StringWidth (tbuf); - screen->DrawText (SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE); - - if (response == mSelection+1) - { - int color = ((MenuTime%8) < 4) || CurrentMenu != this ? CR_RED:CR_GREY; - - x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; - int yy = (y + fontheight/2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2; - screen->DrawText (ConFont, color, x, yy, "\xd", - DTA_CellX, 8 * CleanXfac, - DTA_CellY, 8 * CleanYfac, - TAG_DONE); - } - } + Close (); + return; } + + // [CW] Freeze the game depending on MAPINFO options. + if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE)) + { + menuactive = MENU_On; + } + + bool dimbg = DrawBackdrop(); + DrawSpeakerText(dimbg); + DrawReplies(); + DrawGold(); } }; @@ -1598,3 +1620,37 @@ static void TerminalResponse (const char *str) } } +DEFINE_FIELD(FStrifeDialogueNode, DropType); +DEFINE_FIELD(FStrifeDialogueNode, ThisNodeNum); +DEFINE_FIELD(FStrifeDialogueNode, ItemCheckNode); +DEFINE_FIELD(FStrifeDialogueNode, SpeakerType); +DEFINE_FIELD(FStrifeDialogueNode, SpeakerName); +DEFINE_FIELD(FStrifeDialogueNode, SpeakerVoice); +DEFINE_FIELD(FStrifeDialogueNode, Backdrop); +DEFINE_FIELD(FStrifeDialogueNode, Dialogue); +DEFINE_FIELD(FStrifeDialogueNode, Goodbye); +DEFINE_FIELD(FStrifeDialogueNode, Children); + +DEFINE_FIELD(FStrifeDialogueReply, Next); +DEFINE_FIELD(FStrifeDialogueReply, GiveType); +DEFINE_FIELD(FStrifeDialogueReply, ActionSpecial); +DEFINE_FIELD(FStrifeDialogueReply, Args); +DEFINE_FIELD(FStrifeDialogueReply, PrintAmount); +DEFINE_FIELD(FStrifeDialogueReply, Reply); +DEFINE_FIELD(FStrifeDialogueReply, QuickYes); +DEFINE_FIELD(FStrifeDialogueReply, QuickNo); +DEFINE_FIELD(FStrifeDialogueReply, LogString); +DEFINE_FIELD(FStrifeDialogueReply, NextNode); +DEFINE_FIELD(FStrifeDialogueReply, LogNumber); +DEFINE_FIELD(FStrifeDialogueReply, NeedsGold); + + +DEFINE_FIELD(DConversationMenu, mSpeaker); +DEFINE_FIELD(DConversationMenu, mDialogueLines); +DEFINE_FIELD(DConversationMenu, mResponseLines); +DEFINE_FIELD(DConversationMenu, mResponses); +DEFINE_FIELD(DConversationMenu, mShowGold); +DEFINE_FIELD(DConversationMenu, mCurNode); +DEFINE_FIELD(DConversationMenu, mYpos); +DEFINE_FIELD(DConversationMenu, mPlayer); +DEFINE_FIELD(DConversationMenu, mSelection); From 3c8a5fdbe77b4c877bbd20f36154fba064921f07 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 12:28:05 +0100 Subject: [PATCH 051/207] - scriptified the drawer functions of the conversation menu. --- src/p_conversation.cpp | 161 ------------ wadsrc/static/zscript.txt | 1 + .../static/zscript/menu/conversationmenu.txt | 247 ++++++++++++++++++ 3 files changed, 248 insertions(+), 161 deletions(-) create mode 100644 wadsrc/static/zscript/menu/conversationmenu.txt diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 3250651d1a..dbee57a4e1 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1022,166 +1022,6 @@ public: } return Super::Responder(ev); } - - //============================================================================ - // - // Draw the backdrop, returns true if the text background should be dimmed - // - //============================================================================ - - virtual bool DrawBackdrop() - { - if (mCurNode->Backdrop.isValid()) - { - screen->DrawTexture(TexMan(mCurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE); - return false; - } - return true; - } - - //============================================================================ - // - // Draw the speaker text - // - //============================================================================ - - virtual void DrawSpeakerText(bool dimbg) - { - FString speakerName; - int x = 16 * screen->GetWidth() / 320; - int y = 16 * screen->GetHeight() / 200; - int linesize = (OptionSettings.mLinespacing+2) * CleanYfac; - - // Who is talking to you? - if (mCurNode->SpeakerName.IsNotEmpty()) - { - speakerName = mCurNode->SpeakerName; - if (speakerName[0] == '$') speakerName = GStrings(speakerName + 1); - } - else - { - speakerName = players[consoleplayer].ConversationNPC->GetTag("Person"); - } - - // Dim the screen behind the dialogue (but only if there is no backdrop). - if (dimbg) - { - int i = mDialogueLines->mCount; - screen->Dim(0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200, - 308 * screen->GetWidth() / 320 - 14 * screen->GetWidth() / 320, - speakerName.IsEmpty() ? linesize * i + 6 * CleanYfac - : linesize * i + 6 * CleanYfac + linesize * 3 / 2); - } - - if (speakerName.IsNotEmpty()) - { - screen->DrawText(SmallFont, CR_WHITE, x, y, speakerName, - DTA_CleanNoMove, true, TAG_DONE); - y += linesize * 3 / 2; - } - x = 24 * screen->GetWidth() / 320; - for (int i = 0; i < mDialogueLines->mCount; ++i) - { - screen->DrawText(SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines->mBroken[i].Text, - DTA_CleanNoMove, true, TAG_DONE); - y += linesize; - } - } - - - virtual void DrawReplies() - { - // Dim the screen behind the PC's choices. - screen->Dim(0, 0.45f, (24 - 160) * CleanXfac + screen->GetWidth() / 2, - (mYpos - 2 - 100) * CleanYfac + screen->GetHeight() / 2, - 272 * CleanXfac, - MIN(mResponseLines.Size() * OptionSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); - - int y = mYpos; - int fontheight = OptionSettings.mLinespacing; - - int response = 0; - for (unsigned i = 0; i < mResponseLines.Size(); i++, y += fontheight) - { - int width = SmallFont->StringWidth(mResponseLines[i]); - int x = 64; - - screen->DrawText(SmallFont, CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true, TAG_DONE); - - if (i == mResponses[response]) - { - char tbuf[16]; - - response++; - mysnprintf(tbuf, countof(tbuf), "%d.", response); - x = 50 - SmallFont->StringWidth(tbuf); - screen->DrawText(SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE); - - if (response == mSelection + 1) - { - int color = ((MenuTime % 8) < 4) || CurrentMenu != this ? CR_RED : CR_GREY; - - x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; - int yy = (y + fontheight / 2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2; - screen->DrawText(ConFont, color, x, yy, "\xd", - DTA_CellX, 8 * CleanXfac, - DTA_CellY, 8 * CleanYfac, - TAG_DONE); - } - } - } - } - - virtual void DrawGold() - { - if (mShowGold) - { - auto cointype = PClass::FindActor("Coin"); - if (cointype) - { - AInventory *coin = players[consoleplayer].ConversationPC->FindInventory(cointype); - char goldstr[32]; - - mysnprintf(goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); - screen->DrawText(SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true, - DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE); - screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), - 3, 190, DTA_320x200, true, - DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE); - screen->DrawText(SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE); - screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), - 2, 189, DTA_320x200, true, TAG_DONE); - } - } - - } - - //============================================================================ - // - // DrawConversationMenu - // - //============================================================================ - - void Drawer() - { - if (mCurNode == NULL) - { - Close (); - return; - } - - // [CW] Freeze the game depending on MAPINFO options. - if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE)) - { - menuactive = MENU_On; - } - - bool dimbg = DrawBackdrop(); - DrawSpeakerText(dimbg); - DrawReplies(); - DrawGold(); - } - }; IMPLEMENT_CLASS(DConversationMenu, true, false) @@ -1316,7 +1156,6 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang // And open the menu M_StartControlPanel (false); M_ActivateMenu(cmenu); - ConversationPauseTic = gametic + 20; menuactive = MENU_OnNoPause; } } diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index cbe913fa36..528431575a 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -23,6 +23,7 @@ #include "zscript/menu/textentermenu.txt" #include "zscript/menu/videomenu.txt" #include "zscript/menu/readthis.txt" +#include "zscript/menu/conversationmenu.txt" #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt" diff --git a/wadsrc/static/zscript/menu/conversationmenu.txt b/wadsrc/static/zscript/menu/conversationmenu.txt new file mode 100644 index 0000000000..474fd50f2a --- /dev/null +++ b/wadsrc/static/zscript/menu/conversationmenu.txt @@ -0,0 +1,247 @@ +/* +** conversationmenu.txt +** The Strife dialogue display +** +**--------------------------------------------------------------------------- +** Copyright 2010-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +struct StrifeDialogueNode native +{ + native Class DropType; + native int ThisNodeNum; + native int ItemCheckNode; + + native Class SpeakerType; + native String SpeakerName; + native Sound SpeakerVoice; + native TextureID Backdrop; + native String Dialogue; + native String Goodbye; + + native StrifeDialogueReply Children; +} + +// FStrifeDialogueReply holds responses the player can give to the NPC +struct StrifeDialogueReply native +{ + native StrifeDialogueReply Next; + native Class GiveType; + native int ActionSpecial; + native int Args[5]; + native int PrintAmount; + native String Reply; + native String QuickYes; + native String QuickNo; + native String LogString; + native int NextNode; // index into StrifeDialogues + native int LogNumber; + native bool NeedsGold; +} + + +class ConversationMenu : Menu native +{ + native String mSpeaker; + native BrokenLines mDialogueLines; + native Array mResponseLines; + native Array mResponses; + native bool mShowGold; + native StrifeDialogueNode mCurNode; + native int mYpos; + native PlayerInfo mPlayer; + native int mSelection; + + //ConversationPauseTic = gametic + 20; + + //============================================================================ + // + // Draw the backdrop, returns true if the text background should be dimmed + // + //============================================================================ + + virtual bool DrawBackdrop() + { + if (mCurNode.Backdrop.isValid()) + { + screen.DrawTexture(mCurNode.Backdrop, false, 0, 0, DTA_320x200, true); + return false; + } + return true; + } + + //============================================================================ + // + // Draw the speaker text + // + //============================================================================ + + virtual void DrawSpeakerText(bool dimbg) + { + String speakerName; + int linesize = OptionMenuSettings.mLinespacing * CleanYfac; + int cnt = mDialogueLines.Count(); + + // Who is talking to you? + if (mCurNode.SpeakerName.Length() > 0) + { + speakerName = Stringtable.Localize(mCurNode.SpeakerName); + } + else + { + speakerName = players[consoleplayer].ConversationNPC.GetTag("Person"); + } + + + // Dim the screen behind the dialogue (but only if there is no backdrop). + if (dimbg) + { + int x = 14 * screen.GetWidth() / 320; + int y = 13 * screen.GetHeight() / 200; + int w = 294 * screen.GetWidth() / 320; + int h = linesize * cnt + 6 * CleanYfac; + if (speakerName.Length() > 0) h += linesize * 3 / 2; + screen.Dim(0, 0.45f, x, y, w, h); + } + + int x = 16 * screen.GetWidth() / 320; + int y = 16 * screen.GetHeight() / 200; + + if (speakerName.Length() > 0) + { + screen.DrawText(SmallFont, Font.CR_WHITE, x, y, speakerName, DTA_CleanNoMove, true); + y += linesize * 3 / 2; + } + x = 24 * screen.GetWidth() / 320; + for (int i = 0; i < cnt; ++i) + { + screen.DrawText(SmallFont, Font.CR_UNTRANSLATED, x, y, mDialogueLines.StringAt(i), DTA_CleanNoMove, true); + y += linesize; + } + } + + + //============================================================================ + // + // Draw the replies + // + //============================================================================ + + virtual void DrawReplies() + { + // Dim the screen behind the PC's choices. + screen.Dim(0, 0.45, (24 - 160) * CleanXfac + screen.GetWidth() / 2, (mYpos - 2 - 100) * CleanYfac + screen.GetHeight() / 2, + 272 * CleanXfac, MIN(mResponseLines.Size() * OptionMenuSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); + + int y = mYpos; + int fontheight = OptionMenuSettings.mLinespacing; + + int response = 0; + for (int i = 0; i < mResponseLines.Size(); i++) + { + int width = SmallFont.StringWidth(mResponseLines[i]); + int x = 64; + + screen.DrawText(SmallFont, Font.CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true); + + if (i == mResponses[response]) + { + String tbuf; + + response++; + tbuf = String.Format("%d.", response); + x = 50 - SmallFont.StringWidth(tbuf); + screen.DrawText(SmallFont, Font.CR_GREY, x, y, tbuf, DTA_Clean, true); + + if (response == mSelection + 1) + { + int colr = ((MenuTime() % 8) < 4) || GetCurrentMenu() != self ? Font.CR_RED : Font.CR_GREY; + + x = (50 + 3 - 160) * CleanXfac + screen.GetWidth() / 2; + int yy = (y + fontheight / 2 - 5 - 100) * CleanYfac + screen.GetHeight() / 2; + screen.DrawText(ConFont, colr, x, yy, "\xd", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); + } + } + y += fontheight; + } + } + + virtual void DrawGold() + { + if (mShowGold) + { + let coin = players[consoleplayer].ConversationPC.FindInventory("Coin"); + let icon = GetDefaultByType("Coin").Icon; + let goldstr = String.Format("%d", coin != NULL ? coin.Amount : 0); + screen.DrawText(SmallFont, Font.CR_GRAY, 21, 191, goldstr, DTA_320x200, true, DTA_FillColor, 0, DTA_Alpha, HR_SHADOW); + screen.DrawTexture(icon, false, 3, 190, DTA_320x200, true, DTA_FillColor, 0, DTA_Alpha, HR_SHADOW); + screen.DrawText(SmallFont, Font.CR_GRAY, 20, 190, goldstr, DTA_320x200, true); + screen.DrawTexture(icon, false, 2, 189, DTA_320x200, true); + } + + } + + //============================================================================ + // + // DrawConversationMenu + // + //============================================================================ + + override void Drawer() + { + if (mCurNode == NULL) + { + Close (); + return; + } + + bool dimbg = DrawBackdrop(); + DrawSpeakerText(dimbg); + DrawReplies(); + DrawGold(); + } + + + //============================================================================ + // + // + // + //============================================================================ + + override void Ticker() + { + // will be reactivated later. + // [CW] Freeze the game depending on MAPINFO options. + //if (ConversationPauseTic < gametic && !multiplayer && !level.no_dlg_freeze) + { + menuactive = Menu.On; + } + } + +} From d85b9cdd71bf8debe549fef5fbd17e3f506eb726 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 13:07:49 +0100 Subject: [PATCH 052/207] - scriptified the input methods of DConversationMenu. - fixed handling of DimAllowed. --- src/g_level.cpp | 1 + src/menu/menu.cpp | 9 +- src/menu/menu.h | 2 +- src/p_conversation.cpp | 161 ++---------------- src/scripting/thingdef_data.cpp | 3 + wadsrc/static/zscript/base.txt | 1 + .../static/zscript/menu/conversationmenu.txt | 145 ++++++++++++++++ wadsrc/static/zscript/menu/listmenu.txt | 2 +- wadsrc/static/zscript/menu/menu.txt | 1 + wadsrc/static/zscript/menu/optionmenu.txt | 1 + 10 files changed, 169 insertions(+), 157 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index eafdd7209b..5bc7d44e05 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1936,6 +1936,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN) DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT) +DEFINE_FIELD_BIT(FLevelLocals, flags2, no_dlg_freeze, LEVEL2_CONV_SINGLE_UNFREEZE) //========================================================================== // diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 6569c00c78..b0bf096f88 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -160,6 +160,7 @@ DMenu::DMenu(DMenu *parent) mParentMenu = parent; mMouseCapture = false; mBackbuttonSelected = false; + DontDim = false; GC::WriteBarrier(this, parent); } @@ -445,11 +446,6 @@ DEFINE_ACTION_FUNCTION(DMenu, Close) return 0; } -bool DMenu::DimAllowed() -{ - return true; -} - bool DMenu::TranslateKeyboardEvents() { IFVIRTUAL(DMenu, TranslateKeyboardEvents) @@ -928,7 +924,7 @@ void M_Drawer (void) if (CurrentMenu != nullptr && menuactive != MENU_Off) { - if (CurrentMenu->DimAllowed()) + if (!CurrentMenu->DontDim) { screen->Dim(fade); V_SetBorderNeedRefresh(); @@ -1203,6 +1199,7 @@ CCMD(undocolorpic) DEFINE_FIELD(DMenu, mParentMenu) DEFINE_FIELD(DMenu, mMouseCapture); DEFINE_FIELD(DMenu, mBackbuttonSelected); +DEFINE_FIELD(DMenu, DontDim); DEFINE_FIELD(DMenuDescriptor, mMenuName) DEFINE_FIELD(DMenuDescriptor, mNetgameMessage) diff --git a/src/menu/menu.h b/src/menu/menu.h index 415e3dff67..7d1236ccf9 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -271,13 +271,13 @@ public: TObjPtr mParentMenu; bool mMouseCapture; bool mBackbuttonSelected; + bool DontDim; DMenu(DMenu *parent = NULL); virtual bool Responder (event_t *ev); virtual bool MenuEvent (int mkey, bool fromcontroller); virtual void Ticker (); virtual void Drawer (); - virtual bool DimAllowed (); bool TranslateKeyboardEvents(); virtual void Close(); virtual bool MouseEvent(int type, int x, int y); diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index dbee57a4e1..10562428b5 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -689,8 +689,18 @@ static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player) return false; } -static void SendConversationReply(int node, int reply) +DEFINE_ACTION_FUNCTION(FStrifeDialogueReply, ShouldSkipReply) { + PARAM_SELF_STRUCT_PROLOGUE(FStrifeDialogueReply); + PARAM_POINTER(player, player_t); + ACTION_RETURN_BOOL(ShouldSkipReply(self, player)); +} + +DEFINE_ACTION_FUNCTION(DConversationMenu, SendConversationReply) +{ + PARAM_PROLOGUE; + PARAM_INT(node); + PARAM_INT(reply); switch (node) { case -1: @@ -708,6 +718,7 @@ static void SendConversationReply(int node, int reply) break; } StaticLastReply = reply; + return 0; } @@ -874,154 +885,6 @@ public: } } - //============================================================================= - // - // - // - //============================================================================= - - void OnDestroy() override - { - mDialogueLines->Destroy(); - mDialogueLines = NULL; - I_SetMusicVolume (1.f); - Super::OnDestroy(); - } - - bool DimAllowed() - { - return false; - } - - int GetReplyNum() - { - assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size()); - assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode); - - // This is needed because mSelection represents the replies currently being displayed which will - // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] - FStrifeDialogueReply *reply = mCurNode->Children; - int replynum = mSelection; - for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next) - { - if (ShouldSkipReply(reply, mPlayer)) - replynum++; - else - i++; - } - return replynum; - } - - //============================================================================= - // - // - // - //============================================================================= - - bool MenuEvent(int mkey, bool fromcontroller) - { - if (demoplayback) - { // During demo playback, don't let the user do anything besides close this menu. - if (mkey == MKEY_Back) - { - Close(); - return true; - } - return false; - } - if (mkey == MKEY_Up) - { - if (--mSelection < 0) mSelection = mResponses.Size() - 1; - return true; - } - else if (mkey == MKEY_Down) - { - if (++mSelection >= (int)mResponses.Size()) mSelection = 0; - return true; - } - else if (mkey == MKEY_Back) - { - SendConversationReply(-1, GetReplyNum()); - Close(); - return true; - } - else if (mkey == MKEY_Enter) - { - int replynum = GetReplyNum(); - if ((unsigned)mSelection >= mResponses.Size()) - { - SendConversationReply(-1, replynum); - } - else - { - // Send dialogue and reply numbers across the wire. - SendConversationReply(mCurNode->ThisNodeNum, replynum); - } - Close(); - return true; - } - return false; - } - - //============================================================================= - // - // - // - //============================================================================= - - bool MouseEvent(int type, int x, int y) - { - int sel = -1; - int fh = OptionSettings.mLinespacing; - - // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture - x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160; - y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100; - - if (x >= 24 && x <= 320-24 && y >= mYpos && y < mYpos + fh * (int)mResponseLines.Size()) - { - sel = (y - mYpos) / fh; - for(unsigned i=0;i sel) - { - sel = i-1; - break; - } - } - } - if (sel != -1 && sel != mSelection) - { - //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - } - mSelection = sel; - if (type == MOUSE_Release) - { - return MenuEvent(MKEY_Enter, true); - } - return true; - } - - - //============================================================================= - // - // - // - //============================================================================= - - bool Responder(event_t *ev) - { - if (demoplayback) - { // No interaction during demo playback - return false; - } - if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_Char && ev->data1 >= '0' && ev->data1 <= '9') - { // Activate an item of type numberedmore (dialogue only) - mSelection = ev->data1 == '0' ? 9 : ev->data1 - '1'; - return MenuEvent(MKEY_Enter, false); - } - return Super::Responder(ev); - } }; IMPLEMENT_CLASS(DConversationMenu, true, false) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 3808194e1e..b527832fd8 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -909,6 +909,9 @@ void InitThingdef() fieldptr = new PField("gametic", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gametic); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + fieldptr = new PField("demoplayback", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&demoplayback); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index fcad86814e..b2eff2601f 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -463,6 +463,7 @@ struct LevelLocals native native bool nomonsters; native bool frozen; native bool infinite_flight; + native bool no_dlg_freeze; // level_info_t *info cannot be done yet. native String GetUDMFString(int type, int index, Name key); diff --git a/wadsrc/static/zscript/menu/conversationmenu.txt b/wadsrc/static/zscript/menu/conversationmenu.txt index 474fd50f2a..efe843c513 100644 --- a/wadsrc/static/zscript/menu/conversationmenu.txt +++ b/wadsrc/static/zscript/menu/conversationmenu.txt @@ -63,6 +63,8 @@ struct StrifeDialogueReply native native int NextNode; // index into StrifeDialogues native int LogNumber; native bool NeedsGold; + + native bool ShouldSkipReply(PlayerInfo player); } @@ -78,8 +80,151 @@ class ConversationMenu : Menu native native PlayerInfo mPlayer; native int mSelection; + native static void SendConversationReply(int node, int reply); + //ConversationPauseTic = gametic + 20; + // DontDim = true; + //============================================================================= + // + // + // + //============================================================================= + + override void OnDestroy() + { + mDialogueLines.Destroy(); + SetMusicVolume (1); + Super.OnDestroy(); + } + + protected int GetReplyNum() + { + // This is needed because mSelection represents the replies currently being displayed which will + // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] + let reply = mCurNode.Children; + int replynum = mSelection; + for (int i = 0; i <= mSelection && reply != null; reply = reply.Next) + { + if (reply.ShouldSkipReply(mPlayer)) + replynum++; + else + i++; + } + return replynum; + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent(int mkey, bool fromcontroller) + { + if (demoplayback) + { // During demo playback, don't let the user do anything besides close this menu. + if (mkey == MKEY_Back) + { + Close(); + return true; + } + return false; + } + if (mkey == MKEY_Up) + { + if (--mSelection < 0) mSelection = mResponses.Size() - 1; + return true; + } + else if (mkey == MKEY_Down) + { + if (++mSelection >= mResponses.Size()) mSelection = 0; + return true; + } + else if (mkey == MKEY_Back) + { + SendConversationReply(-1, GetReplyNum()); + Close(); + return true; + } + else if (mkey == MKEY_Enter) + { + int replynum = GetReplyNum(); + if (mSelection >= mResponses.Size()) + { + SendConversationReply(-2, replynum); + } + else + { + // Send dialogue and reply numbers across the wire. + SendConversationReply(mCurNode.ThisNodeNum, replynum); + } + Close(); + return true; + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + int sel = -1; + int fh = OptionMenuSettings.mLinespacing; + + // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture + x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160; + y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100; + + if (x >= 24 && x <= 320-24 && y >= mYpos && y < mYpos + fh * mResponseLines.Size()) + { + sel = (y - mYpos) / fh; + for(int i = 0; i < mResponses.Size(); i++) + { + if (mResponses[i] > sel) + { + sel = i-1; + break; + } + } + } + if (sel != -1 && sel != mSelection) + { + //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); + } + mSelection = sel; + if (type == MOUSE_Release) + { + return MenuEvent(MKEY_Enter, true); + } + return true; + } + + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder(InputEventData ev) + { + if (demoplayback) + { // No interaction during demo playback + return false; + } + if (ev.type == InputEventData.GUI_Event && ev.subtype == InputEventData.GUI_Char && ev.data1 >= 48 && ev.data1 <= 57) + { // Activate an item of type numberedmore (dialogue only) + mSelection = ev.data1 == 48 ? 9 : ev.data1 - 49; + return MenuEvent(MKEY_Enter, false); + } + return Super.Responder(ev); + } + //============================================================================ // // Draw the backdrop, returns true if the text background should be dimmed diff --git a/wadsrc/static/zscript/menu/listmenu.txt b/wadsrc/static/zscript/menu/listmenu.txt index db1a4a19c1..5821d03234 100644 --- a/wadsrc/static/zscript/menu/listmenu.txt +++ b/wadsrc/static/zscript/menu/listmenu.txt @@ -47,7 +47,7 @@ class ListMenu : Menu virtual void Init(Menu parent = NULL, ListMenuDescriptor desc = NULL) { - mParentMenu = parent; + Super.Init(parent); mDesc = desc; if (desc.mCenter) { diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 2f5d9454a0..7d0c030dfd 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -89,6 +89,7 @@ class Menu : Object native native Menu mParentMenu; native bool mMouseCapture; native bool mBackbuttonSelected; + native bool DontDim; void Init(Menu parent) { diff --git a/wadsrc/static/zscript/menu/optionmenu.txt b/wadsrc/static/zscript/menu/optionmenu.txt index c6f0247a76..ed6189335c 100644 --- a/wadsrc/static/zscript/menu/optionmenu.txt +++ b/wadsrc/static/zscript/menu/optionmenu.txt @@ -104,6 +104,7 @@ class OptionMenu : Menu { mParentMenu = parent; mDesc = desc; + DontDim = desc.mDontDim; if (mDesc != NULL && mDesc.mSelectedItem == -1) mDesc.mSelectedItem = FirstSelectable(); mDesc.CalcIndent(); } From e05242e44dc8119dbb839b0688edd324c4f95c78 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 14:21:49 +0100 Subject: [PATCH 053/207] - scriptified the remaining parts of the conversationmenu. - do not resolve the backdrop texture to a texture ID at load time. This will allow custom menu classes to use this info differently. - added a new ZSDF userstring property to dialog pages to give mods more means for customization. - allow overriding the conversation menu class both globally through MAPINFO and per conversation in ZSDF. --- specs/usdf_zdoom.txt | 6 +- src/gi.cpp | 1 + src/gi.h | 1 + src/namedef.h | 1 + src/p_conversation.cpp | 190 ++---------------- src/p_conversation.h | 4 +- src/p_usdf.cpp | 18 +- src/scripting/thingdef_data.cpp | 8 + wadsrc/static/zscript/base.txt | 1 + .../static/zscript/menu/conversationmenu.txt | 158 +++++++++++++-- 10 files changed, 197 insertions(+), 191 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index f800b5ae79..cd4393351d 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -38,6 +38,7 @@ conversation page { drop = ; + userstring = ; New field which can be used to pass data to custom conversation menu classes. ifitem { item = ; @@ -63,10 +64,6 @@ either refuse loading dialogues with the 'ZDoom' namespace or if it does not outright abort on incompatible namespaces fail with a type mismatch error on one of the specified propeties. -In addition ZDoom defines one new field in the top level of a conversation block: - -id = ; Assigns a conversation ID for use in Thing_SetConversation or in UDMF's 'conversation' actor property. - ZDoom-format dialogues need to start with the line: namespace = "ZDoom"; @@ -86,6 +83,7 @@ conversation // Starts a dialog. // the standard conversation ID ('actor' property) is used instead // for this purpose but since 'ZDoom' namespace requires the actor // to be a class name it needs a separate field for this. + class = ; //Override the default conversation menu class for this conversation. page { diff --git a/src/gi.cpp b/src/gi.cpp index 247036ea7a..c497bf176a 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -362,6 +362,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_INT(TextScreenX, "textscreenx") GAMEINFOKEY_INT(TextScreenY, "textscreeny") GAMEINFOKEY_STRING(DefaultEndSequence, "defaultendsequence") + GAMEINFOKEY_STRING(DefaultConversationMenuClass, "defaultconversationmenuclass") GAMEINFOKEY_FONT(mStatscreenMapNameFont, "statscreen_mapnamefont") GAMEINFOKEY_FONT(mStatscreenFinishedFont, "statscreen_finishedfont") GAMEINFOKEY_FONT(mStatscreenEnteringFont, "statscreen_enteringfont") diff --git a/src/gi.h b/src/gi.h index 1bab4e9a7a..24053b0029 100644 --- a/src/gi.h +++ b/src/gi.h @@ -172,6 +172,7 @@ struct gameinfo_t double gibfactor; int TextScreenX; int TextScreenY; + FName DefaultConversationMenuClass; FName DefaultEndSequence; FString mMapArrow, mCheatMapArrow; FString mEasyKey, mCheatKey; diff --git a/src/namedef.h b/src/namedef.h index ebd9f3e8ee..efc70273fb 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -653,6 +653,7 @@ xx(Link) xx(Goodbye) xx(Require) xx(Exclude) +xx(Userstring) // Special menus xx(Mainmenu) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 10562428b5..449f9e286f 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -61,6 +61,7 @@ #include "p_local.h" #include "menu/menu.h" #include "g_levellocals.h" +#include "virtual.h" // The conversations as they exist inside a SCRIPTxx lump. struct Response @@ -124,9 +125,6 @@ static void TerminalResponse (const char *str); static FStrifeDialogueNode *PrevNode; -#define NUM_RANDOM_LINES 10 -#define NUM_RANDOM_GOODBYES 3 - //============================================================================ // // GetStrifeType @@ -351,7 +349,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker // The speaker's portrait, if any. speech.Dialogue[0] = 0; //speech.Backdrop[8] = 0; - node->Backdrop = TexMan.CheckForTexture (speech.Backdrop, FTexture::TEX_MiscPatch); + node->Backdrop = speech.Backdrop; // The speaker's voice for this node, if any. speech.Backdrop[0] = 0; //speech.Sound[8] = 0; @@ -425,7 +423,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker node->Dialogue = speech.Dialogue; // The Teaser version doesn't have portraits. - node->Backdrop.SetInvalid(); + node->Backdrop = ""; // The speaker's voice for this node, if any. if (speech.VoiceNumber != 0) @@ -743,153 +741,6 @@ public: } }; -//============================================================================ -// -// The conversation menu -// -//============================================================================ - -class DConversationMenu : public DMenu -{ - DECLARE_CLASS(DConversationMenu, DMenu) - -public: - FString mSpeaker; - DBrokenLines *mDialogueLines; - TArray mResponseLines; - TArray mResponses; - bool mShowGold; - FStrifeDialogueNode *mCurNode; - int mYpos; - player_t *mPlayer; - int mSelection; - - //============================================================================= - // - // - // - //============================================================================= - - DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player, int activereply) - { - mCurNode = CurNode; - mPlayer = player; - mDialogueLines = NULL; - mShowGold = false; - - // Format the speaker's message. - const char * toSay = CurNode->Dialogue; - if (strncmp (toSay, "RANDOM_", 7) == 0) - { - FString dlgtext; - - dlgtext.Format("TXT_%s_%02d", toSay, 1+(pr_randomspeech() % NUM_RANDOM_LINES)); - toSay = GStrings[dlgtext]; - if (toSay == NULL) - { - toSay = GStrings["TXT_GOAWAY"]; // Ok, it's lame - but it doesn't look like an error to the player. ;) - } - } - else - { - // handle string table replacement - if (toSay[0] == '$') - { - toSay = GStrings(toSay + 1); - } - } - if (toSay == NULL) - { - toSay = "."; - } - unsigned int count; - auto bl = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay, true, &count); - mDialogueLines = new DBrokenLines(bl, count); - - mSelection = -1; - - FStrifeDialogueReply *reply; - int r = -1; - int i,j; - for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next) - { - r++; - if (ShouldSkipReply(reply, mPlayer)) - { - continue; - } - if (activereply == r) mSelection = i - 1; - - mShowGold |= reply->NeedsGold; - - const char *ReplyText = reply->Reply; - if (ReplyText[0] == '$') - { - ReplyText = GStrings(ReplyText + 1); - } - FString ReplyString = ReplyText; - if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->PrintAmount); - - FBrokenLines *ReplyLines = V_BreakLines (SmallFont, 320-50-10, ReplyString); - - mResponses.Push(mResponseLines.Size()); - for (j = 0; ReplyLines[j].Width >= 0; ++j) - { - mResponseLines.Push(ReplyLines[j].Text); - } - - ++i; - V_FreeBrokenLines (ReplyLines); - } - if (mSelection == -1) - { - mSelection = r < activereply ? r + 1 : 0; - } - const char *goodbyestr = CurNode->Goodbye; - if (*goodbyestr == 0) - { - char goodbye[25]; - mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1 + (pr_randomspeech() % NUM_RANDOM_GOODBYES)); - goodbyestr = GStrings[goodbye]; - } - else if (strncmp(goodbyestr, "RANDOM_", 7) == 0) - { - FString byetext; - - byetext.Format("TXT_%s_%02d", goodbyestr, 1 + (pr_randomspeech() % NUM_RANDOM_LINES)); - goodbyestr = GStrings[byetext]; - } - else if (goodbyestr[0] == '$') - { - goodbyestr = GStrings(goodbyestr + 1); - } - if (goodbyestr == nullptr) goodbyestr = "Bye."; - mResponses.Push(mResponseLines.Size()); - mResponseLines.Push(FString(goodbyestr)); - - // Determine where the top of the reply list should be positioned. - mYpos = MIN (140, 192 - mResponseLines.Size() * OptionSettings.mLinespacing); - i = 44 + count * (OptionSettings.mLinespacing + 2); - if (mYpos - 100 < i - screen->GetHeight() / CleanYfac / 2) - { - mYpos = i - screen->GetHeight() / CleanYfac / 2 + 100; - } - ConversationMenuY = mYpos; - //ConversationMenu.indent = 50; - - // Because replies can be selectively hidden mResponses.Size() won't be consistent. - // So make sure mSelection doesn't exceed mResponses.Size(). [FishyClockwork] - if (mSelection >= (int)mResponses.Size()) - { - mSelection = mResponses.Size() - 1; - } - } - -}; - -IMPLEMENT_CLASS(DConversationMenu, true, false) - - //============================================================================ // // P_FreeStrifeConversations @@ -909,7 +760,7 @@ void P_FreeStrifeConversations () ClassRoots.Clear(); PrevNode = NULL; - if (CurrentMenu != NULL && CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu))) + if (CurrentMenu != NULL && CurrentMenu->IsKindOf("ConversationMenu")) { CurrentMenu->Close(); } @@ -1007,8 +858,21 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM); } - DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player, StaticLastReply); + // Create the menu. This may be a user-defined class so check if it is good to use. + FName cls = CurNode->MenuClassName; + if (cls == NAME_None) cls = gameinfo.DefaultConversationMenuClass; + if (cls == NAME_None) cls = "ConversationMenu"; + auto mcls = PClass::FindClass(cls); + if (mcls == nullptr || !mcls->IsDescendantOf("ConversationMenu")) mcls = PClass::FindClass("ConversationMenu"); + assert(mcls); + auto cmenu = mcls->CreateNew(); + IFVIRTUALPTRNAME(cmenu, "ConversationMenu", Init) + { + VMValue params[] = { cmenu, CurNode, pc->player, StaticLastReply }; + VMReturn ret(&ConversationMenuY); + GlobalVMStack.Call(func, params, countof(params), &ret, 1); + } if (CurNode != PrevNode) { // Only reset the selection if showing a different menu. @@ -1018,7 +882,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang // And open the menu M_StartControlPanel (false); - M_ActivateMenu(cmenu); + M_ActivateMenu((DMenu*)cmenu); menuactive = MENU_OnNoPause; } } @@ -1255,8 +1119,7 @@ void P_ConversationCommand (int netcode, int pnum, BYTE **stream) // The conversation menus are normally closed by the menu code, but that // doesn't happen during demo playback, so we need to do it here. - if (demoplayback && CurrentMenu != NULL && - CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu))) + if (demoplayback && CurrentMenu != NULL && CurrentMenu->IsKindOf("ConversationMenu")) { CurrentMenu->Close(); } @@ -1332,6 +1195,8 @@ DEFINE_FIELD(FStrifeDialogueNode, Backdrop); DEFINE_FIELD(FStrifeDialogueNode, Dialogue); DEFINE_FIELD(FStrifeDialogueNode, Goodbye); DEFINE_FIELD(FStrifeDialogueNode, Children); +DEFINE_FIELD(FStrifeDialogueNode, MenuClassName); +DEFINE_FIELD(FStrifeDialogueNode, UserData); DEFINE_FIELD(FStrifeDialogueReply, Next); DEFINE_FIELD(FStrifeDialogueReply, GiveType); @@ -1345,14 +1210,3 @@ DEFINE_FIELD(FStrifeDialogueReply, LogString); DEFINE_FIELD(FStrifeDialogueReply, NextNode); DEFINE_FIELD(FStrifeDialogueReply, LogNumber); DEFINE_FIELD(FStrifeDialogueReply, NeedsGold); - - -DEFINE_FIELD(DConversationMenu, mSpeaker); -DEFINE_FIELD(DConversationMenu, mDialogueLines); -DEFINE_FIELD(DConversationMenu, mResponseLines); -DEFINE_FIELD(DConversationMenu, mResponses); -DEFINE_FIELD(DConversationMenu, mShowGold); -DEFINE_FIELD(DConversationMenu, mCurNode); -DEFINE_FIELD(DConversationMenu, mYpos); -DEFINE_FIELD(DConversationMenu, mPlayer); -DEFINE_FIELD(DConversationMenu, mSelection); diff --git a/src/p_conversation.h b/src/p_conversation.h index c10c4c6972..302203bd2a 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -28,11 +28,13 @@ struct FStrifeDialogueNode PClassActor *SpeakerType; FString SpeakerName; FSoundID SpeakerVoice; - FTextureID Backdrop; + FString Backdrop; FString Dialogue; FString Goodbye; // must init to null for binary scripts to work as intended FStrifeDialogueReply *Children; + FName MenuClassName; + FString UserData; }; // FStrifeDialogueReply holds responses the player can give to the NPC diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index b8e290deb4..d2a1bb25e5 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -316,7 +316,14 @@ class USDFParser : public UDMFParserBase break; case NAME_Panel: - node->Backdrop = TexMan.CheckForTexture (CheckString(key), FTexture::TEX_MiscPatch); + node->Backdrop = CheckString(key); + break; + + case NAME_Userstring: + if (namespace_bits == Zd) + { + node->UserData = CheckString(key); + } break; case NAME_Voice: @@ -391,6 +398,7 @@ class USDFParser : public UDMFParserBase { PClassActor *type = NULL; int dlgid = -1; + FName clsid; unsigned int startpos = StrifeDialogues.Size(); while (!sc.CheckToken('}')) @@ -415,6 +423,13 @@ class USDFParser : public UDMFParserBase dlgid = CheckInt(key); } break; + + case NAME_Class: + if (namespace_bits == Zd) + { + clsid = CheckString(key); + } + break; } } else @@ -440,6 +455,7 @@ class USDFParser : public UDMFParserBase for(;startpos < StrifeDialogues.Size(); startpos++) { StrifeDialogues[startpos]->SpeakerType = type; + StrifeDialogues[startpos]->MenuClassName = clsid; } return true; } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index b527832fd8..1abd0bc4c8 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1219,6 +1219,14 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid) ACTION_RETURN_STRING(s); } +DEFINE_ACTION_FUNCTION(FStringStruct, Left) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_UINT(len); + FString s = self->Left(len); + ACTION_RETURN_STRING(s); +} + DEFINE_ACTION_FUNCTION(FStringStruct, Truncate) { PARAM_SELF_STRUCT_PROLOGUE(FString); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b2eff2601f..500fe3abcc 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -580,6 +580,7 @@ struct StringStruct native native vararg void AppendFormat(String fmt, ...); native void Replace(String pattern, String replacement); + native String Left(int len); native String Mid(int pos = 0, int len = 2147483647); native void Truncate(int newlen); native String CharAt(int pos); diff --git a/wadsrc/static/zscript/menu/conversationmenu.txt b/wadsrc/static/zscript/menu/conversationmenu.txt index efe843c513..dba162ad7c 100644 --- a/wadsrc/static/zscript/menu/conversationmenu.txt +++ b/wadsrc/static/zscript/menu/conversationmenu.txt @@ -41,7 +41,7 @@ struct StrifeDialogueNode native native Class SpeakerType; native String SpeakerName; native Sound SpeakerVoice; - native TextureID Backdrop; + native String Backdrop; native String Dialogue; native String Goodbye; @@ -68,23 +68,147 @@ struct StrifeDialogueReply native } -class ConversationMenu : Menu native +class ConversationMenu : Menu { - native String mSpeaker; - native BrokenLines mDialogueLines; - native Array mResponseLines; - native Array mResponses; - native bool mShowGold; - native StrifeDialogueNode mCurNode; - native int mYpos; - native PlayerInfo mPlayer; - native int mSelection; + String mSpeaker; + BrokenLines mDialogueLines; + Array mResponseLines; + Array mResponses; + bool mShowGold; + StrifeDialogueNode mCurNode; + int mYpos; + PlayerInfo mPlayer; + int mSelection; + int ConversationPauseTic; + + int SpeechWidth; + int ReplyWidth; native static void SendConversationReply(int node, int reply); - //ConversationPauseTic = gametic + 20; - // DontDim = true; + const NUM_RANDOM_LINES = 10; + const NUM_RANDOM_GOODBYES = 3; + //============================================================================= + // + // returns the y position of the replies boy for positioning the terminal response. + // + //============================================================================= + + virtual int Init(StrifeDialogueNode CurNode, PlayerInfo player, int activereply) + { + mCurNode = CurNode; + mPlayer = player; + mShowGold = false; + ConversationPauseTic = gametic + 20; + DontDim = true; + + ReplyWidth = 320-50-10; + SpeechWidth = screen.GetWidth()/CleanXfac - 24*2; + + FormatSpeakerMessage(); + return FormatReplies(activereply); + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual int FormatReplies(int activereply) + { + mSelection = -1; + + StrifeDialogueReply reply; + int r = -1; + int i = 1,j; + for (reply = mCurNode.Children; reply != NULL; reply = reply.Next) + { + r++; + if (reply.ShouldSkipReply(mPlayer)) + { + continue; + } + if (activereply == r) mSelection = i - 1; + + mShowGold |= reply.NeedsGold; + + let ReplyText = Stringtable.Localize(reply.Reply); + if (reply.NeedsGold) ReplyText.AppendFormat(" for %u", reply.PrintAmount); + + let ReplyLines = SmallFont.BreakLines (ReplyText, ReplyWidth); + + mResponses.Push(mResponseLines.Size()); + for (j = 0; j < ReplyLines.Count(); ++j) + { + mResponseLines.Push(ReplyLines.StringAt(j)); + } + + ++i; + ReplyLines.Destroy(); + } + if (mSelection == -1) + { + mSelection = r < activereply ? r + 1 : 0; + } + let goodbyestr = mCurNode.Goodbye; + if (goodbyestr.Length() == 0) + { + goodbyestr = String.Format("$TXT_RANDOMGOODBYE_%d", Random[RandomSpeech](1, NUM_RANDOM_GOODBYES)); + } + else if (goodbyestr.Left(7) == "RANDOM_") + { + goodbyestr = String.Format("$TXT_%s_%02d", goodbyestr, Random[RandomSpeech](1, NUM_RANDOM_LINES)); + } + goodbyestr = Stringtable.Localize(goodbyestr); + if (goodbyestr.Length() == 0 || goodbyestr.CharAt(0) == "$") goodbyestr = "Bye."; + mResponses.Push(mResponseLines.Size()); + mResponseLines.Push(goodbyestr); + + // Determine where the top of the reply list should be positioned. + mYpos = MIN (140, 192 - mResponseLines.Size() * OptionMenuSettings.mLinespacing); + i = 44 + mResponseLines.Size() * OptionMenuSettings.mLinespacing; + if (mYpos - 100 < i - screen.GetHeight() / CleanYfac / 2) + { + mYpos = i - screen.GetHeight() / CleanYfac / 2 + 100; + } + + if (mSelection >= mResponses.Size()) + { + mSelection = mResponses.Size() - 1; + } + return mYpos; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual void FormatSpeakerMessage() + { + // Format the speaker's message. + String toSay = mCurNode.Dialogue; + if (toSay.Left(7) == "RANDOM_") + { + let dlgtext = String.Format("$TXT_%s_%02d", toSay, random[RandomSpeech](1, NUM_RANDOM_LINES)); + toSay = Stringtable.Localize(dlgtext); + if (toSay.CharAt(0) == "$") toSay = Stringtable.Localize("$TXT_GOAWAY"); + } + else + { + // handle string table replacement + toSay = Stringtable.Localize(toSay); + } + if (toSay.Length() == 0) + { + toSay = "."; + } + mDialogueLines = SmallFont.BreakLines(toSay, SpeechWidth); + } + //============================================================================= // // @@ -233,9 +357,10 @@ class ConversationMenu : Menu native virtual bool DrawBackdrop() { - if (mCurNode.Backdrop.isValid()) + let tex = TexMan.CheckForTexture (mCurNode.Backdrop, TexMan.Type_MiscPatch); + if (tex.isValid()) { - screen.DrawTexture(mCurNode.Backdrop, false, 0, 0, DTA_320x200, true); + screen.DrawTexture(tex, false, 0, 0, DTA_320x200, true); return false; } return true; @@ -381,9 +506,8 @@ class ConversationMenu : Menu native override void Ticker() { - // will be reactivated later. // [CW] Freeze the game depending on MAPINFO options. - //if (ConversationPauseTic < gametic && !multiplayer && !level.no_dlg_freeze) + if (ConversationPauseTic < gametic && !multiplayer && !level.no_dlg_freeze) { menuactive = Menu.On; } From 9089beb110fd834e5b8d216d5ec93a3c84cc9631 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 15:23:33 +0100 Subject: [PATCH 054/207] - scriptified most of the remaining parts of DMenu. Only the engine interface remains native now. --- src/gi.cpp | 1 + src/menu/menu.cpp | 236 ++++------------------------ src/menu/menu.h | 23 --- src/scripting/thingdef_data.cpp | 8 + wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/menu/menu.txt | 185 ++++++++++++++++++++-- 6 files changed, 211 insertions(+), 243 deletions(-) diff --git a/src/gi.cpp b/src/gi.cpp index c497bf176a..18fd39f69b 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -52,6 +52,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, infoPages) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton) const char *GameNames[17] = diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index b0bf096f88..c64b057117 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -164,53 +164,11 @@ DMenu::DMenu(DMenu *parent) GC::WriteBarrier(this, parent); } -bool DMenu::Responder (event_t *ev) -{ - bool res = false; - if (ev->type == EV_GUI_Event) - { - if (ev->subtype == EV_GUI_LButtonDown) - { - res = MouseEventBack(MOUSE_Click, ev->data1, ev->data2); - // make the menu's mouse handler believe that the current coordinate is outside the valid range - if (res) ev->data2 = -1; - res |= CallMouseEvent(MOUSE_Click, ev->data1, ev->data2); - if (res) - { - SetCapture(); - } - - } - else if (ev->subtype == EV_GUI_MouseMove) - { - BackbuttonTime = BACKBUTTON_TIME; - if (mMouseCapture || m_use_mouse == 1) - { - res = MouseEventBack(MOUSE_Move, ev->data1, ev->data2); - if (res) ev->data2 = -1; - res |= CallMouseEvent(MOUSE_Move, ev->data1, ev->data2); - } - } - else if (ev->subtype == EV_GUI_LButtonUp) - { - if (mMouseCapture) - { - ReleaseCapture(); - res = MouseEventBack(MOUSE_Release, ev->data1, ev->data2); - if (res) ev->data2 = -1; - res |= CallMouseEvent(MOUSE_Release, ev->data1, ev->data2); - } - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(DMenu, Responder) -{ - PARAM_SELF_PROLOGUE(DMenu); - PARAM_POINTER(ev, event_t); - ACTION_RETURN_BOOL(self->Responder(ev)); -} +//============================================================================= +// +// +// +//============================================================================= bool DMenu::CallResponder(event_t *ev) { @@ -222,7 +180,7 @@ bool DMenu::CallResponder(event_t *ev) GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return !!retval; } - else return Responder(ev); + else return false; } //============================================================================= @@ -231,29 +189,6 @@ bool DMenu::CallResponder(event_t *ev) // //============================================================================= -bool DMenu::MenuEvent (int mkey, bool fromcontroller) -{ - switch (mkey) - { - case MKEY_Back: - { - Close(); - S_Sound (CHAN_VOICE | CHAN_UI, - CurrentMenu != nullptr? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE); - return true; - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(DMenu, MenuEvent) -{ - PARAM_SELF_PROLOGUE(DMenu); - PARAM_INT(key); - PARAM_BOOL(fromcontroller); - ACTION_RETURN_BOOL(self->MenuEvent(key, fromcontroller)); -} - bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) { IFVIRTUAL(DMenu, MenuEvent) @@ -264,7 +199,7 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); return !!retval; } - else return MenuEvent(mkey, fromcontroller); + else return false; } //============================================================================= // @@ -272,6 +207,15 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) // //============================================================================= +DEFINE_ACTION_FUNCTION(DMenu, SetMouseCapture) +{ + PARAM_PROLOGUE; + PARAM_BOOL(on); + if (on) I_SetMouseCapture(); + else I_ReleaseMouseCapture(); + return 0; +} + void DMenu::Close () { if (CurrentMenu == nullptr) return; // double closing can happen in the save menu. @@ -288,108 +232,19 @@ void DMenu::Close () } } -//============================================================================= -// -// -// -//============================================================================= - -bool DMenu::MouseEvent(int type, int x, int y) -{ - return true; -} - -DEFINE_ACTION_FUNCTION(DMenu, MouseEvent) +DEFINE_ACTION_FUNCTION(DMenu, Close) { PARAM_SELF_PROLOGUE(DMenu); - PARAM_INT(type); - PARAM_INT(x); - PARAM_INT(y); - ACTION_RETURN_BOOL(self->MouseEvent(type, x, y)); -} - -bool DMenu::CallMouseEvent(int type, int x, int y) -{ - IFVIRTUAL(DMenu, MouseEvent) - { - VMValue params[] = { (DObject*)this, type, x, y }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 4, &ret, 1, nullptr); - return !!retval; - } - else return MouseEvent (type, x, y); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DMenu::MouseEventBack(int type, int x, int y) -{ - if (m_show_backbutton >= 0) - { - FTexture *tex = TexMan(gameinfo.mBackButton); - if (tex != nullptr) - { - if (m_show_backbutton&1) x -= screen->GetWidth() - tex->GetScaledWidth() * CleanXfac; - if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetScaledHeight() * CleanYfac; - mBackbuttonSelected = ( x >= 0 && x < tex->GetScaledWidth() * CleanXfac && - y >= 0 && y < tex->GetScaledHeight() * CleanYfac); - if (mBackbuttonSelected && type == MOUSE_Release) - { - if (m_use_mouse == 2) mBackbuttonSelected = false; - CallMenuEvent(MKEY_Back, true); - } - return mBackbuttonSelected; - } - } - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMenu::SetCapture() -{ - if (!mMouseCapture) - { - mMouseCapture = true; - I_SetMouseCapture(); - } -} - -void DMenu::ReleaseCapture() -{ - if (mMouseCapture) - { - mMouseCapture = false; - I_ReleaseMouseCapture(); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMenu::Ticker () -{ -} - -DEFINE_ACTION_FUNCTION(DMenu, Ticker) -{ - PARAM_SELF_PROLOGUE(DMenu); - self->Ticker(); + self->Close(); return 0; } +//============================================================================= +// +// +// +//============================================================================= + void DMenu::CallTicker() { IFVIRTUAL(DMenu, Ticker) @@ -397,38 +252,9 @@ void DMenu::CallTicker() VMValue params[] = { (DObject*)this }; GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } - else Ticker(); } -void DMenu::Drawer () -{ - if (this == CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) - { - FTexture *tex = TexMan(gameinfo.mBackButton); - int w = tex->GetScaledWidth() * CleanXfac; - int h = tex->GetScaledHeight() * CleanYfac; - int x = (!(m_show_backbutton&1))? 0:screen->GetWidth() - w; - int y = (!(m_show_backbutton&2))? 0:screen->GetHeight() - h; - if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1)) - { - screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, MAKEARGB(40, 255,255,255), TAG_DONE); - } - else - { - screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha, TAG_DONE); - } - } -} - - -DEFINE_ACTION_FUNCTION(DMenu, Drawer) -{ - PARAM_SELF_PROLOGUE(DMenu); - self->Drawer(); - return 0; -} - void DMenu::CallDrawer() { IFVIRTUAL(DMenu, Drawer) @@ -436,14 +262,6 @@ void DMenu::CallDrawer() VMValue params[] = { (DObject*)this }; GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } - else Drawer(); -} - -DEFINE_ACTION_FUNCTION(DMenu, Close) -{ - PARAM_SELF_PROLOGUE(DMenu); - self->Close(); - return 0; } bool DMenu::TranslateKeyboardEvents() @@ -500,7 +318,11 @@ void M_StartControlPanel (bool makeSound) void M_ActivateMenu(DMenu *menu) { if (menuactive == MENU_Off) menuactive = MENU_On; - if (CurrentMenu != nullptr) CurrentMenu->ReleaseCapture(); + if (CurrentMenu != nullptr && CurrentMenu->mMouseCapture) + { + CurrentMenu->mMouseCapture = false; + I_ReleaseMouseCapture(); + } CurrentMenu = menu; GC::WriteBarrier(CurrentMenu); } diff --git a/src/menu/menu.h b/src/menu/menu.h index 7d1236ccf9..1b4b22255d 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -263,42 +263,19 @@ public: MOUSE_Release }; - enum - { - BACKBUTTON_TIME = 4*TICRATE - }; - TObjPtr mParentMenu; bool mMouseCapture; bool mBackbuttonSelected; bool DontDim; DMenu(DMenu *parent = NULL); - virtual bool Responder (event_t *ev); - virtual bool MenuEvent (int mkey, bool fromcontroller); - virtual void Ticker (); - virtual void Drawer (); bool TranslateKeyboardEvents(); virtual void Close(); - virtual bool MouseEvent(int type, int x, int y); - - virtual void SetFocus(DMenuItemBase *fc) {} - virtual bool CheckFocus(DMenuItemBase *fc) { return false; } - virtual void ReleaseFocus() {} bool CallResponder(event_t *ev); bool CallMenuEvent(int mkey, bool fromcontroller); - bool CallMouseEvent(int type, int x, int y); void CallTicker(); void CallDrawer(); - - bool MouseEventBack(int type, int x, int y); - void SetCapture(); - void ReleaseCapture(); - bool HasCapture() - { - return mMouseCapture; - } }; //============================================================================= diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 1abd0bc4c8..0f5647005f 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -63,6 +63,8 @@ static TArray properties; static TArray AFTable; static TArray FieldTable; +extern int BackbuttonTime; +extern float BackbuttonAlpha; //========================================================================== // @@ -912,6 +914,12 @@ void InitThingdef() fieldptr = new PField("demoplayback", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&demoplayback); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + fieldptr = new PField("BackbuttonTime", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&BackbuttonTime); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + + fieldptr = new PField("BackbuttonAlpha", TypeFloat32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&BackbuttonAlpha); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 500fe3abcc..e9a89b0abc 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -300,6 +300,7 @@ struct GameInfoStruct native native int gametype; native bool norandomplayerclass; native Array infoPages; + native String mBackButton; } class Object native diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 7d0c030dfd..dda75a739f 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -91,31 +91,190 @@ class Menu : Object native native bool mBackbuttonSelected; native bool DontDim; - void Init(Menu parent) - { - mParentMenu = parent; - } - native static int MenuTime(); native static void SetVideoMode(); native static Menu GetCurrentMenu(); native static void SetMenu(Name mnu, int param = 0); native static void StartMessage(String msg, int mode = 0, Name command = 'none'); + native static void SetMouseCapture(bool on); + native void Close(); + native void ActivateMenu(); + //============================================================================= + // + // + // + //============================================================================= + + void Init(Menu parent) + { + mParentMenu = parent; + mMouseCapture = false; + mBackbuttonSelected = false; + DontDim = false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual bool MenuEvent (int mkey, bool fromcontroller) + { + switch (mkey) + { + case MKEY_Back: + Close(); + MenuSound (GetCurrentMenu() != null? "menu/backup" : "menu/clear"); + return true; + } + return false; + } + + + //============================================================================= + // + // + // + //============================================================================= + + protected bool MouseEventBack(int type, int x, int y) + { + if (m_show_backbutton >= 0) + { + let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); + if (tex.IsValid()) + { + Vector2 v = TexMan.GetScaledSize(tex); + int w = int(v.X + 0.5) * CleanXfac; + int h = int(v.Y + 0.5) * CleanYfac; + if (m_show_backbutton&1) x -= screen.GetWidth() - w; + if (m_show_backbutton&2) y -= screen.GetHeight() - h; + mBackbuttonSelected = ( x >= 0 && x < w && y >= 0 && y < h); + if (mBackbuttonSelected && type == MOUSE_Release) + { + if (m_use_mouse == 2) mBackbuttonSelected = false; + MenuEvent(MKEY_Back, true); + } + return mBackbuttonSelected; + } + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual bool Responder(InputEventData ev) + { + bool res = false; + if (ev.type == InputEventData.GUI_Event) + { + if (ev.subtype == InputEventData.GUI_LButtonDown) + { + res = MouseEventBack(MOUSE_Click, ev.data1, ev.data2); + // make the menu's mouse handler believe that the current coordinate is outside the valid range + if (res) ev.data2 = -1; + res |= MouseEvent(MOUSE_Click, ev.data1, ev.data2); + if (res) + { + SetCapture(true); + } + + } + else if (ev.subtype == InputEventData.GUI_MouseMove) + { + BackbuttonTime = 4*Thinker.TICRATE; + if (mMouseCapture || m_use_mouse == 1) + { + res = MouseEventBack(MOUSE_Move, ev.data1, ev.data2); + if (res) ev.data2 = -1; + res |= MouseEvent(MOUSE_Move, ev.data1, ev.data2); + } + } + else if (ev.subtype == InputEventData.GUI_LButtonUp) + { + if (mMouseCapture) + { + SetCapture(false); + res = MouseEventBack(MOUSE_Release, ev.data1, ev.data2); + if (res) ev.data2 = -1; + res |= MouseEvent(MOUSE_Release, ev.data1, ev.data2); + } + } + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual void Drawer () + { + if (self == GetCurrentMenu() && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) + { + let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); + if (tex.IsValid()) + { + Vector2 v = TexMan.GetScaledSize(tex); + int w = int(v.X + 0.5) * CleanXfac; + int h = int(v.Y + 0.5) * CleanYfac; + int x = (!(m_show_backbutton&1))? 0:screen.GetWidth() - w; + int y = (!(m_show_backbutton&2))? 0:screen.GetHeight() - h; + if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1)) + { + screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, Color(40, 255,255,255)); + } + else + { + screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha); + } + } + } + } + + //============================================================================= + // + // + // + //============================================================================= + + void SetCapture(bool on) + { + if (mMouseCapture != on) + { + mMouseCapture = on; + SetMouseCapture(on); + } + } + + //============================================================================= + // + // + // + //============================================================================= + virtual bool TranslateKeyboardEvents() { return true; } virtual void SetFocus(MenuItemBase fc) {} virtual bool CheckFocus(MenuItemBase fc) { return false; } virtual void ReleaseFocus() {} virtual void ResetColor() {} + virtual bool MouseEvent(int type, int mx, int my) { return false; } + virtual void Ticker() {} + + //============================================================================= + // + // + // + //============================================================================= - native virtual bool Responder(InputEventData ev); - native virtual bool MenuEvent (int mkey, bool fromcontroller); - native virtual bool MouseEvent(int type, int mx, int my); - native virtual void Ticker(); - native virtual void Drawer(); - native void Close(); - native void ActivateMenu(); - static void MenuSound(Sound snd) { S_Sound (snd, CHAN_VOICE | CHAN_UI, snd_menuvolume, ATTN_NONE); From fb52b034b0242b393cef3d5c4f44c1221a2865ba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 15:35:28 +0100 Subject: [PATCH 055/207] - added a GenericMenu class, so that all menus can be given a virtual Init method. Doing this to Menu itself would not work because the different menus require different parameters. This also means that all menus that are routed through menu items must inherit from either ListMenu, OptionMenu or GenericMenu. All other types can only be used internally. This should complete the menu scriptification. --- src/menu/menu.cpp | 9 +++++++-- wadsrc/static/zscript/menu/menu.txt | 8 ++++++++ wadsrc/static/zscript/menu/readthis.txt | 15 ++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index c64b057117..b2ceffc7a3 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -469,10 +469,15 @@ void M_SetMenu(FName menu, int param) const PClass *menuclass = PClass::FindClass(menu); if (menuclass != nullptr) { - if (menuclass->IsDescendantOf(RUNTIME_CLASS(DMenu))) + if (menuclass->IsDescendantOf("GenericMenu")) { DMenu *newmenu = (DMenu*)menuclass->CreateNew(); - newmenu->mParentMenu = CurrentMenu; + + IFVIRTUALPTRNAME(newmenu, "GenericMenu", Init) + { + VMValue params[3] = { newmenu, CurrentMenu }; + GlobalVMStack.Call(func, params, 2, nullptr, 0); + } M_ActivateMenu(newmenu); return; } diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index dda75a739f..84478ba818 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -296,3 +296,11 @@ class MenuDescriptor : Object native native static MenuDescriptor GetDescriptor(Name n); } +// This class is only needed to give it a virtual Init method that doesn't belong to Menu itself +class GenericMenu : Menu +{ + virtual void Init(Menu parent) + { + Super.Init(parent); + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/menu/readthis.txt b/wadsrc/static/zscript/menu/readthis.txt index a3db8a8a7d..604fb489e0 100644 --- a/wadsrc/static/zscript/menu/readthis.txt +++ b/wadsrc/static/zscript/menu/readthis.txt @@ -33,7 +33,7 @@ ** */ -class ReadThisMenu : Menu +class ReadThisMenu : GenericMenu { int mScreen; int mInfoTic; @@ -43,18 +43,19 @@ class ReadThisMenu : Menu // // //============================================================================= + + override void Init(Menu parent) + { + Super.Init(parent); + mScreen = 1; + mInfoTic = gametic; + } override void Drawer() { double alpha; TextureID tex, prevpic; - if (mScreen == 0) - { - mScreen = 1; - mInfoTic = gametic; - } - // Did the mapper choose a custom help page via MAPINFO? if (level.F1Pic.Length() != 0) { From c0f588e234bd6516103a0c8ab79d8ad0622bdc59 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 16:08:10 +0100 Subject: [PATCH 056/207] - let M_ClearMenus destroy all open menus so that they can properly deinitialize. --- src/menu/menu.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index b2ceffc7a3..9a88605108 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -766,13 +766,14 @@ void M_Drawer (void) // //============================================================================= -void M_ClearMenus () +void M_ClearMenus() { M_DemoNoPlay = false; - if (CurrentMenu != nullptr) + while (CurrentMenu != nullptr) { + DMenu* parent = CurrentMenu->mParentMenu; CurrentMenu->Destroy(); - CurrentMenu = nullptr; + CurrentMenu = parent; } V_SetBorderNeedRefresh(); menuactive = MENU_Off; From f3b6343e53f3cc846f12af182572abd3413db665 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 17:24:30 +0100 Subject: [PATCH 057/207] - use floats for menu item coordinates. This only has an effect in the ListMenu because the OptionMenu uses fixed offsets which work differently. --- src/menu/menu.cpp | 4 +-- src/menu/menu.h | 14 ++++---- src/menu/menudef.cpp | 32 +++++++++---------- wadsrc/static/zscript/menu/listmenu.txt | 14 ++++---- wadsrc/static/zscript/menu/listmenuitems.txt | 30 ++++++++--------- wadsrc/static/zscript/menu/menuitembase.txt | 12 +++---- wadsrc/static/zscript/menu/playercontrols.txt | 24 +++++++------- wadsrc/static/zscript/menu/playerdisplay.txt | 4 +-- 8 files changed, 68 insertions(+), 66 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 9a88605108..fe5af62686 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -1117,7 +1117,7 @@ DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBi return (DMenuItemBase*)p; } -DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID tex, FName command, int param) +DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param) { auto c = PClass::FindClass("ListMenuItemPatchItem"); auto p = c->CreateNew(); @@ -1127,7 +1127,7 @@ DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FT return (DMenuItemBase*)p; } -DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param) +DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param) { auto c = PClass::FindClass("ListMenuItemTextItem"); auto p = c->CreateNew(); diff --git a/src/menu/menu.h b/src/menu/menu.h index 1b4b22255d..8922147e19 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -138,11 +138,11 @@ class DListMenuDescriptor : public DMenuDescriptor public: TArray mItems; int mSelectedItem; - int mSelectOfsX; - int mSelectOfsY; + double mSelectOfsX; + double mSelectOfsY; FTextureID mSelector; int mDisplayTop; - int mXpos, mYpos; + double mXpos, mYpos; int mWLeft, mWRight; int mLinespacing; // needs to be stored for dynamically created menus int mAutoselect; // this can only be set by internal menu creation functions @@ -288,7 +288,7 @@ class DMenuItemBase : public DObject { DECLARE_CLASS(DMenuItemBase, DObject) public: - int mXpos, mYpos; + double mXpos, mYpos; FNameNoInit mAction; bool mEnabled; @@ -298,7 +298,7 @@ public: bool SetValue(int i, int value); bool GetValue(int i, int *pvalue); void OffsetPositionY(int ydelta) { mYpos += ydelta; } - int GetY() { return mYpos; } + double GetY() { return mYpos; } }; //============================================================================= @@ -355,7 +355,7 @@ DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, bool v); DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center); DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings); DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy); -DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID tex, FName command, int param); -DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param); +DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param); +DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param); #endif diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index f9ecbd808e..cf986ee582 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -305,11 +305,11 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) sc.MustGetString(); desc->mSelector = GetMenuTexture(sc.String); sc.MustGetStringName(","); - sc.MustGetNumber(); - desc->mSelectOfsX = sc.Number; + sc.MustGetFloat(); + desc->mSelectOfsX = sc.Float; sc.MustGetStringName(","); - sc.MustGetNumber(); - desc->mSelectOfsY = sc.Number; + sc.MustGetFloat(); + desc->mSelectOfsY = sc.Float; } else if (sc.Compare("Linespacing")) { @@ -318,11 +318,11 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) } else if (sc.Compare("Position")) { - sc.MustGetNumber(); - desc->mXpos = sc.Number; + sc.MustGetFloat(); + desc->mXpos = sc.Float; sc.MustGetStringName(","); - sc.MustGetNumber(); - desc->mYpos = sc.Number; + sc.MustGetFloat(); + desc->mYpos = sc.Float; } else if (sc.Compare("Centermenu")) { @@ -973,13 +973,13 @@ static void BuildEpisodeMenu() if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) { DListMenuDescriptor *ld = static_cast(*desc); - int posy = ld->mYpos; + int posy = (int)ld->mYpos; int topy = posy; // Get lowest y coordinate of any static item in the menu for(unsigned i = 0; i < ld->mItems.Size(); i++) { - int y = ld->mItems[i]->GetY(); + int y = (int)ld->mItems[i]->GetY(); if (y < topy) topy = y; } @@ -1073,13 +1073,13 @@ static void BuildPlayerclassMenu() // add player display ld->mSelectedItem = ld->mItems.Size(); - int posy = ld->mYpos; + int posy = (int)ld->mYpos; int topy = posy; // Get lowest y coordinate of any static item in the menu for(unsigned i = 0; i < ld->mItems.Size(); i++) { - int y = ld->mItems[i]->GetY(); + int y = (int)ld->mItems[i]->GetY(); if (y < topy) topy = y; } @@ -1333,8 +1333,8 @@ void M_StartupSkillMenu(FGameStartup *gs) if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) { DListMenuDescriptor *ld = static_cast(*desc); - int x = ld->mXpos; - int y = ld->mYpos; + int x = (int)ld->mXpos; + int y = (int)ld->mYpos; // Delete previous contents for(unsigned i=0; imItems.Size(); i++) @@ -1363,7 +1363,7 @@ void M_StartupSkillMenu(FGameStartup *gs) // Get lowest y coordinate of any static item in the menu for(unsigned i = 0; i < ld->mItems.Size(); i++) { - int y = ld->mItems[i]->GetY(); + int y = (int)ld->mItems[i]->GetY(); if (y < topy) topy = y; } @@ -1380,7 +1380,7 @@ void M_StartupSkillMenu(FGameStartup *gs) { ld->mItems[i]->OffsetPositionY(topdelta); } - y = ld->mYpos = posy - topdelta; + ld->mYpos = y = posy - topdelta; } } else diff --git a/wadsrc/static/zscript/menu/listmenu.txt b/wadsrc/static/zscript/menu/listmenu.txt index 5821d03234..a7a9f71ae5 100644 --- a/wadsrc/static/zscript/menu/listmenu.txt +++ b/wadsrc/static/zscript/menu/listmenu.txt @@ -4,11 +4,11 @@ class ListMenuDescriptor : MenuDescriptor native { native Array mItems; native int mSelectedItem; - native int mSelectOfsX; - native int mSelectOfsY; + native double mSelectOfsX; + native double mSelectOfsY; native TextureID mSelector; native int mDisplayTop; - native int mXpos, mYpos; + native double mXpos, mYpos; native int mWLeft, mWRight; native int mLinespacing; // needs to be stored for dynamically created menus native int mAutoselect; // this can only be set by internal menu creation functions @@ -51,16 +51,16 @@ class ListMenu : Menu mDesc = desc; if (desc.mCenter) { - int center = 160; + double center = 160; for(int i=0; i < mDesc.mItems.Size(); i++) { - int xpos = mDesc.mItems[i].GetX(); + double xpos = mDesc.mItems[i].GetX(); int width = mDesc.mItems[i].GetWidth(); - int curx = mDesc.mSelectOfsX; + double curx = mDesc.mSelectOfsX; if (width > 0 && mDesc.mItems[i].Selectable()) { - int left = 160 - (width - curx) / 2 - curx; + double left = 160 - (width - curx) / 2 - curx; if (left < center) center = left; } } diff --git a/wadsrc/static/zscript/menu/listmenuitems.txt b/wadsrc/static/zscript/menu/listmenuitems.txt index e3eec6dd18..c1bafeaf94 100644 --- a/wadsrc/static/zscript/menu/listmenuitems.txt +++ b/wadsrc/static/zscript/menu/listmenuitems.txt @@ -35,7 +35,7 @@ class ListMenuItem : MenuItemBase { - void DrawSelector(int xofs, int yofs, TextureID tex) + void DrawSelector(double xofs, double yofs, TextureID tex) { if (tex.isNull()) { @@ -68,7 +68,7 @@ class ListMenuItemStaticPatch : ListMenuItem TextureID mTexture; bool mCentered; - void Init(int x, int y, TextureID patch, bool centered = false) + void Init(double x, double y, TextureID patch, bool centered = false) { Super.Init(x, y); mTexture = patch; @@ -82,17 +82,17 @@ class ListMenuItemStaticPatch : ListMenuItem return; } - int x = mXpos; + double x = mXpos; Vector2 vec = TexMan.GetScaledSize(mTexture); if (mYpos >= 0) { - if (mCentered) x -= int(vec.X) / 2; + if (mCentered) x -= vec.X / 2; screen.DrawTexture (mTexture, true, x, mYpos, DTA_Clean, true); } else { - int x = (mXpos - 160) * CleanXfac + (Screen.GetWidth()>>1); - if (mCentered) x -= (int(vec.X) * CleanXfac)/2; + x = (mXpos - 160) * CleanXfac + (Screen.GetWidth()>>1); + if (mCentered) x -= (vec.X * CleanXfac)/2; screen.DrawTexture (mTexture, true, x, -mYpos*CleanYfac, DTA_CleanNoMove, true); } } @@ -100,7 +100,7 @@ class ListMenuItemStaticPatch : ListMenuItem class ListMenuItemStaticPatchCentered : ListMenuItemStaticPatch { - void Init(int x, int y, TextureID patch) + void Init(double x, double y, TextureID patch) { Super.Init(x, y, patch, true); } @@ -119,7 +119,7 @@ class ListMenuItemStaticText : ListMenuItem int mColor; bool mCentered; - void Init(ListMenuDescriptor desc, int x, int y, String text, int color = Font.CR_UNTRANSLATED) + void Init(ListMenuDescriptor desc, double x, double y, String text, int color = Font.CR_UNTRANSLATED) { Super.Init(x, y); mText = text; @@ -128,7 +128,7 @@ class ListMenuItemStaticText : ListMenuItem mCentered = false; } - void InitDirect(int x, int y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false) + void InitDirect(double x, double y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false) { Super.Init(x, y); mText = text; @@ -144,13 +144,13 @@ class ListMenuItemStaticText : ListMenuItem String text = Stringtable.Localize(mText); if (mYpos >= 0) { - int x = mXpos; + double x = mXpos; if (mCentered) x -= mFont.StringWidth(text)/2; screen.DrawText(mFont, mColor, x, mYpos, text, DTA_Clean, true); } else { - int x = (mXpos - 160) * CleanXfac + (Screen.GetWidth() >> 1); + double x = (mXpos - 160) * CleanXfac + (Screen.GetWidth() >> 1); if (mCentered) x -= (mFont.StringWidth(text) * CleanXfac)/2; screen.DrawText (mFont, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true); } @@ -160,7 +160,7 @@ class ListMenuItemStaticText : ListMenuItem class ListMenuItemStaticTextCentered : ListMenuItemStaticText { - void Init(ListMenuDescriptor desc, int x, int y, String text, int color = -1) + void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1) { Super.Init(desc, x, y, text, color); mCentered = true; @@ -179,7 +179,7 @@ class ListMenuItemSelectable : ListMenuItem int mHeight; int mParam; - protected void Init(int x, int y, int height, Name childmenu, int param = -1) + protected void Init(double x, double y, int height, Name childmenu, int param = -1) { Super.Init(x, y, childmenu); mHeight = height; @@ -250,7 +250,7 @@ class ListMenuItemTextItem : ListMenuItemSelectable mHotkey = hotkey.CharCodeAt(0); } - void InitDirect(int x, int y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0) + void InitDirect(double x, double y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0) { Super.Init(x, y, height, child, param); mText = text; @@ -288,7 +288,7 @@ class ListMenuItemPatchItem : ListMenuItemSelectable mTexture = patch; } - void InitDirect(int x, int y, int height, TextureID patch, String hotkey, Name child, int param = 0) + void InitDirect(double x, double y, int height, TextureID patch, String hotkey, Name child, int param = 0) { Super.Init(x, y, height, child, param); mHotkey = hotkey.CharCodeAt(0); diff --git a/wadsrc/static/zscript/menu/menuitembase.txt b/wadsrc/static/zscript/menu/menuitembase.txt index de5f05a424..35663d8b2f 100644 --- a/wadsrc/static/zscript/menu/menuitembase.txt +++ b/wadsrc/static/zscript/menu/menuitembase.txt @@ -6,11 +6,11 @@ class MenuItemBase : Object native { - protected native int mXpos, mYpos; + protected native double mXpos, mYpos; protected native Name mAction; native bool mEnabled; - void Init(int xpos = 0, int ypos = 0, Name actionname = 'None') + void Init(double xpos = 0, double ypos = 0, Name actionname = 'None') { mXpos = xpos; mYpos = ypos; @@ -36,10 +36,10 @@ class MenuItemBase : Object native virtual int GetIndent() { return 0; } virtual int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { return indent; } - void OffsetPositionY(int ydelta) { mYpos += ydelta; } - int GetY() { return mYpos; } - int GetX() { return mXpos; } - void SetX(int x) { mXpos = x; } + void OffsetPositionY(double ydelta) { mYpos += ydelta; } + double GetY() { return mYpos; } + double GetX() { return mXpos; } + void SetX(double x) { mXpos = x; } } // this is only used to parse font color ranges in MENUDEF diff --git a/wadsrc/static/zscript/menu/playercontrols.txt b/wadsrc/static/zscript/menu/playercontrols.txt index 389c34043e..b7b4f05f4b 100644 --- a/wadsrc/static/zscript/menu/playercontrols.txt +++ b/wadsrc/static/zscript/menu/playercontrols.txt @@ -71,7 +71,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable // //============================================================================= - void InitDirect(int x, int y, int height, int frameofs, String text, Font font, int color, Name command) + void InitDirect(double x, double y, int height, int frameofs, String text, Font font, int color, Name command) { Super.Init(x, y, height, command); mText = text; @@ -113,7 +113,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable // //============================================================================= - protected void DrawBorder (int x, int y, int len) + protected void DrawBorder (double x, double y, int len) { let left = TexMan.CheckForTexture("M_LSLEFT", TexMan.Type_MiscPatch); let mid = TexMan.CheckForTexture("M_LSCNTR", TexMan.Type_MiscPatch); @@ -141,7 +141,9 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable } else { - screen.Clear(x, y, x + len, y + SmallFont.GetHeight() * 3/2, 0); + int xx = int(x - 160) * CleanXfac + screen.GetWidth()/2; + int yy = int(y - 100) * CleanXfac + screen.GetHeight()/2; + screen.Clear(xx, yy, xx + len*CleanXfac, yy + SmallFont.GetHeight() * CleanYfac * 3/2, 0); } } } @@ -161,7 +163,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable } // Draw player name box - int x = mXpos + mFont.StringWidth(text) + 16 + mFrameSize; + double x = mXpos + mFont.StringWidth(text) + 16 + mFrameSize; DrawBorder (x, mYpos - mFrameSize, MAXPLAYERNAME+1); if (!mEnter) { @@ -246,7 +248,7 @@ class ListMenuItemValueText : ListMenuItemSelectable // //============================================================================= - void InitDirect(int x, int y, int height, String text, Font font, int color, int valuecolor, Name command, Name values) + void InitDirect(double x, double y, int height, String text, Font font, int color, int valuecolor, Name command, Name values) { Super.Init(x, y, height, command); mText = text; @@ -337,7 +339,7 @@ class ListMenuItemValueText : ListMenuItemSelectable String text = Stringtable.Localize(mText); screen.DrawText(mFont, selected? OptionMenuSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true); - int x = mXpos + mFont.StringWidth(text) + 8; + double x = mXpos + mFont.StringWidth(text) + 8; if (mSelections.Size() > 0) { screen.DrawText(mFont, mFontColor2, x, mYpos, mSelections[mSelection], DTA_Clean, true); @@ -385,7 +387,7 @@ class ListMenuItemSlider : ListMenuItemSelectable // //============================================================================= - void InitDirect(int x, int y, int height, String text, Font font, int color, Name command, int min, int max, int step) + void InitDirect(double x, double y, int height, String text, Font font, int color, Name command, int min, int max, int step) { Super.Init(x, y, height, command); mText = text; @@ -463,7 +465,7 @@ class ListMenuItemSlider : ListMenuItemSelectable lm.ReleaseFocus(); } - int slide_left = SmallFont.StringWidth ("Green") + 8 + mXpos; + int slide_left = SmallFont.StringWidth ("Green") + 8 + int(mXpos); int slide_right = slide_left + 12*8; // 12 char cells with 8 pixels each. if (type == Menu.MOUSE_Click) @@ -491,7 +493,7 @@ class ListMenuItemSlider : ListMenuItemSelectable // //============================================================================= - protected void DrawSlider (int x, int y) + protected void DrawSlider (double x, double y) { int range = mMaxrange - mMinrange; int cur = mSelection - mMinrange; @@ -515,8 +517,8 @@ class ListMenuItemSlider : ListMenuItemSelectable screen.DrawText(mFont, selected? OptionMenuSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true); - int x = SmallFont.StringWidth ("Green") + 8 + mXpos; - int x2 = SmallFont.StringWidth (text) + 8 + mXpos; + double x = SmallFont.StringWidth ("Green") + 8 + mXpos; + double x2 = SmallFont.StringWidth (text) + 8 + mXpos; DrawSlider (MAX(x2, x), mYpos); } } \ No newline at end of file diff --git a/wadsrc/static/zscript/menu/playerdisplay.txt b/wadsrc/static/zscript/menu/playerdisplay.txt index 492ba978c3..da64559c84 100644 --- a/wadsrc/static/zscript/menu/playerdisplay.txt +++ b/wadsrc/static/zscript/menu/playerdisplay.txt @@ -252,8 +252,8 @@ class ListMenuItemPlayerDisplay : ListMenuItem } else { - int x = (mXpos - 160) * CleanXfac + (screen.GetWidth() >> 1); - int y = (mYpos - 100) * CleanYfac + (screen.GetHeight() >> 1); + int x = int(mXpos - 160) * CleanXfac + (screen.GetWidth() >> 1); + int y = int(mYpos - 100) * CleanYfac + (screen.GetHeight() >> 1); screen.DrawTexture(mBackdrop, false, x, y - 1, DTA_DestWidth, 72 * CleanXfac, From fa0be4d4a93f580d968ecd50168b28498c04c035 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 17:30:02 +0100 Subject: [PATCH 058/207] - fixed keycodes for confirmation menu. --- wadsrc/static/zscript/menu/messagebox.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt index d952985462..b7b611f415 100644 --- a/wadsrc/static/zscript/menu/messagebox.txt +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -181,12 +181,12 @@ class MessageBoxMenu : Menu int ch = ev.data1; ch = ch >= 65 && ch <91? ch + 32 : ch; - if (ch == 78 /*'n'*/ || ch == 32) + if (ch == 110 /*'n'*/ || ch == 32) { HandleResult(false); return true; } - else if (ch == 89 /*'y'*/) + else if (ch == 121 /*'y'*/) { HandleResult(true); return true; From 68b47d81de98ec3674f1fa8f7d642b9cd3e86b32 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 17:58:54 +0100 Subject: [PATCH 059/207] - fixed WP_NOCHANGE changes with a restart, so this must be taken into account for the script variable holding it. --- src/scripting/thingdef_data.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 0f5647005f..378c6c9278 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -65,6 +65,7 @@ static TArray AFTable; static TArray FieldTable; extern int BackbuttonTime; extern float BackbuttonAlpha; +static AWeapon *wpnochg; //========================================================================== // @@ -924,7 +925,7 @@ void InitThingdef() // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' // is to create a static variable from it and reference that in the script. Yuck!!! - static AWeapon *wpnochg = WP_NOCHANGE; + wpnochg = WP_NOCHANGE; fieldptr = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); From 6c9558459d941a072ffd3fb4f281200be24c5a68 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 18:15:40 +0100 Subject: [PATCH 060/207] - allow menu items to inherit their parent's Init method for MENUDEFS. --- src/menu/menudef.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index cf986ee582..16b5671663 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -369,7 +369,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) PClass *cls = PClass::FindClass(buildname); if (cls != nullptr && cls->IsDescendantOf("ListMenuItem")) { - auto func = dyn_cast(cls->Symbols.FindSymbol("Init", false)); + auto func = dyn_cast(cls->Symbols.FindSymbol("Init", true)); if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. { auto &args = func->Variants[0].Proto->ArgumentTypes; @@ -741,7 +741,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) PClass *cls = PClass::FindClass(buildname); if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem")) { - auto func = dyn_cast(cls->Symbols.FindSymbol("Init", false)); + auto func = dyn_cast(cls->Symbols.FindSymbol("Init", true)); if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. { auto &args = func->Variants[0].Proto->ArgumentTypes; From 65f2433ac727682520ecb4be1b285b5031c23d68 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 18:27:29 +0100 Subject: [PATCH 061/207] - fixed: The text enter screen must be activated if it should be displayed. --- wadsrc/static/zscript/menu/optionmenuitems.txt | 1 + wadsrc/static/zscript/menu/playercontrols.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/wadsrc/static/zscript/menu/optionmenuitems.txt b/wadsrc/static/zscript/menu/optionmenuitems.txt index 9ac3083724..404ce5b36f 100644 --- a/wadsrc/static/zscript/menu/optionmenuitems.txt +++ b/wadsrc/static/zscript/menu/optionmenuitems.txt @@ -1129,6 +1129,7 @@ class OptionMenuItemTextField : OptionMenuFieldBase { Menu.MenuSound("menu/choose"); mEnter = TextEnterMenu.Open(Menu.GetCurrentMenu(), GetCVarString(), -1, 2, fromcontroller); + mEnter.ActivateMenu(); return true; } else if (mkey == Menu.MKEY_Input) diff --git a/wadsrc/static/zscript/menu/playercontrols.txt b/wadsrc/static/zscript/menu/playercontrols.txt index b7b4f05f4b..b0f97cdbc2 100644 --- a/wadsrc/static/zscript/menu/playercontrols.txt +++ b/wadsrc/static/zscript/menu/playercontrols.txt @@ -188,6 +188,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable { Menu.MenuSound ("menu/choose"); mEnter = TextEnterMenu.Open(Menu.GetCurrentMenu(), mPlayerName, MAXPLAYERNAME, 2, fromcontroller); + mEnter.ActivateMenu(); return true; } else if (mkey == Menu.MKEY_Input) From 4ca20e0297f56f8ee517e2bd612da27ed8b857c8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 21:35:06 +0100 Subject: [PATCH 062/207] - fixed: AActor::SetPortalTransition set an incorrect value for the previous position. --- src/p_mobj.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2508f50f22..f9a62892a9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3848,7 +3848,7 @@ void AActor::CheckPortalTransition(bool islinked) DVector3 oldpos = Pos(); if (islinked && !moved) UnlinkFromWorld(&ctx); SetXYZ(PosRelative(Sector->GetOppositePortalGroup(sector_t::ceiling))); - Prev = Pos() - oldpos; + Prev += Pos() - oldpos; Sector = P_PointInSector(Pos()); PrevPortalGroup = Sector->PortalGroup; moved = true; @@ -3865,7 +3865,7 @@ void AActor::CheckPortalTransition(bool islinked) DVector3 oldpos = Pos(); if (islinked && !moved) UnlinkFromWorld(&ctx); SetXYZ(PosRelative(Sector->GetOppositePortalGroup(sector_t::floor))); - Prev = Pos() - oldpos; + Prev += Pos() - oldpos; Sector = P_PointInSector(Pos()); PrevPortalGroup = Sector->PortalGroup; moved = true; From 165a9800658c89e2a4244eb14492cfe329070eae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 22:08:22 +0100 Subject: [PATCH 063/207] - fixed: The base MouseEvent method must return true, not false. - fixed: It is a bad idea to start a save within an MKEY_Input event. At this time the window chain is not stable because the text input screen is in the middle of being taken down, so the save should be deferred until the next Ticker call of the SaveMenu. --- wadsrc/static/zscript/menu/loadsavemenu.txt | 14 ++++++- wadsrc/static/zscript/menu/menu.txt | 2 +- wadsrc/static/zscript/menu/textentermenu.txt | 39 +++++++++----------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index 34d56f3745..05638d393b 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -426,6 +426,8 @@ class LoadSaveMenu : ListMenu class SaveMenu : LoadSaveMenu { + String mSaveName; + //============================================================================= // // @@ -464,7 +466,6 @@ class SaveMenu : LoadSaveMenu override bool MenuEvent (int mkey, bool fromcontroller) { - if (Super.MenuEvent(mkey, fromcontroller)) { return true; @@ -483,8 +484,9 @@ class SaveMenu : LoadSaveMenu } else if (mkey == MKEY_Input) { + // Do not start the save here, it would cause some serious execution ordering problems. mEntering = false; - manager.DoSave(Selected, mInput.GetText()); + mSaveName = mInput.GetText(); mInput = null; } else if (mkey == MKEY_Abort) @@ -525,6 +527,14 @@ class SaveMenu : LoadSaveMenu } + override void Ticker() + { + if (mSaveName.Length() > 0) + { + manager.DoSave(Selected, mSaveName); + mSaveName = ""; + } + } } diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 84478ba818..9f59b32397 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -266,7 +266,7 @@ class Menu : Object native virtual bool CheckFocus(MenuItemBase fc) { return false; } virtual void ReleaseFocus() {} virtual void ResetColor() {} - virtual bool MouseEvent(int type, int mx, int my) { return false; } + virtual bool MouseEvent(int type, int mx, int my) { return true; } virtual void Ticker() {} //============================================================================= diff --git a/wadsrc/static/zscript/menu/textentermenu.txt b/wadsrc/static/zscript/menu/textentermenu.txt index 356eba1e60..b92932aaf3 100644 --- a/wadsrc/static/zscript/menu/textentermenu.txt +++ b/wadsrc/static/zscript/menu/textentermenu.txt @@ -171,31 +171,28 @@ class TextEnterMenu : Menu override bool MouseEvent(int type, int x, int y) { - if (mMouseCapture || m_use_mouse == 1) - { - int cell_width = 18 * CleanXfac; - int cell_height = 12 * CleanYfac; - int screen_y = screen.GetHeight() - INPUTGRID_HEIGHT * cell_height; - int screen_x = (screen.GetWidth() - INPUTGRID_WIDTH * cell_width) / 2; + int cell_width = 18 * CleanXfac; + int cell_height = 12 * CleanYfac; + int screen_y = screen.GetHeight() - INPUTGRID_HEIGHT * cell_height; + int screen_x = (screen.GetWidth() - INPUTGRID_WIDTH * cell_width) / 2; - if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y) + if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y) + { + InputGridX = (x - screen_x) / cell_width; + InputGridY = (y - screen_y) / cell_height; + if (type == MOUSE_Release) { - InputGridX = (x - screen_x) / cell_width; - InputGridY = (y - screen_y) / cell_height; - if (type == MOUSE_Release) + if (MenuEvent(MKEY_Enter, true)) { - if (MenuEvent(MKEY_Enter, true)) - { - MenuSound("menu/choose"); - if (m_use_mouse == 2) InputGridX = InputGridY = -1; - return true; - } + MenuSound("menu/choose"); + if (m_use_mouse == 2) InputGridX = InputGridY = -1; } } - else - { - InputGridX = InputGridY = -1; - } + return true; + } + else + { + InputGridX = InputGridY = -1; } return Super.MouseEvent(type, x, y); } @@ -262,8 +259,8 @@ class TextEnterMenu : Menu if (mEnterString.Length() > 0) { Menu parent = mParentMenu; - Close(); parent.MenuEvent(MKEY_Input, false); + Close(); return true; } } From 26144340b804521c1d069aece5aa30f95eddf1ce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 23:20:09 +0100 Subject: [PATCH 064/207] - fixed: Hexen's poison cloud needs to call P_DamageMobj, even with a damage value of 0. Added a new flag to handle this case because normally this is not desirable. --- src/actor.h | 1 + src/p_map.cpp | 5 +++-- src/scripting/thingdef_data.cpp | 1 + wadsrc/static/zscript/hexen/flechette.txt | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/actor.h b/src/actor.h index a973c101a6..d3c430759e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -387,6 +387,7 @@ enum ActorFlag7 MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. MF7_SMASHABLE = 0x04000000, // dies if hitting the floor. MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields. + MF7_FORCEZERORADIUSDMG = 0x10000000, // passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. }; // --- mobj.renderflags --- diff --git a/src/p_map.cpp b/src/p_map.cpp index da84855fde..789a070767 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5674,8 +5674,9 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom } points *= thing->GetClass()->RDFactor; + double check = int(points) * bombdamage; // points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.) - if ((((double)int(points) * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) + if ((check > 0 || (check == 0 && bombspot->flags7 & MF7_FORCEZERORADIUSDMG)) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { // OK to damage; target is in direct path double vz; double thrust; @@ -5752,7 +5753,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom double factor = splashfactor * thing->GetClass()->RDFactor; damage = int(damage * factor); - if (damage > 0) + if (damage > 0 || (bombspot->flags7 & MF7_FORCEZERORADIUSDMG)) { //[MC] Don't count actors saved by buddha if already at 1 health. int prehealth = thing->health; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 378c6c9278..41d8644ea8 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -316,6 +316,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7), DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7), DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7), + DEFINE_FLAG(MF7, FORCEZERORADIUSDMG, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/wadsrc/static/zscript/hexen/flechette.txt b/wadsrc/static/zscript/hexen/flechette.txt index 3440312c9e..1708b843b5 100644 --- a/wadsrc/static/zscript/hexen/flechette.txt +++ b/wadsrc/static/zscript/hexen/flechette.txt @@ -437,7 +437,7 @@ class PoisonCloud : Actor Mass 0x7fffffff; +NOBLOCKMAP +NOGRAVITY +DROPOFF +NODAMAGETHRUST - +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT +BLOCKEDBYSOLIDACTORS + +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT +BLOCKEDBYSOLIDACTORS +FORCEZERORADIUSDMG RenderStyle "Translucent"; Alpha 0.6; DeathSound "PoisonShroomDeath"; From b134ea5b4f0062aa4ea81a3d233a1f0b06bb8919 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Wed, 15 Feb 2017 10:10:54 -0500 Subject: [PATCH 065/207] - fixed: Change compiled exe version strings to match git repo numbers. This is viewable in Windows by right-clicking on the executable and selecting "Properties". --- src/version.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index ca7de97fef..5ee5472f2f 100644 --- a/src/version.h +++ b/src/version.h @@ -31,6 +31,8 @@ ** */ +#include "gitinfo.h" + #ifndef __VERSION_H__ #define __VERSION_H__ @@ -41,12 +43,16 @@ const char *GetVersionString(); /** Lots of different version numbers **/ +#ifdef GIT_DESCRIPTION +#define VERSIONSTR GIT_DESCRIPTION +#else #define VERSIONSTR "2.3pre" +#endif // The version as seen in the Windows resource #define RC_FILEVERSION 2,3,9999,0 #define RC_PRODUCTVERSION 2,3,9999,0 -#define RC_PRODUCTVERSION2 "2.3pre" +#define RC_PRODUCTVERSION2 VERSIONSTR // Version identifier for network games. // Bump it every time you do a release unless you're certain you From 051a394f476bbf7578d9400aec3b18132b5469b7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 20 Feb 2017 00:22:36 +0100 Subject: [PATCH 066/207] - fixed some mess in the graphics organization for the Strife status bar. This alternatingly loaded two different patch sets but it was entirely unclear which was supposed to be loaded when so they now are merged into one. It should have been two different variables from the start. --- src/g_statusbar/sbar.h | 10 ---------- src/g_statusbar/strife_sbar.cpp | 21 +++++---------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 3c911e6932..1e8af15144 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -404,16 +404,6 @@ public: double CrosshairSize; double Displacement; - enum - { - imgLAME = 0, - imgNEGATIVE = 1, - imgINumbers = 2, - imgBNEGATIVE = 12, - imgBNumbers = 13, - imgSmNumbers = 23, - NUM_BASESB_IMAGES = 33 - }; FImageCollection Images; player_t *CPlayer; diff --git a/src/g_statusbar/strife_sbar.cpp b/src/g_statusbar/strife_sbar.cpp index 177117eb2b..9726574827 100644 --- a/src/g_statusbar/strife_sbar.cpp +++ b/src/g_statusbar/strife_sbar.cpp @@ -186,18 +186,6 @@ class DStrifeStatusBar : public DBaseStatusBar public: DStrifeStatusBar () : DBaseStatusBar (32) { - static const char *sharedLumpNames[] = - { - NULL, NULL, "INVFONY0", "INVFONY1", "INVFONY2", - "INVFONY3", "INVFONY4", "INVFONY5", "INVFONY6", "INVFONY7", - "INVFONY8", "INVFONY9", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, "INVFONG0", "INVFONG1", - "INVFONG2", "INVFONG3", "INVFONG4", "INVFONG5", "INVFONG6", - "INVFONG7", "INVFONG8", "INVFONG9" - }; - - DBaseStatusBar::Images.Init (sharedLumpNames, NUM_BASESB_IMAGES); DoCommonInit (); } @@ -301,10 +289,11 @@ private: "INVFONY0", "INVFONY1", "INVFONY2", "INVFONY3", "INVFONY4", "INVFONY5", "INVFONY6", "INVFONY7", "INVFONY8", "INVFONY9", "INVFONY%", - "I_COMM", "I_MDKT", "I_ARM1", "I_ARM2" + "I_COMM", "I_MDKT", "I_ARM1", "I_ARM2", nullptr + }; - Images.Init (strifeLumpNames, NUM_STRIFESB_IMAGES); + Images.Init (strifeLumpNames, countof(strifeLumpNames)); CursorImage = Images[imgINVCURS] != NULL ? imgINVCURS : imgCURSOR01; @@ -834,8 +823,8 @@ private: imgMEDI, imgARM1, imgARM2, - - NUM_STRIFESB_IMAGES + imgNEGATIVE, + imgINumbers = imgFONG0, }; FImageCollection Images; From bb6e667f33adddb024fa38a3f1984a1ff273724b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 20 Feb 2017 01:42:53 +0100 Subject: [PATCH 067/207] - removed some unneeded version.h #includes. --- src/g_statusbar/sbarinfo.cpp | 1 - src/gl/compatibility/gl_20.cpp | 1 - src/menu/menu.h | 1 - src/scripting/decorate/thingdef_parse.cpp | 1 - src/scripting/decorate/thingdef_states.cpp | 1 - src/scripting/zscript/zcc_compile.cpp | 1 - 6 files changed, 6 deletions(-) diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index 2fd21737f2..5096ee8134 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -54,7 +54,6 @@ #include "v_palette.h" #include "p_acs.h" #include "gstrings.h" -#include "version.h" #include "cmdlib.h" #include "g_levellocals.h" diff --git a/src/gl/compatibility/gl_20.cpp b/src/gl/compatibility/gl_20.cpp index eeb5572c18..7fc8b783bd 100644 --- a/src/gl/compatibility/gl_20.cpp +++ b/src/gl/compatibility/gl_20.cpp @@ -34,7 +34,6 @@ #include "doomtype.h" #include "m_argv.h" #include "zstring.h" -#include "version.h" #include "i_system.h" #include "v_text.h" #include "r_utility.h" diff --git a/src/menu/menu.h b/src/menu/menu.h index 8922147e19..6d7bdc9271 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -9,7 +9,6 @@ #include "r_data/r_translate.h" #include "c_cvars.h" #include "v_font.h" -#include "version.h" #include "textures/textures.h" EXTERN_CVAR(Float, snd_menuvolume) diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 991577f68e..e444d30a9f 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -52,7 +52,6 @@ #include "backend/codegen.h" #include "w_wad.h" #include "v_video.h" -#include "version.h" #include "v_text.h" #include "m_argv.h" diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 63269eeeb5..74c67cf84e 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -54,7 +54,6 @@ #include "i_system.h" #include "colormatcher.h" #include "backend/codegen.h" -#include "version.h" #include "templates.h" #include "backend/vmbuilder.h" diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index c802dda367..29f82d90e9 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -49,7 +49,6 @@ #include "i_system.h" #include "gdtoa.h" #include "backend/vmbuilder.h" -#include "version.h" static int GetIntConst(FxExpression *ex, FCompileContext &ctx) { From bdd20d3887d7ec0c9c5872d218b2180c3f1fa79f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 21 Feb 2017 22:36:20 +0200 Subject: [PATCH 068/207] Fixed initialization of Strife dialogs internal structures Explicit assignment to members, no more memset() on non-PoD types https://mantis.zdoom.org/view.php?id=317 --- src/p_conversation.cpp | 10 ---------- src/p_conversation.h | 28 +++++++++++++--------------- src/p_usdf.cpp | 3 --- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 449f9e286f..90271333c2 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -568,16 +568,6 @@ FStrifeDialogueNode::~FStrifeDialogueNode () } } -//============================================================================ -// -// FStrifeDialogueReply :: ~FStrifeDialogueReply -// -//============================================================================ - -FStrifeDialogueReply::~FStrifeDialogueReply () -{ -} - //============================================================================ // // FindNode diff --git a/src/p_conversation.h b/src/p_conversation.h index 302203bd2a..7ee24093b6 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -20,19 +20,19 @@ struct FStrifeDialogueItemCheck struct FStrifeDialogueNode { ~FStrifeDialogueNode (); - PClassActor *DropType; + PClassActor *DropType = nullptr; TArray ItemCheck; - int ThisNodeNum; // location of this node in StrifeDialogues - int ItemCheckNode; // index into StrifeDialogues + int ThisNodeNum = 0; // location of this node in StrifeDialogues + int ItemCheckNode = 0; // index into StrifeDialogues - PClassActor *SpeakerType; + PClassActor *SpeakerType = nullptr; FString SpeakerName; FSoundID SpeakerVoice; FString Backdrop; FString Dialogue; FString Goodbye; // must init to null for binary scripts to work as intended - FStrifeDialogueReply *Children; + FStrifeDialogueReply *Children = nullptr; FName MenuClassName; FString UserData; }; @@ -40,13 +40,11 @@ struct FStrifeDialogueNode // FStrifeDialogueReply holds responses the player can give to the NPC struct FStrifeDialogueReply { - ~FStrifeDialogueReply (); - - FStrifeDialogueReply *Next; - PClassActor *GiveType; - int ActionSpecial; - int Args[5]; - int PrintAmount; + FStrifeDialogueReply *Next = nullptr; + PClassActor *GiveType = nullptr; + int ActionSpecial = 0; + int Args[5] = {}; + int PrintAmount = 0; TArray ItemCheck; TArray ItemCheckRequire; TArray ItemCheckExclude; @@ -54,9 +52,9 @@ struct FStrifeDialogueReply FString QuickYes; FString QuickNo; FString LogString; - int NextNode; // index into StrifeDialogues - int LogNumber; - bool NeedsGold; + int NextNode = 0; // index into StrifeDialogues + int LogNumber = 0; + bool NeedsGold = false; }; extern TArray StrifeDialogues; diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index d2a1bb25e5..5a5f3c8269 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -121,7 +121,6 @@ class USDFParser : public UDMFParserBase bool ParseChoice(FStrifeDialogueReply **&replyptr) { FStrifeDialogueReply *reply = new FStrifeDialogueReply; - memset(reply, 0, sizeof(*reply)); reply->Next = *replyptr; *replyptr = reply; @@ -293,8 +292,6 @@ class USDFParser : public UDMFParserBase { FStrifeDialogueNode *node = new FStrifeDialogueNode; FStrifeDialogueReply **replyptr = &node->Children; - memset(node, 0, sizeof(*node)); - //node->ItemCheckCount[0] = node->ItemCheckCount[1] = node->ItemCheckCount[2] = -1; node->ThisNodeNum = StrifeDialogues.Push(node); node->ItemCheckNode = -1; From b45418d3636b4e286fbdb00e9708d30c8149d64e Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 12:21:04 +0200 Subject: [PATCH 069/207] Removed problematic assert() from garbage collector DObject::GetClass() cannot be called from Barrier() function Lazy evaluation it contains screwed up object type if called from base class constructor Example: DSeqSectorNode::DSeqSectorNode() -> DSeqNode::DSeqNode() -> GC::WriteBarrier() -> Barrier() https://mantis.zdoom.org/view.php?id=299 --- src/dobjgc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 4fe609a5a0..3d683aff11 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -544,7 +544,6 @@ void FullGC() void Barrier(DObject *pointing, DObject *pointed) { - assert(pointed->GetClass() != nullptr); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointed->IsWhite() && !pointed->IsDead()); assert(State != GCS_Finalize && State != GCS_Pause); From 61de40c6788828ec91b3d91caef579567757c6a0 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 17:39:04 +0200 Subject: [PATCH 070/207] Relaxed error check for menu textures Null texture is acceptable as menu patch Total conversion IWADs like Adventures of Square may use this technique https://mantis.zdoom.org/view.php?id=320 --- src/menu/menudef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 16b5671663..bc95198f27 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -411,7 +411,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) else if (args[i] == TypeTextureID) { auto f = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); - if (!f.isValid()) + if (!f.Exists()) { sc.ScriptError("Unknown texture %s", sc.String); } From 322aee97d60e14f35a381f448e2a1fc214a6fb93 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 22:25:24 +0200 Subject: [PATCH 071/207] Removed dynamic light binding for deleted class StrifeZap1 https://mantis.zdoom.org/view.php?id=311 --- wadsrc_lights/static/filter/strife/gldefs.txt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/wadsrc_lights/static/filter/strife/gldefs.txt b/wadsrc_lights/static/filter/strife/gldefs.txt index 8a2bdcc5dc..7474486ba0 100644 --- a/wadsrc_lights/static/filter/strife/gldefs.txt +++ b/wadsrc_lights/static/filter/strife/gldefs.txt @@ -2651,16 +2651,6 @@ flickerlight LGNTAIL chance 0.8 } -object StrifeZap1 -{ - frame ZAP1A { light ARROWZAP1 } - frame ZAP1B { light ARROWZAP2 } - frame ZAP1C { light ARROWZAP3 } - frame ZAP1D { light ARROWZAP4 } - frame ZAP1E { light ARROWZAP5 } - frame ZAP1F { light ARROWZAP6 } -} - object SpectralLightningBase { frame ZAP1A { light ARROWZAP1 } @@ -2871,4 +2861,4 @@ object TeleportFog frame TFOGD { light TFOG4 } frame TFOGE { light TFOG5 } frame TFOGF { light TFOG6 } -} \ No newline at end of file +} From eb40e8bcf0a035e1922119bcf1b44877719455b1 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 23:02:58 +0200 Subject: [PATCH 072/207] Removed DYNLIGHT preprocessor definition https://mantis.zdoom.org/view.php?id=318 --- src/scripting/decorate/thingdef_states.cpp | 4 +--- src/scripting/zscript/zcc_compile.cpp | 3 +-- src/version.h | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 74c67cf84e..b3d4c904a2 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -315,9 +315,7 @@ do_stop: do { sc.MustGetString(); - #ifdef DYNLIGHT - AddStateLight(&state, sc.String); - #endif + AddStateLight(&state, sc.String); } while (sc.CheckString(",")); sc.MustGetStringName(")"); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 29f82d90e9..b28226efbb 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2562,7 +2562,7 @@ void ZCCCompiler::CompileStates() state.Misc1 = IntConstFromNode(sl->Offset, c->Type()); state.Misc2 = IntConstFromNode(static_cast(sl->Offset->SiblingNext), c->Type()); } -#ifdef DYNLIGHT + if (sl->Lights != nullptr) { auto l = sl->Lights; @@ -2572,7 +2572,6 @@ void ZCCCompiler::CompileStates() l = static_cast(l->SiblingNext); } while (l != sl->Lights); } -#endif if (sl->Action != nullptr) { diff --git a/src/version.h b/src/version.h index 5ee5472f2f..a03c6a21e8 100644 --- a/src/version.h +++ b/src/version.h @@ -87,8 +87,6 @@ const char *GetVersionString(); // SVN revision ever got. #define SAVEVER 4550 -#define DYNLIGHT - // This is so that derivates can use the same savegame versions without worrying about engine compatibility #define GAMESIG "GZDOOM" #define BASEWAD "gzdoom.pk3" From 59d304274ff7f73423b822bcb8b7e82c68af2b11 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 22 Feb 2017 23:20:54 +0100 Subject: [PATCH 073/207] - Fixed some scripts showing up as 'unknown'. See https://mantis.zdoom.org/view.php?id=322 . --- src/p_acs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 00b1d7be85..463868d88a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2821,6 +2821,8 @@ void FBehavior::StaticStartTypedScripts (WORD type, AActor *activator, bool alwa "Unloading", "Disconnect", "Return", + "Event", + "Kill", "Reopen" }; DPrintf(DMSG_NOTIFY, "Starting all scripts of type %d (%s)\n", type, From 47ff6ec33fb198aadd1c9b0cc1365ecb6f583f10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 22 Feb 2017 23:52:25 +0100 Subject: [PATCH 074/207] - converted the intermission stat screen into a class so that its contents can be better exposed to ZScript. --- src/gi.cpp | 3 + src/wi_stuff.cpp | 3885 ++++++++++++++++---------------- wadsrc/static/zscript/base.txt | 9 + 3 files changed, 1951 insertions(+), 1946 deletions(-) diff --git a/src/gi.cpp b/src/gi.cpp index 18fd39f69b..fa8afb5459 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -53,6 +53,9 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, infoPages) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenMapNameFont) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenEnteringFont) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenFinishedFont) const char *GameNames[17] = diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 73a5b9742e..ebc022df8d 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -54,237 +54,13 @@ #include "cmdlib.h" #include "g_levellocals.h" -// States for the intermission -typedef enum -{ - NoState = -1, - StatCount, - ShowNextLoc, - LeavingIntermission -} stateenum_t; - -CVAR (Bool, wi_percents, true, CVAR_ARCHIVE) -CVAR (Bool, wi_showtotaltime, true, CVAR_ARCHIVE) -CVAR (Bool, wi_noautostartmap, false, CVAR_USERINFO|CVAR_ARCHIVE) -CVAR (Int, wi_autoadvance, 0, CVAR_SERVERINFO) +CVAR(Bool, wi_percents, true, CVAR_ARCHIVE) +CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE) +CVAR(Bool, wi_noautostartmap, false, CVAR_USERINFO | CVAR_ARCHIVE) +CVAR(Int, wi_autoadvance, 0, CVAR_SERVERINFO) -void WI_loadData (); -void WI_unloadData (); - -// GLOBAL LOCATIONS -#define WI_TITLEY 2 -#define WI_SPACINGY 33 - -// SINGPLE-PLAYER STUFF -#define SP_STATSX 50 -#define SP_STATSY 50 - -#define SP_TIMEX 8 -#define SP_TIMEY (200-32) - - -// NET GAME STUFF -#define NG_STATSY 50 -#define NG_STATSX (32 + star->GetScaledWidth()/2 + 32*!dofrags) - -#define NG_SPACINGX 64 - - -// DEATHMATCH STUFF -#define DM_MATRIXX 42 -#define DM_MATRIXY 68 - -#define DM_SPACINGX 40 - -#define DM_TOTALSX 269 - -#define DM_KILLERSX 10 -#define DM_KILLERSY 100 -#define DM_VICTIMSX 5 -#define DM_VICTIMSY 50 - -// These animation variables, structures, etc. are used for the -// DOOM/Ultimate DOOM intermission screen animations. This is -// totally different from any sprite or texture/flat animations -typedef enum -{ - ANIM_ALWAYS, // determined by patch entry - ANIM_PIC, // continuous - - // condition bitflags - ANIM_IFVISITED=8, - ANIM_IFNOTVISITED=16, - ANIM_IFENTERING=32, - ANIM_IFNOTENTERING=64, - ANIM_IFLEAVING=128, - ANIM_IFNOTLEAVING=256, - ANIM_IFTRAVELLING=512, - ANIM_IFNOTTRAVELLING=1024, - - ANIM_TYPE=7, - ANIM_CONDITION=~7, - -} animenum_t; - -struct yahpt_t -{ - int x, y; -}; - -struct lnode_t -{ - int x; // x/y coordinate pair structure - int y; - char level[9]; -} ; - - -#define FACEBACKOFS 4 - - -// -// Animation. -// There is another anim_t used in p_spec. -// (which is why I have renamed this one!) -// - -#define MAX_ANIMATION_FRAMES 20 -struct in_anim_t -{ - int type; // Made an int so I can use '|' - int period; // period in tics between animations - int nanims; // number of animation frames - yahpt_t loc; // location of animation - int data; // ALWAYS: n/a, RANDOM: period deviation (<256) - FTexture * p[MAX_ANIMATION_FRAMES]; // actual graphics for frames of animations - - // following must be initialized to zero before use! - int nexttic; // next value of bcnt (used in conjunction with period) - int ctr; // next frame number to animate - int state; // used by RANDOM and LEVEL when animating - - char levelname[9]; - char levelname2[9]; -}; - -static TArray lnodes; -static TArray anims; - - -// -// GENERAL DATA -// - -// -// Locally used stuff. -// - - -// States for single-player -#define SP_KILLS 0 -#define SP_ITEMS 2 -#define SP_SECRET 4 -#define SP_FRAGS 6 -#define SP_TIME 8 -#define SP_PAR ST_TIME - -#define SP_PAUSE 1 - -#define SHOWNEXTLOCDELAY 4 // in seconds - -static int acceleratestage; // used to accelerate or skip a stage -static bool playerready[MAXPLAYERS]; -static int me; // wbs->pnum -static stateenum_t state; // specifies current state -static wbstartstruct_t *wbs; // contains information passed into intermission -static wbplayerstruct_t*plrs; // wbs->plyr[] -static int cnt; // used for general timing -static int bcnt; // used for timing of background animation -static int cnt_kills[MAXPLAYERS]; -static int cnt_items[MAXPLAYERS]; -static int cnt_secret[MAXPLAYERS]; -static int cnt_frags[MAXPLAYERS]; -static int cnt_deaths[MAXPLAYERS]; -static int cnt_time; -static int cnt_total_time; -static int cnt_par; -static int cnt_pause; -static int total_frags; -static int total_deaths; -static bool noautostartmap; -static int dofrags; -static int ng_state; - -// -// GRAPHICS -// - -struct FPatchInfo -{ - FFont *mFont; - FTexture *mPatch; - EColorRange mColor; - - void Init(FGIFont &gifont) - { - if (gifont.color == NAME_Null) - { - mPatch = TexMan[gifont.fontname]; // "entering" - mColor = mPatch == NULL? CR_UNTRANSLATED : CR_UNDEFINED; - mFont = NULL; - } - else - { - mFont = V_GetFont(gifont.fontname); - mColor = V_FindFontColor(gifont.color); - mPatch = NULL; - } - if (mFont == NULL) - { - mFont = BigFont; - } - } -}; - -static FPatchInfo mapname; -static FPatchInfo finished; -static FPatchInfo entering; - -static TArray yah; // You Are Here graphic -static FTexture* splat; // splat -static FTexture* sp_secret; // "secret" -static FTexture* kills; // "Kills", "Scrt", "Items", "Frags" -static FTexture* secret; -static FTexture* items; -static FTexture* frags; -static FTexture* timepic; // Time sucks. -static FTexture* par; -static FTexture* sucks; -static FTexture* killers; // "killers", "victims" -static FTexture* victims; -static FTexture* total; // "Total", your face, your dead face -//static FTexture* star; -//static FTexture* bstar; -static FTexture* p; // Player graphic -static FTexture* lnames[2]; // Name graphics of each level (centered) - -// [RH] Info to dynamically generate the level name graphics -static FString lnametexts[2]; - -static FTexture *background; - -// -// CODE -// - -// ==================================================================== -// -// Background script commands -// -// ==================================================================== - -static const char *WI_Cmd[]={ +static const char *WI_Cmd[] = { "Background", "Splat", "Pointer", @@ -307,1880 +83,2097 @@ static const char *WI_Cmd[]={ NULL }; -//==================================================================== -// -// Loads the background - either from a single texture -// or an intermission lump. -// Unfortunately the texture manager is incapable of recognizing text -// files so if you use a script you have to prefix its name by '$' in -// MAPINFO. -// -//==================================================================== -static bool IsExMy(const char * name) + +struct FPatchInfo { - // Only check for the first 3 episodes. They are the only ones with default intermission scripts. - // Level names can be upper- and lower case so use tolower to check! - return (tolower(name[0])=='e' && name[1]>='1' && name[1]<='3' && tolower(name[2])=='m'); -} + FFont *mFont; + FTexture *mPatch; + EColorRange mColor; -void WI_LoadBackground(bool isenterpic) -{ - const char *lumpname = NULL; - char buffer[10]; - in_anim_t an; - lnode_t pt; - FTextureID texture; - - bcnt=0; - - texture.SetInvalid(); - if (isenterpic) + void Init(FGIFont &gifont) { - level_info_t * li = FindLevelInfo(wbs->next); - if (li != NULL) lumpname = li->EnterPic; - } - else - { - lumpname = level.info->ExitPic; - } - - // Try to get a default if nothing specified - if (lumpname == NULL || lumpname[0]==0) - { - lumpname = NULL; - switch(gameinfo.gametype) + if (gifont.color == NAME_Null) { - case GAME_Chex: - case GAME_Doom: - if (!(gameinfo.flags & GI_MAPxx)) - { - const char *level = isenterpic ? wbs->next : wbs->current; - if (IsExMy(level)) - { - mysnprintf(buffer, countof(buffer), "$IN_EPI%c", level[1]); - lumpname = buffer; - } - } - if (!lumpname) - { - if (isenterpic) - { - // One special case needs to be handled here! - // If going from E1-E3 to E4 the default should be used, not the exit pic. - - // Not if the exit pic is user defined! - if (level.info->ExitPic.IsNotEmpty()) return; - - // E1-E3 need special treatment when playing Doom 1. - if (!(gameinfo.flags & GI_MAPxx)) - { - // not if the last level is not from the first 3 episodes - if (!IsExMy(wbs->current)) return; - - // not if the next level is one of the first 3 episodes - if (IsExMy(wbs->next)) return; - } - } - lumpname = "INTERPIC"; - } - break; - - case GAME_Heretic: - if (isenterpic) - { - if (IsExMy(wbs->next)) - { - mysnprintf(buffer, countof(buffer), "$IN_HTC%c", wbs->next[1]); - lumpname = buffer; - } - } - if (!lumpname) - { - if (isenterpic) return; - lumpname = "FLOOR16"; - } - break; - - case GAME_Hexen: - if (isenterpic) return; - lumpname = "INTERPIC"; - break; - - case GAME_Strife: - default: - // Strife doesn't have an intermission pic so choose something neutral. - if (isenterpic) return; - lumpname = gameinfo.BorderFlat; - break; + mPatch = TexMan[gifont.fontname]; // "entering" + mColor = mPatch == NULL ? CR_UNTRANSLATED : CR_UNDEFINED; + mFont = NULL; + } + else + { + mFont = V_GetFont(gifont.fontname); + mColor = V_FindFontColor(gifont.color); + mPatch = NULL; + } + if (mFont == NULL) + { + mFont = BigFont; } } - if (lumpname == NULL) +}; + + + +class FIntermissionScreen +{ +public: + // States for the intermission + enum EState { - // shouldn't happen! - background = NULL; - return; + NoState = -1, + StatCount, + ShowNextLoc, + LeavingIntermission + }; + + + enum EValues + { + // GLOBAL LOCATIONS + WI_TITLEY = 2, + + // SINGPLE-PLAYER STUFF + SP_STATSX = 50, + SP_STATSY = 50, + + SP_TIMEX = 8, + SP_TIMEY = (200 - 32), + + // NET GAME STUFF + NG_STATSY = 50, + }; + + + + // These animation variables, structures, etc. are used for the + // DOOM/Ultimate DOOM intermission screen animations. This is + // totally different from any sprite or texture/flat animations + enum EAnim + { + ANIM_ALWAYS, // determined by patch entry + ANIM_PIC, // continuous + + // condition bitflags + ANIM_IFVISITED = 8, + ANIM_IFNOTVISITED = 16, + ANIM_IFENTERING = 32, + ANIM_IFNOTENTERING = 64, + ANIM_IFLEAVING = 128, + ANIM_IFNOTLEAVING = 256, + ANIM_IFTRAVELLING = 512, + ANIM_IFNOTTRAVELLING = 1024, + + ANIM_TYPE = 7, + ANIM_CONDITION = ~7, + + }; + + // States for single-player + enum ESPState + { + SP_KILLS = 0, + SP_ITEMS = 2, + SP_SECRET = 4, + SP_FRAGS = 6, + SP_TIME = 8, + }; + + static const int SHOWNEXTLOCDELAY = 4; // in seconds + + struct yahpt_t + { + int x, y; + }; + + struct lnode_t + { + int x; // x/y coordinate pair structure + int y; + char level[9]; + }; + + + // + // Animation. + // There is another anim_t used in p_spec. + // (which is why I have renamed this one!) + // + + static const int MAX_ANIMATION_FRAMES = 20; + struct in_anim_t + { + int type; // Made an int so I can use '|' + int period; // period in tics between animations + int nanims; // number of animation frames + yahpt_t loc; // location of animation + int data; // ALWAYS: n/a, RANDOM: period deviation (<256) + FTexture * p[MAX_ANIMATION_FRAMES]; // actual graphics for frames of animations + + // following must be initialized to zero before use! + int nexttic; // next value of bcnt (used in conjunction with period) + int ctr; // next frame number to animate + int state; // used by RANDOM and LEVEL when animating + + char levelname[9]; + char levelname2[9]; + }; + + TArray lnodes; + TArray anims; + + int acceleratestage; // used to accelerate or skip a stage + bool playerready[MAXPLAYERS]; + int me; // wbs->pnum + EState state; // specifies current state + wbstartstruct_t *wbs; // contains information passed into intermission + wbplayerstruct_t*plrs; // wbs->plyr[] + int cnt; // used for general timing + int bcnt; // used for timing of background animation + int cnt_kills[MAXPLAYERS]; + int cnt_items[MAXPLAYERS]; + int cnt_secret[MAXPLAYERS]; + int cnt_frags[MAXPLAYERS]; + int cnt_deaths[MAXPLAYERS]; + int cnt_time; + int cnt_total_time; + int cnt_par; + int cnt_pause; + int total_frags; + int total_deaths; + bool noautostartmap; + int dofrags; + int ng_state; + + // + // GRAPHICS + // + + FPatchInfo mapname; + FPatchInfo finished; + FPatchInfo entering; + + TArray yah; // You Are Here graphic + FTexture* splat; // splat + FTexture* sp_secret; // "secret" + FTexture* kills; // "Kills", "Scrt", "Items", "Frags" + FTexture* secret; + FTexture* items; + FTexture* frags; + FTexture* timepic; // Time sucks. + FTexture* par; + FTexture* sucks; + FTexture* killers; // "killers", "victims" + FTexture* victims; + FTexture* total; // "Total", your face, your dead face + FTexture* p; // Player graphic + FTexture* lnames[2]; // Name graphics of each level (centered) + + // [RH] Info to dynamically generate the level name graphics + FString lnametexts[2]; + + FTexture *background; + + bool snl_pointeron = false; + + int player_deaths[MAXPLAYERS]; + int sp_state; + + // + // CODE + // + + + //==================================================================== + // + // Loads the background - either from a single texture + // or an intermission lump. + // Unfortunately the texture manager is incapable of recognizing text + // files so if you use a script you have to prefix its name by '$' in + // MAPINFO. + // + //==================================================================== + static bool IsExMy(const char * name) + { + // Only check for the first 3 episodes. They are the only ones with default intermission scripts. + // Level names can be upper- and lower case so use tolower to check! + return (tolower(name[0])=='e' && name[1]>='1' && name[1]<='3' && tolower(name[2])=='m'); } - lnodes.Clear(); - anims.Clear(); - yah.Clear(); - splat = NULL; + void WI_LoadBackground(bool isenterpic) + { + const char *lumpname = NULL; + char buffer[10]; + in_anim_t an; + lnode_t pt; + FTextureID texture; - // a name with a starting '$' indicates an intermission script - if (*lumpname!='$') - { - texture = TexMan.CheckForTexture(lumpname, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); - } - else - { - int lumpnum=Wads.CheckNumForFullName(lumpname+1, true); - if (lumpnum>=0) + bcnt=0; + + texture.SetInvalid(); + if (isenterpic) { - FScanner sc(lumpnum); - while (sc.GetString()) + level_info_t * li = FindLevelInfo(wbs->next); + if (li != NULL) lumpname = li->EnterPic; + } + else + { + lumpname = level.info->ExitPic; + } + + // Try to get a default if nothing specified + if (lumpname == NULL || lumpname[0]==0) + { + lumpname = NULL; + switch(gameinfo.gametype) { - memset(&an,0,sizeof(an)); - int caseval = sc.MustMatchString(WI_Cmd); - switch(caseval) + case GAME_Chex: + case GAME_Doom: + if (!(gameinfo.flags & GI_MAPxx)) { - case 0: // Background - sc.MustGetString(); - texture = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); - break; - - case 1: // Splat - sc.MustGetString(); - splat = TexMan[sc.String]; - break; - - case 2: // Pointers - while (sc.GetString() && !sc.Crossed) + const char *level = isenterpic ? wbs->next : wbs->current; + if (IsExMy(level)) { - yah.Push(TexMan[sc.String]); + mysnprintf(buffer, countof(buffer), "$IN_EPI%c", level[1]); + lumpname = buffer; } - if (sc.Crossed) - sc.UnGet(); - break; - - case 3: // Spots - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) + } + if (!lumpname) + { + if (isenterpic) { - sc.MustGetString(); - strncpy(pt.level, sc.String,8); - pt.level[8] = 0; - sc.MustGetNumber(); - pt.x = sc.Number; - sc.MustGetNumber(); - pt.y = sc.Number; - lnodes.Push(pt); - } - break; + // One special case needs to be handled here! + // If going from E1-E3 to E4 the default should be used, not the exit pic. - case 4: // IfEntering - an.type = ANIM_IFENTERING; - goto readanimation; + // Not if the exit pic is user defined! + if (level.info->ExitPic.IsNotEmpty()) return; - case 5: // IfEntering - an.type = ANIM_IFNOTENTERING; - goto readanimation; - - case 6: // IfVisited - an.type = ANIM_IFVISITED; - goto readanimation; - - case 7: // IfNotVisited - an.type = ANIM_IFNOTVISITED; - goto readanimation; - - case 8: // IfLeaving - an.type = ANIM_IFLEAVING; - goto readanimation; - - case 9: // IfNotLeaving - an.type = ANIM_IFNOTLEAVING; - goto readanimation; - - case 10: // IfTravelling - an.type = ANIM_IFTRAVELLING; - sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; - goto readanimation; - - case 11: // IfNotTravelling - an.type = ANIM_IFTRAVELLING; - sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; - goto readanimation; - - case 14: // NoAutostartMap - noautostartmap = true; - break; - - readanimation: - sc.MustGetString(); - strncpy(an.levelname, sc.String, 8); - an.levelname[8] = 0; - sc.MustGetString(); - caseval=sc.MustMatchString(WI_Cmd); - - default: - switch (caseval) - { - case 12: // Animation - an.type |= ANIM_ALWAYS; - sc.MustGetNumber(); - an.loc.x = sc.Number; - sc.MustGetNumber(); - an.loc.y = sc.Number; - sc.MustGetNumber(); - an.period = sc.Number; - an.nexttic = 1 + (M_Random() % an.period); - if (sc.GetString()) + // E1-E3 need special treatment when playing Doom 1. + if (!(gameinfo.flags & GI_MAPxx)) { - if (sc.Compare("ONCE")) + // not if the last level is not from the first 3 episodes + if (!IsExMy(wbs->current)) return; + + // not if the next level is one of the first 3 episodes + if (IsExMy(wbs->next)) return; + } + } + lumpname = "INTERPIC"; + } + break; + + case GAME_Heretic: + if (isenterpic) + { + if (IsExMy(wbs->next)) + { + mysnprintf(buffer, countof(buffer), "$IN_HTC%c", wbs->next[1]); + lumpname = buffer; + } + } + if (!lumpname) + { + if (isenterpic) return; + lumpname = "FLOOR16"; + } + break; + + case GAME_Hexen: + if (isenterpic) return; + lumpname = "INTERPIC"; + break; + + case GAME_Strife: + default: + // Strife doesn't have an intermission pic so choose something neutral. + if (isenterpic) return; + lumpname = gameinfo.BorderFlat; + break; + } + } + if (lumpname == NULL) + { + // shouldn't happen! + background = NULL; + return; + } + + lnodes.Clear(); + anims.Clear(); + yah.Clear(); + splat = NULL; + + // a name with a starting '$' indicates an intermission script + if (*lumpname!='$') + { + texture = TexMan.CheckForTexture(lumpname, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); + } + else + { + int lumpnum=Wads.CheckNumForFullName(lumpname+1, true); + if (lumpnum>=0) + { + FScanner sc(lumpnum); + while (sc.GetString()) + { + memset(&an,0,sizeof(an)); + int caseval = sc.MustMatchString(WI_Cmd); + switch(caseval) + { + case 0: // Background + sc.MustGetString(); + texture = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); + break; + + case 1: // Splat + sc.MustGetString(); + splat = TexMan[sc.String]; + break; + + case 2: // Pointers + while (sc.GetString() && !sc.Crossed) + { + yah.Push(TexMan[sc.String]); + } + if (sc.Crossed) + sc.UnGet(); + break; + + case 3: // Spots + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + strncpy(pt.level, sc.String,8); + pt.level[8] = 0; + sc.MustGetNumber(); + pt.x = sc.Number; + sc.MustGetNumber(); + pt.y = sc.Number; + lnodes.Push(pt); + } + break; + + case 4: // IfEntering + an.type = ANIM_IFENTERING; + goto readanimation; + + case 5: // IfEntering + an.type = ANIM_IFNOTENTERING; + goto readanimation; + + case 6: // IfVisited + an.type = ANIM_IFVISITED; + goto readanimation; + + case 7: // IfNotVisited + an.type = ANIM_IFNOTVISITED; + goto readanimation; + + case 8: // IfLeaving + an.type = ANIM_IFLEAVING; + goto readanimation; + + case 9: // IfNotLeaving + an.type = ANIM_IFNOTLEAVING; + goto readanimation; + + case 10: // IfTravelling + an.type = ANIM_IFTRAVELLING; + sc.MustGetString(); + strncpy(an.levelname2, sc.String, 8); + an.levelname2[8] = 0; + goto readanimation; + + case 11: // IfNotTravelling + an.type = ANIM_IFTRAVELLING; + sc.MustGetString(); + strncpy(an.levelname2, sc.String, 8); + an.levelname2[8] = 0; + goto readanimation; + + case 14: // NoAutostartMap + noautostartmap = true; + break; + + readanimation: + sc.MustGetString(); + strncpy(an.levelname, sc.String, 8); + an.levelname[8] = 0; + sc.MustGetString(); + caseval=sc.MustMatchString(WI_Cmd); + + default: + switch (caseval) + { + case 12: // Animation + an.type |= ANIM_ALWAYS; + sc.MustGetNumber(); + an.loc.x = sc.Number; + sc.MustGetNumber(); + an.loc.y = sc.Number; + sc.MustGetNumber(); + an.period = sc.Number; + an.nexttic = 1 + (M_Random() % an.period); + if (sc.GetString()) { - an.data = 1; + if (sc.Compare("ONCE")) + { + an.data = 1; + } + else + { + sc.UnGet(); + } + } + if (!sc.CheckString("{")) + { + sc.MustGetString(); + an.p[an.nanims++] = TexMan[sc.String]; } else { - sc.UnGet(); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (an.nanimstype & ANIM_TYPE) - { - case ANIM_ALWAYS: - if (bcnt >= a->nexttic) + else { - if (++a->ctr >= a->nanims) + Printf("Intermission script %s not found!\n", lumpname+1); + texture = TexMan.GetTexture("INTERPIC", FTexture::TEX_MiscPatch); + } + } + background=TexMan[texture]; + } + + //==================================================================== + // + // made this more generic and configurable through a script + // Removed all the ugly special case handling for different game modes + // + //==================================================================== + + void WI_updateAnimatedBack() + { + unsigned int i; + + for(i=0;itype & ANIM_TYPE) + { + case ANIM_ALWAYS: + if (bcnt >= a->nexttic) { - if (a->data==0) a->ctr = 0; - else a->ctr--; + if (++a->ctr >= a->nanims) + { + if (a->data==0) a->ctr = 0; + else a->ctr--; + } + a->nexttic = bcnt + a->period; } - a->nexttic = bcnt + a->period; + break; + + case ANIM_PIC: + a->ctr = 0; + break; + } - break; - - case ANIM_PIC: - a->ctr = 0; - break; - } } -} -//==================================================================== -// -// Draws the background including all animations -// -//==================================================================== + //==================================================================== + // + // Draws the background including all animations + // + //==================================================================== -void WI_drawBackground() -{ - unsigned int i; - double animwidth=320; // For a flat fill or clear background scale animations to 320x200 - double animheight=200; - - if (background) + void WI_drawBackground() { - // background - if (background->UseType == FTexture::TEX_MiscPatch) + unsigned int i; + double animwidth=320; // For a flat fill or clear background scale animations to 320x200 + double animheight=200; + + if (background) { - // scale all animations below to fit the size of the base pic - // The base pic is always scaled to fit the screen so this allows - // placing the animations precisely where they belong on the base pic - animwidth = background->GetScaledWidthDouble(); - animheight = background->GetScaledHeightDouble(); - screen->FillBorder (NULL); - screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); + // background + if (background->UseType == FTexture::TEX_MiscPatch) + { + // scale all animations below to fit the size of the base pic + // The base pic is always scaled to fit the screen so this allows + // placing the animations precisely where they belong on the base pic + animwidth = background->GetScaledWidthDouble(); + animheight = background->GetScaledHeightDouble(); + screen->FillBorder (NULL); + screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); + } + else + { + screen->FlatFill(0, 0, SCREENWIDTH, SCREENHEIGHT, background); + } } else { - screen->FlatFill(0, 0, SCREENWIDTH, SCREENHEIGHT, background); + screen->Clear(0,0, SCREENWIDTH, SCREENHEIGHT, 0, 0); } - } - else - { - screen->Clear(0,0, SCREENWIDTH, SCREENHEIGHT, 0, 0); - } - for(i=0;itype & ANIM_CONDITION) + for(i=0;ilevelname); - if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; - break; + in_anim_t * a = &anims[i]; + level_info_t * li; - case ANIM_IFNOTVISITED: - li = FindLevelInfo(a->levelname); - if (li == NULL || (li->flags & LEVEL_VISITED)) continue; - break; + switch (a->type & ANIM_CONDITION) + { + case ANIM_IFVISITED: + li = FindLevelInfo(a->levelname); + if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; + break; - // StatCount means 'leaving' - everything else means 'entering'! - case ANIM_IFENTERING: - if (state == StatCount || strnicmp(a->levelname, wbs->next, 8)) continue; - break; + case ANIM_IFNOTVISITED: + li = FindLevelInfo(a->levelname); + if (li == NULL || (li->flags & LEVEL_VISITED)) continue; + break; - case ANIM_IFNOTENTERING: - if (state != StatCount && !strnicmp(a->levelname, wbs->next, 8)) continue; - break; + // StatCount means 'leaving' - everything else means 'entering'! + case ANIM_IFENTERING: + if (state == StatCount || strnicmp(a->levelname, wbs->next, 8)) continue; + break; - case ANIM_IFLEAVING: - if (state != StatCount || strnicmp(a->levelname, wbs->current, 8)) continue; - break; + case ANIM_IFNOTENTERING: + if (state != StatCount && !strnicmp(a->levelname, wbs->next, 8)) continue; + break; - case ANIM_IFNOTLEAVING: - if (state == StatCount && !strnicmp(a->levelname, wbs->current, 8)) continue; - break; + case ANIM_IFLEAVING: + if (state != StatCount || strnicmp(a->levelname, wbs->current, 8)) continue; + break; - case ANIM_IFTRAVELLING: - if (strnicmp(a->levelname2, wbs->current, 8) || strnicmp(a->levelname, wbs->next, 8)) continue; - break; + case ANIM_IFNOTLEAVING: + if (state == StatCount && !strnicmp(a->levelname, wbs->current, 8)) continue; + break; - case ANIM_IFNOTTRAVELLING: - if (!strnicmp(a->levelname2, wbs->current, 8) && !strnicmp(a->levelname, wbs->next, 8)) continue; - break; + case ANIM_IFTRAVELLING: + if (strnicmp(a->levelname2, wbs->current, 8) || strnicmp(a->levelname, wbs->next, 8)) continue; + break; + + case ANIM_IFNOTTRAVELLING: + if (!strnicmp(a->levelname2, wbs->current, 8) && !strnicmp(a->levelname, wbs->next, 8)) continue; + break; + } + if (a->ctr >= 0) + screen->DrawTexture(a->p[a->ctr], a->loc.x, a->loc.y, + DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); } - if (a->ctr >= 0) - screen->DrawTexture(a->p[a->ctr], a->loc.x, a->loc.y, - DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); } -} -//==================================================================== -// -// Draws a single character with a shadow -// -//==================================================================== + //==================================================================== + // + // Draws a single character with a shadow + // + //==================================================================== -static int WI_DrawCharPatch (FFont *font, int charcode, int x, int y, EColorRange translation=CR_UNTRANSLATED, bool nomove=false) -{ - int width; - font->GetChar(charcode, &width); - screen->DrawChar(font, translation, x, y, charcode, - nomove ? DTA_CleanNoMove : DTA_Clean, true, - DTA_ShadowAlpha, (gameinfo.gametype & GAME_DoomChex) ? 0 : 0.5, - TAG_DONE); - return x - width; -} - -//==================================================================== -// -// CheckRealHeight -// -// Checks the posts in a texture and returns the lowest row (plus one) -// of the texture that is actually used. -// -//==================================================================== - -int CheckRealHeight(FTexture *tex) -{ - const FTexture::Span *span; - int maxy = 0, miny = tex->GetHeight(); - - for (int i = 0; i < tex->GetWidth(); ++i) + int WI_DrawCharPatch (FFont *font, int charcode, int x, int y, EColorRange translation=CR_UNTRANSLATED, bool nomove=false) { - tex->GetColumn(i, &span); - while (span->Length != 0) + int width; + font->GetChar(charcode, &width); + screen->DrawChar(font, translation, x, y, charcode, + nomove ? DTA_CleanNoMove : DTA_Clean, true, + DTA_ShadowAlpha, (gameinfo.gametype & GAME_DoomChex) ? 0 : 0.5, + TAG_DONE); + return x - width; + } + + //==================================================================== + // + // CheckRealHeight + // + // Checks the posts in a texture and returns the lowest row (plus one) + // of the texture that is actually used. + // + //==================================================================== + + int CheckRealHeight(FTexture *tex) + { + const FTexture::Span *span; + int maxy = 0, miny = tex->GetHeight(); + + for (int i = 0; i < tex->GetWidth(); ++i) { - if (span->TopOffset < miny) + tex->GetColumn(i, &span); + while (span->Length != 0) { - miny = span->TopOffset; + if (span->TopOffset < miny) + { + miny = span->TopOffset; + } + if (span->TopOffset + span->Length > maxy) + { + maxy = span->TopOffset + span->Length; + } + span++; } - if (span->TopOffset + span->Length > maxy) - { - maxy = span->TopOffset + span->Length; - } - span++; } + // Scale maxy before returning it + maxy = int((maxy *2) / tex->Scale.Y); + maxy = (maxy >> 1) + (maxy & 1); + return maxy; } - // Scale maxy before returning it - maxy = int((maxy *2) / tex->Scale.Y); - maxy = (maxy >> 1) + (maxy & 1); - return maxy; -} -//==================================================================== -// -// Draws a level name with the big font -// -// x is no longer passed as a parameter because the text is now broken into several lines -// if it is too long -// -//==================================================================== + //==================================================================== + // + // Draws a level name with the big font + // + // x is no longer passed as a parameter because the text is now broken into several lines + // if it is too long + // + //==================================================================== -int WI_DrawName(int y, FTexture *tex, const char *levelname) -{ - // draw - if (tex) + int WI_DrawName(int y, FTexture *tex, const char *levelname) { - screen->DrawTexture(tex, (screen->GetWidth() - tex->GetScaledWidth()*CleanXfac) /2, y, DTA_CleanNoMove, true, TAG_DONE); - int h = tex->GetScaledHeight(); - if (h > 50) - { // Fix for Deus Vult II and similar wads that decide to make these hugely tall - // patches with vast amounts of empty space at the bottom. - h = CheckRealHeight(tex); + // draw + if (tex) + { + screen->DrawTexture(tex, (screen->GetWidth() - tex->GetScaledWidth()*CleanXfac) /2, y, DTA_CleanNoMove, true, TAG_DONE); + int h = tex->GetScaledHeight(); + if (h > 50) + { // Fix for Deus Vult II and similar wads that decide to make these hugely tall + // patches with vast amounts of empty space at the bottom. + h = CheckRealHeight(tex); + } + return y + (h + BigFont->GetHeight()/4) * CleanYfac; + } + else + { + int i; + size_t l; + const char *p; + int h = 0; + int lumph; + + lumph = mapname.mFont->GetHeight() * CleanYfac; + + p = levelname; + if (!p) return 0; + l = strlen(p); + if (!l) return 0; + + FBrokenLines *lines = V_BreakLines(mapname.mFont, screen->GetWidth() / CleanXfac, p); + + if (lines) + { + for (i = 0; lines[i].Width >= 0; i++) + { + screen->DrawText(mapname.mFont, mapname.mColor, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h, + lines[i].Text, DTA_CleanNoMove, true, TAG_DONE); + h += lumph; + } + V_FreeBrokenLines(lines); + } + return y + h + lumph/4; } - return y + (h + BigFont->GetHeight()/4) * CleanYfac; } - else + + //==================================================================== + // + // Draws a text, either as patch or as string from the string table + // + //==================================================================== + + int WI_DrawPatchText(int y, FPatchInfo *pinfo, const char *stringname) + { + const char *string = GStrings(stringname); + int midx = screen->GetWidth() / 2; + + if (pinfo->mPatch != NULL) + { + screen->DrawTexture(pinfo->mPatch, midx - pinfo->mPatch->GetScaledWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE); + return y + (pinfo->mPatch->GetScaledHeight() * CleanYfac); + } + else + { + screen->DrawText(pinfo->mFont, pinfo->mColor, midx - pinfo->mFont->StringWidth(string)*CleanXfac/2, + y, string, DTA_CleanNoMove, true, TAG_DONE); + return y + pinfo->mFont->GetHeight() * CleanYfac; + } + } + + + //==================================================================== + // + // Draws " Finished!" + // + // Either uses the specified patch or the big font + // A level name patch can be specified for all games now, not just Doom. + // + //==================================================================== + + int WI_drawLF () + { + int y = WI_TITLEY * CleanYfac; + + y = WI_DrawName(y, wbs->LName0, lnametexts[0]); + + // Adjustment for different font sizes for map name and 'finished'. + y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4; + + // draw "Finished!" + if (y < (NG_STATSY - finished.mFont->GetHeight()*3/4) * CleanYfac) + { + // don't draw 'finished' if the level name is too tall + y = WI_DrawPatchText(y, &finished, "WI_FINISHED"); + } + return y; + } + + + //==================================================================== + // + // Draws "Entering " + // + // Either uses the specified patch or the big font + // A level name patch can be specified for all games now, not just Doom. + // + //==================================================================== + + void WI_drawEL () + { + int y = WI_TITLEY * CleanYfac; + + y = WI_DrawPatchText(y, &entering, "WI_ENTERING"); + y += entering.mFont->GetHeight() * CleanYfac / 4; + WI_DrawName(y, wbs->LName1, lnametexts[1]); + } + + + //==================================================================== + // + // Draws the splats and the 'You are here' arrows + // + //==================================================================== + + int WI_MapToIndex (const char *map) + { + unsigned int i; + + for (i = 0; i < lnodes.Size(); i++) + { + if (!strnicmp (lnodes[i].level, map, 8)) + break; + } + return i; + } + + + //==================================================================== + // + // Draws the splats and the 'You are here' arrows + // + //==================================================================== + + void WI_drawOnLnode( int n, FTexture * c[] ,int numc) + { + int i; + for(i=0;iGetScaledWidth(); + bottom = c[i]->GetScaledHeight(); + left = lnodes[n].x - c[i]->GetScaledLeftOffset(); + top = lnodes[n].y - c[i]->GetScaledTopOffset(); + right += left; + bottom += top; + + if (left >= 0 && right < 320 && top >= 0 && bottom < 200) + { + screen->DrawTexture (c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE); + break; + } + } + } + + //==================================================================== + // + // Draws a number. + // If digits > 0, then use that many digits minimum, + // otherwise only use as many as necessary. + // x is the right edge of the number. + // Returns new x position, that is, the left edge of the number. + // + //==================================================================== + int WI_drawNum (FFont *font, int x, int y, int n, int digits, bool leadingzeros=true, EColorRange translation=CR_UNTRANSLATED) + { + int fontwidth = font->GetCharWidth('3'); + char text[8]; + int len; + char *text_p; + bool nomove = font != IntermissionFont; + + if (nomove) + { + fontwidth *= CleanXfac; + } + if (leadingzeros) + { + len = mysnprintf (text, countof(text), "%0*d", digits, n); + } + else + { + len = mysnprintf (text, countof(text), "%d", n); + } + text_p = text + MIN(len, countof(text)-1); + + while (--text_p >= text) + { + // Digits are centered in a box the width of the '3' character. + // Other characters (specifically, '-') are right-aligned in their cell. + if (*text_p >= '0' && *text_p <= '9') + { + x -= fontwidth; + WI_DrawCharPatch(font, *text_p, x + (fontwidth - font->GetCharWidth(*text_p)) / 2, y, translation, nomove); + } + else + { + WI_DrawCharPatch(font, *text_p, x - font->GetCharWidth(*text_p), y, translation, nomove); + x -= fontwidth; + } + } + if (len < digits) + { + x -= fontwidth * (digits - len); + } + return x; + } + + //==================================================================== + // + // + // + //==================================================================== + + void WI_drawPercent (FFont *font, int x, int y, int p, int b, bool show_total=true, EColorRange color=CR_UNTRANSLATED) + { + if (p < 0) + return; + + if (wi_percents) + { + if (font != IntermissionFont) + { + x -= font->GetCharWidth('%') * CleanXfac; + } + else + { + x -= font->GetCharWidth('%'); + } + screen->DrawText(font, color, x, y, "%", font != IntermissionFont ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE); + if (font != IntermissionFont) + { + x -= 2*CleanXfac; + } + WI_drawNum(font, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color); + } + else + { + if (show_total) + { + x = WI_drawNum(font, x, y, b, 2, false); + x -= font->GetCharWidth('/'); + screen->DrawText (IntermissionFont, color, x, y, "/", + DTA_Clean, true, TAG_DONE); + } + WI_drawNum (font, x, y, p, -1, false, color); + } + } + + //==================================================================== + // + // Display level completion time and par, or "sucks" message if overflow. + // + //==================================================================== + void WI_drawTime (int x, int y, int t, bool no_sucks=false) + { + bool sucky; + + if (t<0) + return; + + sucky = !no_sucks && t >= wbs->sucktime * 60 * 60 && wbs->sucktime > 0; + + if (sucky) + { // "sucks" + if (sucks != NULL) + { + screen->DrawTexture (sucks, x - sucks->GetScaledWidth(), y - IntermissionFont->GetHeight() - 2, + DTA_Clean, true, TAG_DONE); + } + else + { + screen->DrawText (BigFont, CR_UNTRANSLATED, x - BigFont->StringWidth("SUCKS"), y - IntermissionFont->GetHeight() - 2, + "SUCKS", DTA_Clean, true, TAG_DONE); + } + } + + int hours = t / 3600; + t -= hours * 3600; + int minutes = t / 60; + t -= minutes * 60; + int seconds = t; + + // Why were these offsets hard coded? Half the WADs with custom patches + // I tested screwed up miserably in this function! + int num_spacing = IntermissionFont->GetCharWidth('3'); + int colon_spacing = IntermissionFont->GetCharWidth(':'); + + x = WI_drawNum (IntermissionFont, x, y, seconds, 2) - 1; + WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); + x = WI_drawNum (IntermissionFont, x, y, minutes, 2, hours!=0); + if (hours) + { + WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); + WI_drawNum (IntermissionFont, x, y, hours, 2); + } + } + + void WI_End () + { + state = LeavingIntermission; + WI_unloadData (); + + //Added by mc + if (deathmatch) + { + bglobal.RemoveAllBots (consoleplayer != Net_Arbitrator); + } + } + + bool WI_autoSkip() + { + return wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE); + } + + void WI_initNoState () + { + state = NoState; + acceleratestage = 0; + cnt = 10; + } + + void WI_updateNoState () + { + WI_updateAnimatedBack(); + + if (acceleratestage) + { + cnt = 0; + } + else + { + bool noauto = noautostartmap; + bool autoskip = WI_autoSkip(); + + for (int i = 0; !noauto && i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + noauto |= players[i].userinfo.GetNoAutostartMap(); + } + } + if (!noauto || autoskip) + { + cnt--; + } + } + + if (cnt == 0) + { + WI_End(); + G_WorldDone(); + } + } + + + void WI_initShowNextLoc () + { + if (wbs->next_ep == -1) + { + // Last map in episode - there is no next location! + WI_End(); + G_WorldDone(); + return; + } + + state = ShowNextLoc; + acceleratestage = 0; + cnt = SHOWNEXTLOCDELAY * TICRATE; + WI_LoadBackground(true); + } + + void WI_updateShowNextLoc () + { + WI_updateAnimatedBack(); + + if (!--cnt || acceleratestage) + WI_initNoState(); + else + snl_pointeron = (cnt & 31) < 20; + } + + void WI_drawShowNextLoc(void) + { + unsigned int i; + + WI_drawBackground(); + + if (splat) + { + for (i=0 ; iflags & LEVEL_VISITED) WI_drawOnLnode(i, &splat,1); // draw a splat on taken cities. + } + } + + // draw flashing ptr + if (snl_pointeron && yah.Size()) + { + unsigned int v = WI_MapToIndex (wbs->next); + // Draw only if it points to a valid level on the current screen! + if (vGetHeight() * CleanYfac; - - p = levelname; - if (!p) return 0; - l = strlen(p); - if (!l) return 0; - - FBrokenLines *lines = V_BreakLines(mapname.mFont, screen->GetWidth() / CleanXfac, p); - - if (lines) - { - for (i = 0; lines[i].Width >= 0; i++) - { - screen->DrawText(mapname.mFont, mapname.mColor, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h, - lines[i].Text, DTA_CleanNoMove, true, TAG_DONE); - h += lumph; - } - V_FreeBrokenLines(lines); - } - return y + h + lumph/4; - } -} - -//==================================================================== -// -// Draws a text, either as patch or as string from the string table -// -//==================================================================== - -int WI_DrawPatchText(int y, FPatchInfo *pinfo, const char *stringname) -{ - const char *string = GStrings(stringname); - int midx = screen->GetWidth() / 2; - - if (pinfo->mPatch != NULL) - { - screen->DrawTexture(pinfo->mPatch, midx - pinfo->mPatch->GetScaledWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE); - return y + (pinfo->mPatch->GetScaledHeight() * CleanYfac); - } - else - { - screen->DrawText(pinfo->mFont, pinfo->mColor, midx - pinfo->mFont->StringWidth(string)*CleanXfac/2, - y, string, DTA_CleanNoMove, true, TAG_DONE); - return y + pinfo->mFont->GetHeight() * CleanYfac; - } -} - - -//==================================================================== -// -// Draws " Finished!" -// -// Either uses the specified patch or the big font -// A level name patch can be specified for all games now, not just Doom. -// -//==================================================================== - -int WI_drawLF () -{ - int y = WI_TITLEY * CleanYfac; - - y = WI_DrawName(y, wbs->LName0, lnametexts[0]); + int frags = 0; - // Adjustment for different font sizes for map name and 'finished'. - y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4; - - // draw "Finished!" - if (y < (NG_STATSY - finished.mFont->GetHeight()*3/4) * CleanYfac) - { - // don't draw 'finished' if the level name is too tall - y = WI_DrawPatchText(y, &finished, "WI_FINISHED"); - } - return y; -} - - -//==================================================================== -// -// Draws "Entering " -// -// Either uses the specified patch or the big font -// A level name patch can be specified for all games now, not just Doom. -// -//==================================================================== - -void WI_drawEL () -{ - int y = WI_TITLEY * CleanYfac; - - y = WI_DrawPatchText(y, &entering, "WI_ENTERING"); - y += entering.mFont->GetHeight() * CleanYfac / 4; - WI_DrawName(y, wbs->LName1, lnametexts[1]); -} - - -//==================================================================== -// -// Draws the splats and the 'You are here' arrows -// -//==================================================================== - -int WI_MapToIndex (const char *map) -{ - unsigned int i; - - for (i = 0; i < lnodes.Size(); i++) - { - if (!strnicmp (lnodes[i].level, map, 8)) - break; - } - return i; -} - - -//==================================================================== -// -// Draws the splats and the 'You are here' arrows -// -//==================================================================== - -void WI_drawOnLnode( int n, FTexture * c[] ,int numc) -{ - int i; - for(i=0;iGetScaledWidth(); - bottom = c[i]->GetScaledHeight(); - left = lnodes[n].x - c[i]->GetScaledLeftOffset(); - top = lnodes[n].y - c[i]->GetScaledTopOffset(); - right += left; - bottom += top; + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] + && i!=playernum) + { + frags += plrs[playernum].frags[i]; + } + } - if (left >= 0 && right < 320 && top >= 0 && bottom < 200) - { - screen->DrawTexture (c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE); - break; - } - } -} + // JDC hack - negative frags. + frags -= plrs[playernum].frags[playernum]; -//==================================================================== -// -// Draws a number. -// If digits > 0, then use that many digits minimum, -// otherwise only use as many as necessary. -// x is the right edge of the number. -// Returns new x position, that is, the left edge of the number. -// -//==================================================================== -int WI_drawNum (FFont *font, int x, int y, int n, int digits, bool leadingzeros=true, EColorRange translation=CR_UNTRANSLATED) -{ - int fontwidth = font->GetCharWidth('3'); - char text[8]; - int len; - char *text_p; - bool nomove = font != IntermissionFont; - - if (nomove) - { - fontwidth *= CleanXfac; - } - if (leadingzeros) - { - len = mysnprintf (text, countof(text), "%0*d", digits, n); - } - else - { - len = mysnprintf (text, countof(text), "%d", n); - } - text_p = text + MIN(len, countof(text)-1); - - while (--text_p >= text) - { - // Digits are centered in a box the width of the '3' character. - // Other characters (specifically, '-') are right-aligned in their cell. - if (*text_p >= '0' && *text_p <= '9') - { - x -= fontwidth; - WI_DrawCharPatch(font, *text_p, x + (fontwidth - font->GetCharWidth(*text_p)) / 2, y, translation, nomove); - } - else - { - WI_DrawCharPatch(font, *text_p, x - font->GetCharWidth(*text_p), y, translation, nomove); - x -= fontwidth; - } - } - if (len < digits) - { - x -= fontwidth * (digits - len); - } - return x; -} - -//==================================================================== -// -// -// -//==================================================================== - -void WI_drawPercent (FFont *font, int x, int y, int p, int b, bool show_total=true, EColorRange color=CR_UNTRANSLATED) -{ - if (p < 0) - return; - - if (wi_percents) - { - if (font != IntermissionFont) - { - x -= font->GetCharWidth('%') * CleanXfac; - } - else - { - x -= font->GetCharWidth('%'); - } - screen->DrawText(font, color, x, y, "%", font != IntermissionFont ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE); - if (font != IntermissionFont) - { - x -= 2*CleanXfac; - } - WI_drawNum(font, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color); - } - else - { - if (show_total) - { - x = WI_drawNum(font, x, y, b, 2, false); - x -= font->GetCharWidth('/'); - screen->DrawText (IntermissionFont, color, x, y, "/", - DTA_Clean, true, TAG_DONE); - } - WI_drawNum (font, x, y, p, -1, false, color); - } -} - -//==================================================================== -// -// Display level completion time and par, or "sucks" message if overflow. -// -//==================================================================== -void WI_drawTime (int x, int y, int t, bool no_sucks=false) -{ - bool sucky; - - if (t<0) - return; - - sucky = !no_sucks && t >= wbs->sucktime * 60 * 60 && wbs->sucktime > 0; - - if (sucky) - { // "sucks" - if (sucks != NULL) - { - screen->DrawTexture (sucks, x - sucks->GetScaledWidth(), y - IntermissionFont->GetHeight() - 2, - DTA_Clean, true, TAG_DONE); - } - else - { - screen->DrawText (BigFont, CR_UNTRANSLATED, x - BigFont->StringWidth("SUCKS"), y - IntermissionFont->GetHeight() - 2, - "SUCKS", DTA_Clean, true, TAG_DONE); - } + return frags; } - int hours = t / 3600; - t -= hours * 3600; - int minutes = t / 60; - t -= minutes * 60; - int seconds = t; - // Why were these offsets hard coded? Half the WADs with custom patches - // I tested screwed up miserably in this function! - int num_spacing = IntermissionFont->GetCharWidth('3'); - int colon_spacing = IntermissionFont->GetCharWidth(':'); - - x = WI_drawNum (IntermissionFont, x, y, seconds, 2) - 1; - WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); - x = WI_drawNum (IntermissionFont, x, y, minutes, 2, hours!=0); - if (hours) + void WI_initDeathmatchStats (void) { - WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); - WI_drawNum (IntermissionFont, x, y, hours, 2); - } -} + int i, j; -void WI_End () -{ - state = LeavingIntermission; - WI_unloadData (); + state = StatCount; + acceleratestage = 0; + memset(playerready, 0, sizeof(playerready)); + memset(cnt_frags, 0, sizeof(cnt_frags)); + memset(cnt_deaths, 0, sizeof(cnt_deaths)); + memset(player_deaths, 0, sizeof(player_deaths)); + total_frags = 0; + total_deaths = 0; - //Added by mc - if (deathmatch) - { - bglobal.RemoveAllBots (consoleplayer != Net_Arbitrator); - } -} + ng_state = 1; + cnt_pause = TICRATE; -bool WI_autoSkip() -{ - return wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE); -} - -void WI_initNoState () -{ - state = NoState; - acceleratestage = 0; - cnt = 10; -} - -void WI_updateNoState () -{ - WI_updateAnimatedBack(); - - if (acceleratestage) - { - cnt = 0; - } - else - { - bool noauto = noautostartmap; - bool autoskip = WI_autoSkip(); - - for (int i = 0; !noauto && i < MAXPLAYERS; ++i) + for (i=0 ; inext_ep == -1) - { - // Last map in episode - there is no next location! - WI_End(); - G_WorldDone(); - return; - } - - state = ShowNextLoc; - acceleratestage = 0; - cnt = SHOWNEXTLOCDELAY * TICRATE; - WI_LoadBackground(true); -} - -void WI_updateShowNextLoc () -{ - WI_updateAnimatedBack(); - - if (!--cnt || acceleratestage) - WI_initNoState(); - else - snl_pointeron = (cnt & 31) < 20; -} - -void WI_drawShowNextLoc(void) -{ - unsigned int i; - - WI_drawBackground(); - - if (splat) - { - for (i=0 ; iflags & LEVEL_VISITED) WI_drawOnLnode(i, &splat,1); // draw a splat on taken cities. - } - } - - // draw flashing ptr - if (snl_pointeron && yah.Size()) - { - unsigned int v = WI_MapToIndex (wbs->next); - // Draw only if it points to a valid level on the current screen! - if (v plrs[i].fragcount) cnt_frags[i] = plrs[i].fragcount; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 4) - { - if (!(bcnt & 3)) - S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i = 0; i player_deaths[i]) cnt_deaths[i] = player_deaths[i]; - else - stillticking = true; - } - if (!stillticking) - { + } S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; + ng_state = 6; + } + + if (ng_state == 2) + { + if (!(bcnt & 3)) + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i = 0; i plrs[i].fragcount) + cnt_frags[i] = plrs[i].fragcount; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 4) + { + if (!(bcnt & 3)) + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i = 0; i player_deaths[i]) + cnt_deaths[i] = player_deaths[i]; + else + stillticking = true; + } + if (!stillticking) + { + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 6) + { + int i; + for (i = 0; i < MAXPLAYERS; i++) + { + // If the player is in the game and not ready, stop checking + if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) + break; + } + + // All players are ready; proceed. + if ((i == MAXPLAYERS && acceleratestage) || autoskip) + { + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE); + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } } } - else if (ng_state == 6) + + + + void WI_drawDeathmatchStats () { - int i; + int i, pnum, x, y, ypadding, height, lineheight; + int maxnamewidth, maxscorewidth, maxiconheight; + int pwidth = IntermissionFont->GetCharWidth('%'); + int icon_x, name_x, frags_x, deaths_x; + int deaths_len; + float h, s, v, r, g, b; + EColorRange color; + const char *text_deaths, *text_frags; + FTexture *readyico = TexMan.FindTexture("READYICO"); + player_t *sortedplayers[MAXPLAYERS]; + + // draw animated background + WI_drawBackground(); + + y = WI_drawLF(); + + HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); + // Use the readyico height if it's bigger. + height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); + maxiconheight = MAX(height, maxiconheight); + height = SmallFont->GetHeight() * CleanYfac; + lineheight = MAX(height, maxiconheight * CleanYfac); + ypadding = (lineheight - height + 1) / 2; + y += CleanYfac; + + text_deaths = GStrings("SCORE_DEATHS"); + //text_color = GStrings("SCORE_COLOR"); + text_frags = GStrings("SCORE_FRAGS"); + + icon_x = 8 * CleanXfac; + name_x = icon_x + maxscorewidth * CleanXfac; + frags_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_frags)) + 8) * CleanXfac; + deaths_x = frags_x + ((deaths_len = SmallFont->StringWidth(text_deaths)) + 8) * CleanXfac; + + x = (SCREENWIDTH - deaths_x) >> 1; + icon_x += x; + name_x += x; + frags_x += x; + deaths_x += x; + + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, frags_x - SmallFont->StringWidth(text_frags)*CleanXfac, y, text_frags, DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, deaths_x - deaths_len*CleanXfac, y, text_deaths, DTA_CleanNoMove, true, TAG_DONE); + y += height + 6 * CleanYfac; + + // Sort all players for (i = 0; i < MAXPLAYERS; i++) { - // If the player is in the game and not ready, stop checking - if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) - break; + sortedplayers[i] = &players[i]; } - // All players are ready; proceed. - if ((i == MAXPLAYERS && acceleratestage) || autoskip) - { - S_Sound(CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE); - WI_initShowNextLoc(); - } - } - else if (ng_state & 1) - { - if (!--cnt_pause) - { - ng_state++; - cnt_pause = TICRATE; - } - } -} + if (teamplay) + qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams); + else + qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints); - - -void WI_drawDeathmatchStats () -{ - int i, pnum, x, y, ypadding, height, lineheight; - int maxnamewidth, maxscorewidth, maxiconheight; - int pwidth = IntermissionFont->GetCharWidth('%'); - int icon_x, name_x, frags_x, deaths_x; - int deaths_len; - float h, s, v, r, g, b; - EColorRange color; - const char *text_deaths, *text_frags; - FTexture *readyico = TexMan.FindTexture("READYICO"); - player_t *sortedplayers[MAXPLAYERS]; - - // draw animated background - WI_drawBackground(); - - y = WI_drawLF(); - - HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); - // Use the readyico height if it's bigger. - height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); - maxiconheight = MAX(height, maxiconheight); - height = SmallFont->GetHeight() * CleanYfac; - lineheight = MAX(height, maxiconheight * CleanYfac); - ypadding = (lineheight - height + 1) / 2; - y += CleanYfac; - - text_deaths = GStrings("SCORE_DEATHS"); - //text_color = GStrings("SCORE_COLOR"); - text_frags = GStrings("SCORE_FRAGS"); - - icon_x = 8 * CleanXfac; - name_x = icon_x + maxscorewidth * CleanXfac; - frags_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_frags)) + 8) * CleanXfac; - deaths_x = frags_x + ((deaths_len = SmallFont->StringWidth(text_deaths)) + 8) * CleanXfac; - - x = (SCREENWIDTH - deaths_x) >> 1; - icon_x += x; - name_x += x; - frags_x += x; - deaths_x += x; - - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, frags_x - SmallFont->StringWidth(text_frags)*CleanXfac, y, text_frags, DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, deaths_x - deaths_len*CleanXfac, y, text_deaths, DTA_CleanNoMove, true, TAG_DONE); - y += height + 6 * CleanYfac; - - // Sort all players - for (i = 0; i < MAXPLAYERS; i++) - { - sortedplayers[i] = &players[i]; - } - - if (teamplay) - qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams); - else - qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints); - - // Draw lines for each player - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *player = sortedplayers[i]; - pnum = int(player - players); - - if (!playeringame[pnum]) - continue; - - D_GetPlayerColor(pnum, &h, &s, &v, NULL); - HSVtoRGB(&r, &g, &b, h, s, v); - - screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), - clamp(int(g*255.f), 0, 255), - clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (deaths_x - x) + (8 * CleanXfac), lineheight); - - if (playerready[pnum] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion - screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); - - color = (EColorRange)HU_GetRowColor(player, pnum == consoleplayer); - if (player->mo->ScoreIcon.isValid()) - { - FTexture *pic = TexMan[player->mo->ScoreIcon]; - screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); - } - screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); - WI_drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, color); - if (ng_state >= 2) - { - WI_drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, color); - } - y += lineheight + CleanYfac; - } - - // Draw "TOTAL" line - y += height + 3 * CleanYfac; - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); - WI_drawNum(SmallFont, frags_x, y, total_frags, 0, false, color); - if (ng_state >= 4) - { - WI_drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, color); - } - - // Draw game time - y += height + CleanYfac; - - int seconds = Tics2Seconds(plrs[me].stime); - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - seconds = seconds % 60; - - FString leveltime = GStrings("SCORE_LVLTIME"); - leveltime += ": "; - - char timer[sizeof "HH:MM:SS"]; - mysnprintf(timer, sizeof(timer), "%02i:%02i:%02i", hours, minutes, seconds); - leveltime += timer; - - screen->DrawText(SmallFont, color, x, y, leveltime, DTA_CleanNoMove, true, TAG_DONE); -} - -void WI_initNetgameStats () -{ - - int i; - - state = StatCount; - acceleratestage = 0; - memset(playerready, 0, sizeof(playerready)); - ng_state = 1; - - cnt_pause = TICRATE; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0; - - dofrags += WI_fragSum (i); - } - - dofrags = !!dofrags; -} - -void WI_updateNetgameStats () -{ - - int i; - int fsum; - bool stillticking; - bool autoskip = WI_autoSkip(); - - WI_updateAnimatedBack (); - - if ((acceleratestage || autoskip) && ng_state != 10) - { - acceleratestage = 0; - - for (i=0 ; i plrs[i].skills) - cnt_kills[i] = plrs[i].skills; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 4) - { - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i=0 ; i plrs[i].sitems) - cnt_items[i] = plrs[i].sitems; - else - stillticking = true; - } - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 6) - { - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i=0 ; i plrs[i].ssecret) - cnt_secret[i] = plrs[i].ssecret; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state += 1 + 2*!dofrags; - } - } - else if (ng_state == 8) - { - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i=0 ; i= (fsum = WI_fragSum(i))) - cnt_frags[i] = fsum; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/cooptotal", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 10) - { - int i; + // Draw lines for each player for (i = 0; i < MAXPLAYERS; i++) { - // If the player is in the game and not ready, stop checking - if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) - break; + player_t *player = sortedplayers[i]; + pnum = int(player - players); + + if (!playeringame[pnum]) + continue; + + D_GetPlayerColor(pnum, &h, &s, &v, NULL); + HSVtoRGB(&r, &g, &b, h, s, v); + + screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), + clamp(int(g*255.f), 0, 255), + clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (deaths_x - x) + (8 * CleanXfac), lineheight); + + if (playerready[pnum] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion + screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); + + color = (EColorRange)HU_GetRowColor(player, pnum == consoleplayer); + if (player->mo->ScoreIcon.isValid()) + { + FTexture *pic = TexMan[player->mo->ScoreIcon]; + screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); + } + screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); + WI_drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, color); + if (ng_state >= 2) + { + WI_drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, color); + } + y += lineheight + CleanYfac; } - // All players are ready; proceed. - if ((i == MAXPLAYERS && acceleratestage) || autoskip) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE); - WI_initShowNextLoc(); - } - } - else if (ng_state & 1) - { - if (!--cnt_pause) - { - ng_state++; - cnt_pause = TICRATE; - } - } -} - -void WI_drawNetgameStats () -{ - int i, x, y, ypadding, height, lineheight; - int maxnamewidth, maxscorewidth, maxiconheight; - int pwidth = IntermissionFont->GetCharWidth('%'); - int icon_x, name_x, kills_x, bonus_x, secret_x; - int bonus_len, secret_len; - int missed_kills, missed_items, missed_secrets; - float h, s, v, r, g, b; - EColorRange color; - const char *text_bonus, *text_secret, *text_kills; - FTexture *readyico = TexMan.FindTexture("READYICO"); - - // draw animated background - WI_drawBackground(); - - y = WI_drawLF(); - - HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); - // Use the readyico height if it's bigger. - height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); - if (height > maxiconheight) - { - maxiconheight = height; - } - height = SmallFont->GetHeight() * CleanYfac; - lineheight = MAX(height, maxiconheight * CleanYfac); - ypadding = (lineheight - height + 1) / 2; - y += CleanYfac; - - text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS"); - text_secret = GStrings("SCORE_SECRET"); - text_kills = GStrings("SCORE_KILLS"); - - icon_x = 8 * CleanXfac; - name_x = icon_x + maxscorewidth * CleanXfac; - kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac; - bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac; - secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac; - - x = (SCREENWIDTH - secret_x) >> 1; - icon_x += x; - name_x += x; - kills_x += x; - bonus_x += x; - secret_x += x; - - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true, TAG_DONE); - y += height + 6 * CleanYfac; - - missed_kills = wbs->maxkills; - missed_items = wbs->maxitems; - missed_secrets = wbs->maxsecret; - - // Draw lines for each player - for (i = 0; i < MAXPLAYERS; ++i) - { - player_t *player; - - if (!playeringame[i]) - continue; - - player = &players[i]; - - D_GetPlayerColor(i, &h, &s, &v, NULL); - HSVtoRGB(&r, &g, &b, h, s, v); - - screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), - clamp(int(g*255.f), 0, 255), - clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (secret_x - x) + (8 * CleanXfac), lineheight); - - if (playerready[i] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion - screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); - - color = (EColorRange)HU_GetRowColor(player, i == consoleplayer); - if (player->mo->ScoreIcon.isValid()) - { - FTexture *pic = TexMan[player->mo->ScoreIcon]; - screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); - } - screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); - WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color); - missed_kills -= cnt_kills[i]; + // Draw "TOTAL" line + y += height + 3 * CleanYfac; + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); + WI_drawNum(SmallFont, frags_x, y, total_frags, 0, false, color); if (ng_state >= 4) { - WI_drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs->maxitems, false, color); - missed_items -= cnt_items[i]; - if (ng_state >= 6) + WI_drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, color); + } + + // Draw game time + y += height + CleanYfac; + + int seconds = Tics2Seconds(plrs[me].stime); + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + seconds = seconds % 60; + + FString leveltime = GStrings("SCORE_LVLTIME"); + leveltime += ": "; + + char timer[sizeof "HH:MM:SS"]; + mysnprintf(timer, sizeof(timer), "%02i:%02i:%02i", hours, minutes, seconds); + leveltime += timer; + + screen->DrawText(SmallFont, color, x, y, leveltime, DTA_CleanNoMove, true, TAG_DONE); + } + + void WI_initNetgameStats () + { + + int i; + + state = StatCount; + acceleratestage = 0; + memset(playerready, 0, sizeof(playerready)); + ng_state = 1; + + cnt_pause = TICRATE; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0; + + dofrags += WI_fragSum (i); + } + + dofrags = !!dofrags; + } + + void WI_updateNetgameStats () + { + + int i; + int fsum; + bool stillticking; + bool autoskip = WI_autoSkip(); + + WI_updateAnimatedBack (); + + if ((acceleratestage || autoskip) && ng_state != 10) + { + acceleratestage = 0; + + for (i=0 ; imaxsecret, false, color); - missed_secrets -= cnt_secret[i]; + if (!playeringame[i]) + continue; + + cnt_kills[i] = plrs[i].skills; + cnt_items[i] = plrs[i].sitems; + cnt_secret[i] = plrs[i].ssecret; + + if (dofrags) + cnt_frags[i] = WI_fragSum (i); + } + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state = 10; + } + + if (ng_state == 2) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i=0 ; i plrs[i].skills) + cnt_kills[i] = plrs[i].skills; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; } } - y += lineheight + CleanYfac; - } - - // Draw "MISSED" line - y += 3 * CleanYfac; - screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE); - WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY); - if (ng_state >= 4) - { - WI_drawPercent(SmallFont, bonus_x, y, missed_items, wbs->maxitems, false, CR_DARKGRAY); - if (ng_state >= 6) - { - WI_drawPercent(SmallFont, secret_x, y, missed_secrets, wbs->maxsecret, false, CR_DARKGRAY); - } - } - - // Draw "TOTAL" line - y += height + 3 * CleanYfac; - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); - WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color); - if (ng_state >= 4) - { - WI_drawNum(SmallFont, bonus_x, y, wbs->maxitems, 0, false, color); - if (ng_state >= 6) - { - WI_drawNum(SmallFont, secret_x, y, wbs->maxsecret, 0, false, color); - } - } -} - -static int sp_state; - -void WI_initStats () -{ - state = StatCount; - acceleratestage = 0; - sp_state = 1; - cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1; - cnt_time = cnt_par = -1; - cnt_pause = TICRATE; - - cnt_total_time = -1; -} - -void WI_updateStats () -{ - WI_updateAnimatedBack (); - - if (acceleratestage && sp_state != 10) - { - acceleratestage = 0; - sp_state = 10; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - - cnt_kills[0] = plrs[me].skills; - cnt_items[0] = plrs[me].sitems; - cnt_secret[0] = plrs[me].ssecret; - cnt_time = Tics2Seconds(plrs[me].stime); - cnt_par = wbs->partime / TICRATE; - cnt_total_time = Tics2Seconds(wbs->totaltime); - } - - if (sp_state == 2) - { - if (gameinfo.intermissioncounter) - { - cnt_kills[0] += 2; - - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - } - if (!gameinfo.intermissioncounter || cnt_kills[0] >= plrs[me].skills) - { - cnt_kills[0] = plrs[me].skills; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - sp_state++; - } - } - else if (sp_state == 4) - { - if (gameinfo.intermissioncounter) - { - cnt_items[0] += 2; - - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - } - if (!gameinfo.intermissioncounter || cnt_items[0] >= plrs[me].sitems) - { - cnt_items[0] = plrs[me].sitems; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - sp_state++; - } - } - else if (sp_state == 6) - { - if (gameinfo.intermissioncounter) - { - cnt_secret[0] += 2; - - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - } - if (!gameinfo.intermissioncounter || cnt_secret[0] >= plrs[me].ssecret) - { - cnt_secret[0] = plrs[me].ssecret; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - sp_state++; - } - } - else if (sp_state == 8) - { - if (gameinfo.intermissioncounter) + else if (ng_state == 4) { if (!(bcnt&3)) S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - cnt_time += 3; - cnt_par += 3; - cnt_total_time += 3; - } + stillticking = false; - int sec = Tics2Seconds(plrs[me].stime); - if (!gameinfo.intermissioncounter || cnt_time >= sec) - cnt_time = sec; - - int tsec = Tics2Seconds(wbs->totaltime); - if (!gameinfo.intermissioncounter || cnt_total_time >= tsec) - cnt_total_time = tsec; - - if (!gameinfo.intermissioncounter || cnt_par >= wbs->partime / TICRATE) - { - cnt_par = wbs->partime / TICRATE; - - if (cnt_time >= sec) + for (i=0 ; i plrs[i].sitems) + cnt_items[i] = plrs[i].sitems; + else + stillticking = true; + } + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 6) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i=0 ; i plrs[i].ssecret) + cnt_secret[i] = plrs[i].ssecret; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state += 1 + 2*!dofrags; + } + } + else if (ng_state == 8) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i=0 ; i= (fsum = WI_fragSum(i))) + cnt_frags[i] = fsum; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/cooptotal", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 10) + { + int i; + for (i = 0; i < MAXPLAYERS; i++) + { + // If the player is in the game and not ready, stop checking + if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) + break; + } + + // All players are ready; proceed. + if ((i == MAXPLAYERS && acceleratestage) || autoskip) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE); + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } + } + } + + void WI_drawNetgameStats () + { + int i, x, y, ypadding, height, lineheight; + int maxnamewidth, maxscorewidth, maxiconheight; + int pwidth = IntermissionFont->GetCharWidth('%'); + int icon_x, name_x, kills_x, bonus_x, secret_x; + int bonus_len, secret_len; + int missed_kills, missed_items, missed_secrets; + float h, s, v, r, g, b; + EColorRange color; + const char *text_bonus, *text_secret, *text_kills; + FTexture *readyico = TexMan.FindTexture("READYICO"); + + // draw animated background + WI_drawBackground(); + + y = WI_drawLF(); + + HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); + // Use the readyico height if it's bigger. + height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); + if (height > maxiconheight) + { + maxiconheight = height; + } + height = SmallFont->GetHeight() * CleanYfac; + lineheight = MAX(height, maxiconheight * CleanYfac); + ypadding = (lineheight - height + 1) / 2; + y += CleanYfac; + + text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS"); + text_secret = GStrings("SCORE_SECRET"); + text_kills = GStrings("SCORE_KILLS"); + + icon_x = 8 * CleanXfac; + name_x = icon_x + maxscorewidth * CleanXfac; + kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac; + bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac; + secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac; + + x = (SCREENWIDTH - secret_x) >> 1; + icon_x += x; + name_x += x; + kills_x += x; + bonus_x += x; + secret_x += x; + + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true, TAG_DONE); + y += height + 6 * CleanYfac; + + missed_kills = wbs->maxkills; + missed_items = wbs->maxitems; + missed_secrets = wbs->maxsecret; + + // Draw lines for each player + for (i = 0; i < MAXPLAYERS; ++i) + { + player_t *player; + + if (!playeringame[i]) + continue; + + player = &players[i]; + + D_GetPlayerColor(i, &h, &s, &v, NULL); + HSVtoRGB(&r, &g, &b, h, s, v); + + screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), + clamp(int(g*255.f), 0, 255), + clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (secret_x - x) + (8 * CleanXfac), lineheight); + + if (playerready[i] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion + screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); + + color = (EColorRange)HU_GetRowColor(player, i == consoleplayer); + if (player->mo->ScoreIcon.isValid()) + { + FTexture *pic = TexMan[player->mo->ScoreIcon]; + screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); + } + screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); + WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color); + missed_kills -= cnt_kills[i]; + if (ng_state >= 4) + { + WI_drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs->maxitems, false, color); + missed_items -= cnt_items[i]; + if (ng_state >= 6) + { + WI_drawPercent(SmallFont, secret_x, y + ypadding, cnt_secret[i], wbs->maxsecret, false, color); + missed_secrets -= cnt_secret[i]; + } + } + y += lineheight + CleanYfac; + } + + // Draw "MISSED" line + y += 3 * CleanYfac; + screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE); + WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY); + if (ng_state >= 4) + { + WI_drawPercent(SmallFont, bonus_x, y, missed_items, wbs->maxitems, false, CR_DARKGRAY); + if (ng_state >= 6) + { + WI_drawPercent(SmallFont, secret_x, y, missed_secrets, wbs->maxsecret, false, CR_DARKGRAY); + } + } + + // Draw "TOTAL" line + y += height + 3 * CleanYfac; + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); + WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color); + if (ng_state >= 4) + { + WI_drawNum(SmallFont, bonus_x, y, wbs->maxitems, 0, false, color); + if (ng_state >= 6) + { + WI_drawNum(SmallFont, secret_x, y, wbs->maxsecret, 0, false, color); + } + } + } + + + void WI_initStats () + { + state = StatCount; + acceleratestage = 0; + sp_state = 1; + cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1; + cnt_time = cnt_par = -1; + cnt_pause = TICRATE; + + cnt_total_time = -1; + } + + void WI_updateStats () + { + WI_updateAnimatedBack (); + + if (acceleratestage && sp_state != 10) + { + acceleratestage = 0; + sp_state = 10; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + + cnt_kills[0] = plrs[me].skills; + cnt_items[0] = plrs[me].sitems; + cnt_secret[0] = plrs[me].ssecret; + cnt_time = Tics2Seconds(plrs[me].stime); + cnt_par = wbs->partime / TICRATE; + cnt_total_time = Tics2Seconds(wbs->totaltime); + } + + if (sp_state == 2) + { + if (gameinfo.intermissioncounter) + { + cnt_kills[0] += 2; + + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + } + if (!gameinfo.intermissioncounter || cnt_kills[0] >= plrs[me].skills) + { + cnt_kills[0] = plrs[me].skills; S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); sp_state++; } } - } - else if (sp_state == 10) - { - if (acceleratestage) + else if (sp_state == 4) { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/paststats", 1, ATTN_NONE); - WI_initShowNextLoc(); + if (gameinfo.intermissioncounter) + { + cnt_items[0] += 2; + + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + } + if (!gameinfo.intermissioncounter || cnt_items[0] >= plrs[me].sitems) + { + cnt_items[0] = plrs[me].sitems; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + sp_state++; + } + } + else if (sp_state == 6) + { + if (gameinfo.intermissioncounter) + { + cnt_secret[0] += 2; + + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + } + if (!gameinfo.intermissioncounter || cnt_secret[0] >= plrs[me].ssecret) + { + cnt_secret[0] = plrs[me].ssecret; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + sp_state++; + } + } + else if (sp_state == 8) + { + if (gameinfo.intermissioncounter) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + cnt_time += 3; + cnt_par += 3; + cnt_total_time += 3; + } + + int sec = Tics2Seconds(plrs[me].stime); + if (!gameinfo.intermissioncounter || cnt_time >= sec) + cnt_time = sec; + + int tsec = Tics2Seconds(wbs->totaltime); + if (!gameinfo.intermissioncounter || cnt_total_time >= tsec) + cnt_total_time = tsec; + + if (!gameinfo.intermissioncounter || cnt_par >= wbs->partime / TICRATE) + { + cnt_par = wbs->partime / TICRATE; + + if (cnt_time >= sec) + { + cnt_total_time = tsec; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + sp_state++; + } + } + } + else if (sp_state == 10) + { + if (acceleratestage) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/paststats", 1, ATTN_NONE); + WI_initShowNextLoc(); + } + } + else if (sp_state & 1) + { + if (!--cnt_pause) + { + sp_state++; + cnt_pause = TICRATE; + } } } - else if (sp_state & 1) + + void WI_drawStats (void) { - if (!--cnt_pause) - { - sp_state++; - cnt_pause = TICRATE; - } - } -} + // line height + int lh; -void WI_drawStats (void) -{ - // line height - int lh; + lh = IntermissionFont->GetHeight() * 3 / 2; - lh = IntermissionFont->GetHeight() * 3 / 2; - - // draw animated background - WI_drawBackground(); + // draw animated background + WI_drawBackground(); - WI_drawLF(); + WI_drawLF(); - if (gameinfo.gametype & GAME_DoomChex) - { - screen->DrawTexture (kills, SP_STATSX, SP_STATSY, DTA_Clean, true, TAG_DONE); - WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY, cnt_kills[0], wbs->maxkills); - - screen->DrawTexture (items, SP_STATSX, SP_STATSY+lh, DTA_Clean, true, TAG_DONE); - WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+lh, cnt_items[0], wbs->maxitems); - - screen->DrawTexture (sp_secret, SP_STATSX, SP_STATSY+2*lh, DTA_Clean, true, TAG_DONE); - WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0], wbs->maxsecret); - - screen->DrawTexture (timepic, SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); - WI_drawTime (160 - SP_TIMEX, SP_TIMEY, cnt_time); - if (wi_showtotaltime) + if (gameinfo.gametype & GAME_DoomChex) { - WI_drawTime (160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, true); // no 'sucks' for total time ever! - } + screen->DrawTexture (kills, SP_STATSX, SP_STATSY, DTA_Clean, true, TAG_DONE); + WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY, cnt_kills[0], wbs->maxkills); - if (wbs->partime) - { - screen->DrawTexture (par, 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); - WI_drawTime (320 - SP_TIMEX, SP_TIMEY, cnt_par); - } + screen->DrawTexture (items, SP_STATSX, SP_STATSY+lh, DTA_Clean, true, TAG_DONE); + WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+lh, cnt_items[0], wbs->maxitems); - } - else - { - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, GStrings("TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, GStrings("TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, GStrings("TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawTexture (sp_secret, SP_STATSX, SP_STATSY+2*lh, DTA_Clean, true, TAG_DONE); + WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0], wbs->maxsecret); - int countpos = gameinfo.gametype==GAME_Strife? 285:270; - if (sp_state >= 2) - { - WI_drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs->maxkills); - } - if (sp_state >= 4) - { - WI_drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs->maxitems); - } - if (sp_state >= 6) - { - WI_drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs->maxsecret); - } - if (sp_state >= 8) - { - screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, GStrings("TXT_IMTIME"), - DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - WI_drawTime (249, 160, cnt_time); + screen->DrawTexture (timepic, SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); + WI_drawTime (160 - SP_TIMEX, SP_TIMEY, cnt_time); if (wi_showtotaltime) { - WI_drawTime (249, 180, cnt_total_time); + WI_drawTime (160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, true); // no 'sucks' for total time ever! } - } - } -} -// ==================================================================== -// WI_checkForAccelerate -// Purpose: See if the player has hit either the attack or use key -// or mouse button. If so we set acceleratestage to 1 and -// all those display routines above jump right to the end. -// Args: none -// Returns: void -// -// ==================================================================== -void WI_checkForAccelerate(void) -{ - int i; - player_t *player; - - // check for button presses to skip delays - for (i = 0, player = players; i < MAXPLAYERS; i++, player++) - { - if (playeringame[i]) - { - if ((player->cmd.ucmd.buttons ^ player->oldbuttons) && - ((players[i].cmd.ucmd.buttons & players[i].oldbuttons) - == players[i].oldbuttons) && player->Bot == NULL) + if (wbs->partime) { - acceleratestage = 1; - playerready[i] = true; + screen->DrawTexture (par, 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); + WI_drawTime (320 - SP_TIMEX, SP_TIMEY, cnt_par); } - player->oldbuttons = player->cmd.ucmd.buttons; + } - } -} - -// ==================================================================== -// WI_Ticker -// Purpose: Do various updates every gametic, for stats, animation, -// checking that intermission music is running, etc. -// Args: none -// Returns: void -// -// ==================================================================== -void WI_Ticker(void) -{ - // counter for general background animation - bcnt++; - - if (bcnt == 1) - { - // intermission music - use the defaults if none specified - if (level.info->InterMusic.IsNotEmpty()) - S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder); else - S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); - - } - - WI_checkForAccelerate(); - - switch (state) - { - case StatCount: - if (deathmatch) WI_updateDeathmatchStats(); - else if (multiplayer) WI_updateNetgameStats(); - else WI_updateStats(); - break; - - case ShowNextLoc: - WI_updateShowNextLoc(); - break; - - case NoState: - WI_updateNoState(); - break; - - case LeavingIntermission: - // Hush, GCC. - break; - } -} - - -void WI_loadData(void) -{ - entering.Init(gameinfo.mStatscreenEnteringFont); - finished.Init(gameinfo.mStatscreenFinishedFont); - mapname.Init(gameinfo.mStatscreenMapNameFont); - - if (gameinfo.gametype & GAME_DoomChex) - { - kills = TexMan["WIOSTK"]; // "kills" - secret = TexMan["WIOSTS"]; // "scrt" - sp_secret = TexMan["WISCRT2"]; // "secret" - items = TexMan["WIOSTI"]; // "items" - frags = TexMan["WIFRGS"]; // "frgs" - timepic = TexMan["WITIME"]; // "time" - sucks = TexMan["WISUCKS"]; // "sucks" - par = TexMan["WIPAR"]; // "par" - killers = TexMan["WIKILRS"]; // "killers" (vertical] - victims = TexMan["WIVCTMS"]; // "victims" (horiz] - total = TexMan["WIMSTT"]; // "total" -// star = TexMan["STFST01"]; // your face -// bstar = TexMan["STFDEAD0"]; // dead face - p = TexMan["STPBANY"]; - } -#if 0 - else if (gameinfo.gametype & GAME_Raven) - { - if (gameinfo.gametype == GAME_Heretic) { - star = TexMan["FACEA0"]; - bstar = TexMan["FACEB0"]; + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, GStrings("TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, GStrings("TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, GStrings("TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + + int countpos = gameinfo.gametype==GAME_Strife? 285:270; + if (sp_state >= 2) + { + WI_drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs->maxkills); + } + if (sp_state >= 4) + { + WI_drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs->maxitems); + } + if (sp_state >= 6) + { + WI_drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs->maxsecret); + } + if (sp_state >= 8) + { + screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, GStrings("TXT_IMTIME"), + DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + WI_drawTime (249, 160, cnt_time); + if (wi_showtotaltime) + { + WI_drawTime (249, 180, cnt_total_time); + } + } } - else + } + + // ==================================================================== + // WI_checkForAccelerate + // Purpose: See if the player has hit either the attack or use key + // or mouse button. If so we set acceleratestage to 1 and + // all those display routines above jump right to the end. + // Args: none + // Returns: void + // + // ==================================================================== + void WI_checkForAccelerate(void) + { + int i; + player_t *player; + + // check for button presses to skip delays + for (i = 0, player = players; i < MAXPLAYERS; i++, player++) + { + if (playeringame[i]) + { + if ((player->cmd.ucmd.buttons ^ player->oldbuttons) && + ((players[i].cmd.ucmd.buttons & players[i].oldbuttons) + == players[i].oldbuttons) && player->Bot == NULL) + { + acceleratestage = 1; + playerready[i] = true; + } + player->oldbuttons = player->cmd.ucmd.buttons; + } + } + } + + // ==================================================================== + // WI_Ticker + // Purpose: Do various updates every gametic, for stats, animation, + // checking that intermission music is running, etc. + // Args: none + // Returns: void + // + // ==================================================================== + void WI_Ticker(void) + { + // counter for general background animation + bcnt++; + + if (bcnt == 1) + { + // intermission music - use the defaults if none specified + if (level.info->InterMusic.IsNotEmpty()) + S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder); + else + S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); + + } + + WI_checkForAccelerate(); + + switch (state) + { + case StatCount: + if (deathmatch) WI_updateDeathmatchStats(); + else if (multiplayer) WI_updateNetgameStats(); + else WI_updateStats(); + break; + + case ShowNextLoc: + WI_updateShowNextLoc(); + break; + + case NoState: + WI_updateNoState(); + break; + + case LeavingIntermission: + // Hush, GCC. + break; + } + } + + + void WI_loadData(void) + { + entering.Init(gameinfo.mStatscreenEnteringFont); + finished.Init(gameinfo.mStatscreenFinishedFont); + mapname.Init(gameinfo.mStatscreenMapNameFont); + + if (gameinfo.gametype & GAME_DoomChex) + { + kills = TexMan["WIOSTK"]; // "kills" + secret = TexMan["WIOSTS"]; // "scrt" + sp_secret = TexMan["WISCRT2"]; // "secret" + items = TexMan["WIOSTI"]; // "items" + frags = TexMan["WIFRGS"]; // "frgs" + timepic = TexMan["WITIME"]; // "time" + sucks = TexMan["WISUCKS"]; // "sucks" + par = TexMan["WIPAR"]; // "par" + killers = TexMan["WIKILRS"]; // "killers" (vertical] + victims = TexMan["WIVCTMS"]; // "victims" (horiz] + total = TexMan["WIMSTT"]; // "total" + // star = TexMan["STFST01"]; // your face + // bstar = TexMan["STFDEAD0"]; // dead face + p = TexMan["STPBANY"]; + } + #if 0 + else if (gameinfo.gametype & GAME_Raven) + { + if (gameinfo.gametype == GAME_Heretic) + { + star = TexMan["FACEA0"]; + bstar = TexMan["FACEB0"]; + } + else + { + star = BigFont->GetChar('*', NULL); + bstar = star; + } + } + else // Strife needs some handling, too! { star = BigFont->GetChar('*', NULL); bstar = star; } + #endif + + // Use the local level structure which can be overridden by hubs + lnametexts[0] = level.LevelName; + + level_info_t *li = FindLevelInfo(wbs->next); + if (li) lnametexts[1] = li->LookupLevelName(); + else lnametexts[1] = ""; + + WI_LoadBackground(false); } - else // Strife needs some handling, too! + + void WI_unloadData () { - star = BigFont->GetChar('*', NULL); - bstar = star; + // [RH] The texture data gets unloaded at pre-map time, so there's nothing to do here + return; } -#endif - // Use the local level structure which can be overridden by hubs - lnametexts[0] = level.LevelName; - - level_info_t *li = FindLevelInfo(wbs->next); - if (li) lnametexts[1] = li->LookupLevelName(); - else lnametexts[1] = ""; - - WI_LoadBackground(false); -} - -void WI_unloadData () -{ - // [RH] The texture data gets unloaded at pre-map time, so there's nothing to do here - return; -} - -void WI_Drawer (void) -{ - switch (state) + void WI_Drawer (void) { - case StatCount: + switch (state) + { + case StatCount: + if (deathmatch) + WI_drawDeathmatchStats(); + else if (multiplayer) + WI_drawNetgameStats(); + else + WI_drawStats(); + break; + + case ShowNextLoc: + WI_drawShowNextLoc(); + break; + + case LeavingIntermission: + break; + + default: + WI_drawNoState(); + break; + } + } + + + void WI_initVariables (wbstartstruct_t *wbstartstruct) + { + wbs = wbstartstruct; + acceleratestage = 0; + cnt = bcnt = 0; + me = wbs->pnum; + plrs = wbs->plyr; + } + + void WI_Start (wbstartstruct_t *wbstartstruct) + { + noautostartmap = false; + V_SetBlend (0,0,0,0); + WI_initVariables (wbstartstruct); + WI_loadData (); if (deathmatch) - WI_drawDeathmatchStats(); + WI_initDeathmatchStats(); else if (multiplayer) - WI_drawNetgameStats(); + WI_initNetgameStats(); else - WI_drawStats(); - break; - - case ShowNextLoc: - WI_drawShowNextLoc(); - break; - - case LeavingIntermission: - break; - - default: - WI_drawNoState(); - break; + WI_initStats(); + S_StopAllChannels (); + SN_StopAllSequences (); } -} +}; +static FIntermissionScreen WI_Screen; -void WI_initVariables (wbstartstruct_t *wbstartstruct) +void WI_Ticker() { - wbs = wbstartstruct; - acceleratestage = 0; - cnt = bcnt = 0; - me = wbs->pnum; - plrs = wbs->plyr; + WI_Screen.WI_Ticker(); } -void WI_Start (wbstartstruct_t *wbstartstruct) +// Called by main loop, +// draws the intermission directly into the screen buffer. +void WI_Drawer() { - noautostartmap = false; - V_SetBlend (0,0,0,0); - WI_initVariables (wbstartstruct); - WI_loadData (); - if (deathmatch) - WI_initDeathmatchStats(); - else if (multiplayer) - WI_initNetgameStats(); - else - WI_initStats(); - S_StopAllChannels (); - SN_StopAllSequences (); + WI_Screen.WI_Drawer(); +} + +// Setup for an intermission screen. +void WI_Start(wbstartstruct_t *wbstartstruct) +{ + WI_Screen.WI_Start(wbstartstruct); } diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index e9a89b0abc..0aba717cb1 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -290,6 +290,12 @@ struct CVar native native int ResetToDefault(); } +struct GIFont +{ + Name fontname; + Name color; +}; + struct GameInfoStruct native { // will be extended as needed. @@ -301,6 +307,9 @@ struct GameInfoStruct native native bool norandomplayerclass; native Array infoPages; native String mBackButton; + native GIFont mStatscreenMapNameFont; + native GIFont mStatscreenEnteringFont; + native GIFont mStatscreenFinishedFont; } class Object native From d295186378b4e96f19274b973710248b6160943e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 00:16:14 +0100 Subject: [PATCH 075/207] - made all fields of in_anim_t script-safe (except for the texture pointer which will have to be replaced by a Texture ID. --- src/wi_stuff.cpp | 55 +++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index ebc022df8d..5bb1786655 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -198,23 +198,29 @@ public: // (which is why I have renamed this one!) // - static const int MAX_ANIMATION_FRAMES = 20; struct in_anim_t { int type; // Made an int so I can use '|' int period; // period in tics between animations - int nanims; // number of animation frames yahpt_t loc; // location of animation int data; // ALWAYS: n/a, RANDOM: period deviation (<256) - FTexture * p[MAX_ANIMATION_FRAMES]; // actual graphics for frames of animations + TArray frames; // actual graphics for frames of animations // following must be initialized to zero before use! int nexttic; // next value of bcnt (used in conjunction with period) int ctr; // next frame number to animate int state; // used by RANDOM and LEVEL when animating - char levelname[9]; - char levelname2[9]; + FString LevelName; + FString LevelName2; + + void Reset() + { + type = period = loc.x = loc.y = data = nexttic = ctr = state = 0; + LevelName = ""; + LevelName2 = ""; + frames.Clear(); + } }; TArray lnodes; @@ -414,7 +420,7 @@ public: FScanner sc(lumpnum); while (sc.GetString()) { - memset(&an,0,sizeof(an)); + an.Reset(); int caseval = sc.MustMatchString(WI_Cmd); switch(caseval) { @@ -479,15 +485,13 @@ public: case 10: // IfTravelling an.type = ANIM_IFTRAVELLING; sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; + an.LevelName2 = sc.String; goto readanimation; case 11: // IfNotTravelling an.type = ANIM_IFTRAVELLING; sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; + an.LevelName2 = sc.String; goto readanimation; case 14: // NoAutostartMap @@ -496,8 +500,7 @@ public: readanimation: sc.MustGetString(); - strncpy(an.levelname, sc.String, 8); - an.levelname[8] = 0; + an.LevelName = sc.String; sc.MustGetString(); caseval=sc.MustMatchString(WI_Cmd); @@ -527,15 +530,14 @@ public: if (!sc.CheckString("{")) { sc.MustGetString(); - an.p[an.nanims++] = TexMan[sc.String]; + an.frames.Push(TexMan[sc.String]); } else { while (!sc.CheckString("}")) { sc.MustGetString(); - if (an.nanims= a->nexttic) { - if (++a->ctr >= a->nanims) + if (++a->ctr >= (int)a->frames.Size()) { if (a->data==0) a->ctr = 0; else a->ctr--; @@ -647,42 +650,42 @@ public: switch (a->type & ANIM_CONDITION) { case ANIM_IFVISITED: - li = FindLevelInfo(a->levelname); + li = FindLevelInfo(a->LevelName); if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; break; case ANIM_IFNOTVISITED: - li = FindLevelInfo(a->levelname); + li = FindLevelInfo(a->LevelName); if (li == NULL || (li->flags & LEVEL_VISITED)) continue; break; // StatCount means 'leaving' - everything else means 'entering'! case ANIM_IFENTERING: - if (state == StatCount || strnicmp(a->levelname, wbs->next, 8)) continue; + if (state == StatCount || strnicmp(a->LevelName, wbs->next, 8)) continue; break; case ANIM_IFNOTENTERING: - if (state != StatCount && !strnicmp(a->levelname, wbs->next, 8)) continue; + if (state != StatCount && !strnicmp(a->LevelName, wbs->next, 8)) continue; break; case ANIM_IFLEAVING: - if (state != StatCount || strnicmp(a->levelname, wbs->current, 8)) continue; + if (state != StatCount || strnicmp(a->LevelName, wbs->current, 8)) continue; break; case ANIM_IFNOTLEAVING: - if (state == StatCount && !strnicmp(a->levelname, wbs->current, 8)) continue; + if (state == StatCount && !strnicmp(a->LevelName, wbs->current, 8)) continue; break; case ANIM_IFTRAVELLING: - if (strnicmp(a->levelname2, wbs->current, 8) || strnicmp(a->levelname, wbs->next, 8)) continue; + if (strnicmp(a->LevelName2, wbs->current, 8) || strnicmp(a->LevelName, wbs->next, 8)) continue; break; case ANIM_IFNOTTRAVELLING: - if (!strnicmp(a->levelname2, wbs->current, 8) && !strnicmp(a->levelname, wbs->next, 8)) continue; + if (!strnicmp(a->LevelName2, wbs->current, 8) && !strnicmp(a->LevelName, wbs->next, 8)) continue; break; } if (a->ctr >= 0) - screen->DrawTexture(a->p[a->ctr], a->loc.x, a->loc.y, + screen->DrawTexture(a->frames[a->ctr], a->loc.x, a->loc.y, DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); } } From 91f8f5b55665f3a1639e5ba075abfd52150c53f8 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 23 Feb 2017 10:20:02 +0200 Subject: [PATCH 076/207] Restored EndGameMenu as a pseudo-class Fixes the following error: Attempting to open menu of unknown type 'EndGameMenu' At least Adventures of Square is using this class in main menu --- src/menu/menu.cpp | 5 +++++ src/menu/messagebox.cpp | 27 ++++++++++++++++----------- src/namedef.h | 1 + 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index fe5af62686..e4920ef55a 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -411,6 +411,11 @@ void M_SetMenu(FName menu, int param) C_DoCommand("menu_quit"); return; + case NAME_EndGameMenu: + // The separate menu class no longer exists but the name still needs support for existing mods. + void ActivateEndGameMenu(); + ActivateEndGameMenu(); + return; } // End of special checks diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index 795bb60e4d..b3b0e1fe78 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -125,17 +125,8 @@ CCMD (menu_quit) // //============================================================================= -CCMD (menu_endgame) -{ // F7 - if (!usergame) - { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); - return; - } - - //M_StartControlPanel (true); - S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); - +void ActivateEndGameMenu() +{ FString tempstring = GStrings(netgame ? "NETEND" : "ENDGAME"); DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() { @@ -149,6 +140,20 @@ CCMD (menu_endgame) M_ActivateMenu(newmenu); } +CCMD (menu_endgame) +{ // F7 + if (!usergame) + { + S_Sound (CHAN_VOICE | CHAN_UI, "menu/invalid", snd_menuvolume, ATTN_NONE); + return; + } + + //M_StartControlPanel (true); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); + + ActivateEndGameMenu(); +} + //============================================================================= // // diff --git a/src/namedef.h b/src/namedef.h index efc70273fb..105d29cddf 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -671,6 +671,7 @@ xx(Optionsmenu) xx(Quitmenu) xx(Savemenu) xx(Playermenu) +xx(EndGameMenu) xx(Playerbox) xx(Team) From 17f04c5043197968622539b98a2f73cc8f4ea6f0 Mon Sep 17 00:00:00 2001 From: Thomas Hume Date: Thu, 23 Feb 2017 00:58:08 +0100 Subject: [PATCH 077/207] Correct two overflows in PInt ctor --- src/dobjtype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 211c73e824..6684776da5 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -501,7 +501,7 @@ PInt::PInt(unsigned int size, bool unsign, bool compatible) MemberOnly = (size < 4); if (!unsign) { - int maxval = (1 << ((8 * size) - 1)) - 1; + int maxval = (1u << ((8 * size) - 1)) - 1; // compute as unsigned to prevent overflow before -1 int minval = -maxval - 1; Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, minval)); Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, maxval)); @@ -509,7 +509,7 @@ PInt::PInt(unsigned int size, bool unsign, bool compatible) else { Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, 0u)); - Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, (1u << (8 * size)) - 1)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, (1u << ((8 * size) - 1)))); } SetOps(); } From 4bae6e81db91923da8578554fccd911510b8fded Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 18:33:49 +0100 Subject: [PATCH 078/207] - turned the texture pointers in wbstartstruct_t into scripting compatible texture IDs. --- src/g_level.cpp | 6 +++--- src/wi_stuff.cpp | 4 ++-- src/wi_stuff.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 5bc7d44e05..5f074ddb35 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -776,7 +776,7 @@ void G_DoCompleted (void) AM_Stop (); wminfo.finished_ep = level.cluster - 1; - wminfo.LName0 = TexMan[TexMan.CheckForTexture(level.info->PName, FTexture::TEX_MiscPatch)]; + wminfo.LName0 = TexMan.CheckForTexture(level.info->PName, FTexture::TEX_MiscPatch); wminfo.current = level.MapName; if (deathmatch && @@ -792,12 +792,12 @@ void G_DoCompleted (void) if (nextinfo == NULL || strncmp (nextlevel, "enDSeQ", 6) == 0) { wminfo.next = nextlevel; - wminfo.LName1 = NULL; + wminfo.LName1.SetInvalid(); } else { wminfo.next = nextinfo->MapName; - wminfo.LName1 = TexMan[TexMan.CheckForTexture(nextinfo->PName, FTexture::TEX_MiscPatch)]; + wminfo.LName1 = TexMan.CheckForTexture(nextinfo->PName, FTexture::TEX_MiscPatch); } } diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 5bb1786655..e695e1ca0e 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -836,7 +836,7 @@ public: { int y = WI_TITLEY * CleanYfac; - y = WI_DrawName(y, wbs->LName0, lnametexts[0]); + y = WI_DrawName(y, TexMan(wbs->LName0), lnametexts[0]); // Adjustment for different font sizes for map name and 'finished'. y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4; @@ -866,7 +866,7 @@ public: y = WI_DrawPatchText(y, &entering, "WI_ENTERING"); y += entering.mFont->GetHeight() * CleanYfac / 4; - WI_DrawName(y, wbs->LName1, lnametexts[1]); + WI_DrawName(y, TexMan(wbs->LName1), lnametexts[1]); } diff --git a/src/wi_stuff.h b/src/wi_stuff.h index 7eefb9ee5f..8670b759f7 100644 --- a/src/wi_stuff.h +++ b/src/wi_stuff.h @@ -51,8 +51,8 @@ struct wbstartstruct_t FString current; // [RH] Name of map just finished FString next; // next level, [RH] actual map name - FTexture *LName0; - FTexture *LName1; + FTextureID LName0; + FTextureID LName1; int maxkills; int maxitems; From 65c4653f59b23d5ecc9de17360fbf42ba2ade66c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 19:03:31 +0100 Subject: [PATCH 079/207] - restored some code in PClass::CreateDerivedClass that accidentally got removed. --- src/dobjtype.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 6684776da5..75193b868b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3219,16 +3219,24 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) const PClass *existclass = FindClass(name); - // This is a placeholder so fill it in - if (existclass != NULL && existclass->Size == (unsigned)-1) + if (existclass != nullptr) { - type = const_cast(existclass); - if (!IsDescendantOf(type->ParentClass)) + // This is a placeholder so fill it in + if (existclass->Size == TentativeClass) { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); + type = const_cast(existclass); + if (!IsDescendantOf(type->ParentClass)) + { + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); + } + DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); + notnew = true; + } + else + { + // a different class with the same name already exists. Let the calling code deal with this. + return nullptr; } - DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); - notnew = true; } else { From fc101049c68ed1b47b25606489fcd3ee7b8aa8e8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 19:29:43 +0100 Subject: [PATCH 080/207] - exported gamestate variable and forced it to 32 bit internally. - forced gameaction_t to 32 bit to avoid problems with undefined size issues. --- src/d_event.h | 4 ++-- src/doomdef.h | 4 ++-- src/scripting/thingdef_data.cpp | 5 ++++- wadsrc/static/zscript/constants.txt | 12 ++++++++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/d_event.h b/src/d_event.h index 9e90054a33..962286b8f2 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -55,7 +55,7 @@ struct event_t }; -typedef enum +enum gameaction_t : int { ga_nothing, ga_loadlevel, @@ -75,7 +75,7 @@ typedef enum ga_screenshot, ga_togglemap, ga_fullconsole, -} gameaction_t; +}; diff --git a/src/doomdef.h b/src/doomdef.h index 5a1d1f95f4..a07985bb65 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -64,7 +64,7 @@ typedef enum // The current state of the game: whether we are // playing, gazing at the intermission screen, // the game final animation, or a demo. -typedef enum +enum gamestate_t : int { GS_LEVEL, GS_INTERMISSION, @@ -79,7 +79,7 @@ typedef enum GS_FORCEWIPEFADE = -2, GS_FORCEWIPEBURN = -3, GS_FORCEWIPEMELT = -4 -} gamestate_t; +}; extern gamestate_t gamestate; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 41d8644ea8..735fddba78 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -851,7 +851,10 @@ void InitThingdef() fieldptr = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); - fieldptr = new PField("gameaction", TypeUInt8, VARF_Native | VARF_Static, (intptr_t)&gameaction); + fieldptr = new PField("gameaction", TypeUInt32, VARF_Native | VARF_Static, (intptr_t)&gameaction); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + + fieldptr = new PField("gamestate", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gamestate); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); fieldptr = new PField("skyflatnum", TypeTextureID, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&skyflatnum); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 6996da6cc8..e2390cfd1f 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1029,6 +1029,18 @@ enum PaletteFlashFlags PF_HAZARD = 8, }; +enum EGameState +{ + GS_LEVEL, + GS_INTERMISSION, + GS_FINALE, + GS_DEMOSCREEN, + GS_FULLCONSOLE, + GS_HIDECONSOLE, + GS_STARTUP, + GS_TITLELEVEL, +} + enum EGameAction { ga_nothing, From e2d5a708f8d2e7e4765451aa2ec5e38ee6196d26 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 20:18:02 +0100 Subject: [PATCH 081/207] - added an amount parameter to the 'drop' CCMD. --- src/actor.h | 2 +- src/d_net.cpp | 10 ++++++++-- src/g_game.cpp | 5 +++++ src/g_game.h | 1 + src/p_mobj.cpp | 9 +++++---- wadsrc/static/zscript/inventory/ammo.txt | 8 ++++---- wadsrc/static/zscript/inventory/armor.txt | 2 +- wadsrc/static/zscript/inventory/health.txt | 4 ++-- wadsrc/static/zscript/inventory/inventory.txt | 10 ++++++---- wadsrc/static/zscript/inventory/powerups.txt | 2 +- wadsrc/static/zscript/inventory/weapons.txt | 6 +++--- wadsrc/static/zscript/strife/coin.txt | 13 ++++++++----- 12 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/actor.h b/src/actor.h index d3c430759e..d387da2c88 100644 --- a/src/actor.h +++ b/src/actor.h @@ -713,7 +713,7 @@ public: virtual bool UseInventory (AInventory *item); // Tosses an item out of the inventory. - AInventory *DropInventory (AInventory *item); + AInventory *DropInventory (AInventory *item, int amt = -1); // Removes all items from the inventory. void ClearInventory(); diff --git a/src/d_net.cpp b/src/d_net.cpp index a480ae0ae7..7163cdd55d 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2271,6 +2271,9 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_INVDROP: { DWORD which = ReadLong (stream); + int amt = -1; + + if (type == DEM_INVDROP) amt = ReadLong(stream); if (gamestate == GS_LEVEL && !paused && players[player].playerstate != PST_DEAD) @@ -2288,7 +2291,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } else { - players[player].mo->DropInventory (item); + players[player].mo->DropInventory (item, amt); } } } @@ -2764,10 +2767,13 @@ void Net_SkipCommand (int type, BYTE **stream) break; case DEM_INVUSE: - case DEM_INVDROP: skip = 4; break; + case DEM_INVDROP: + skip = 8; + break; + case DEM_GENERICCHEAT: case DEM_DROPPLAYER: case DEM_FOV: diff --git a/src/g_game.cpp b/src/g_game.cpp index e5a48c245e..d93d6743bf 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -241,6 +241,7 @@ FString BackupSaveName; bool SendLand; const AInventory *SendItemUse, *SendItemDrop; +int SendItemDropAmount; EXTERN_CVAR (Int, team) @@ -457,12 +458,14 @@ CCMD (invdrop) if (players[consoleplayer].mo) { SendItemDrop = players[consoleplayer].mo->InvSel; + SendItemDropAmount = -1; } } CCMD (weapdrop) { SendItemDrop = players[consoleplayer].ReadyWeapon; + SendItemDropAmount = -1; } CCMD (drop) @@ -470,6 +473,7 @@ CCMD (drop) if (argv.argc() > 1 && who != NULL) { SendItemDrop = who->FindInventory(argv[1]); + SendItemDropAmount = argv.argc() > 2 ? atoi(argv[2]) : -1; } } @@ -762,6 +766,7 @@ void G_BuildTiccmd (ticcmd_t *cmd) { Net_WriteByte (DEM_INVDROP); Net_WriteLong (SendItemDrop->InventoryID); + Net_WriteLong(SendItemDropAmount); SendItemDrop = NULL; } diff --git a/src/g_game.h b/src/g_game.h index 0a11527fd7..f3f7740398 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -94,6 +94,7 @@ extern AActor *bodyque[BODYQUESIZE]; extern int bodyqueslot; class AInventory; extern const AInventory *SendItemUse, *SendItemDrop; +extern int SendItemDropAmount; #endif diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f9a62892a9..e2f7b18c35 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1035,14 +1035,14 @@ DEFINE_ACTION_FUNCTION(AActor, UseInventory) // //=========================================================================== -AInventory *AActor::DropInventory (AInventory *item) +AInventory *AActor::DropInventory (AInventory *item, int amt) { AInventory *drop = nullptr; IFVIRTUALPTR(item, AInventory, CreateTossable) { - VMValue params[1] = { (DObject*)item }; + VMValue params[] = { (DObject*)item, amt }; VMReturn ret((void**)&drop); - GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); } if (drop == nullptr) return NULL; drop->SetOrigin(PosPlusZ(10.), false); @@ -1059,7 +1059,8 @@ DEFINE_ACTION_FUNCTION(AActor, DropInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT_NOT_NULL(item, AInventory); - ACTION_RETURN_OBJECT(self->DropInventory(item)); + PARAM_INT(amt); + ACTION_RETURN_OBJECT(self->DropInventory(item, amt)); } //============================================================================ diff --git a/wadsrc/static/zscript/inventory/ammo.txt b/wadsrc/static/zscript/inventory/ammo.txt index ba087a8942..e742e806d9 100644 --- a/wadsrc/static/zscript/inventory/ammo.txt +++ b/wadsrc/static/zscript/inventory/ammo.txt @@ -173,9 +173,9 @@ class Ammo : Inventory // //=========================================================================== - override Inventory CreateTossable() + override Inventory CreateTossable(int amt) { - Inventory copy = Super.CreateTossable(); + Inventory copy = Super.CreateTossable(amt); if (copy != null) { // Do not increase ammo by dropping it and picking it back up at // certain skill levels. @@ -306,9 +306,9 @@ class BackpackItem : Inventory // //=========================================================================== - override Inventory CreateTossable () + override Inventory CreateTossable (int amount) { - let pack = BackpackItem(Super.CreateTossable()); + let pack = BackpackItem(Super.CreateTossable(-1)); if (pack != NULL) { pack.bDepleted = true; diff --git a/wadsrc/static/zscript/inventory/armor.txt b/wadsrc/static/zscript/inventory/armor.txt index 50161e8af2..ae9ab562e2 100644 --- a/wadsrc/static/zscript/inventory/armor.txt +++ b/wadsrc/static/zscript/inventory/armor.txt @@ -489,7 +489,7 @@ class HexenArmor : Armor // //=========================================================================== - override Inventory CreateTossable () + override Inventory CreateTossable (int amount) { return NULL; } diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt index 88bf6b133c..230b3575be 100644 --- a/wadsrc/static/zscript/inventory/health.txt +++ b/wadsrc/static/zscript/inventory/health.txt @@ -120,9 +120,9 @@ class HealthPickup : Inventory // //=========================================================================== - override Inventory CreateTossable () + override Inventory CreateTossable (int amount) { - Inventory copy = Super.CreateTossable (); + Inventory copy = Super.CreateTossable (-1); if (copy != NULL) { copy.health = health; diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index 28b20cdd5d..06caedad73 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -440,7 +440,7 @@ class Inventory : Actor native // //=========================================================================== - virtual Inventory CreateTossable () + virtual Inventory CreateTossable (int amt = -1) { // If self actor lacks a SpawnState, don't drop it. (e.g. A base weapon // like the fist can't be dropped because you'll never see it.) @@ -448,7 +448,7 @@ class Inventory : Actor native { return NULL; } - if (bUndroppable || bUntossable || Owner == NULL || Amount <= 0) + if (bUndroppable || bUntossable || Owner == NULL || Amount <= 0 || amt == 0) { return NULL; } @@ -462,11 +462,13 @@ class Inventory : Actor native let copy = Inventory(Spawn (GetClass(), Owner.Pos, NO_REPLACE)); if (copy != NULL) { + amt = clamp(amt, 1, Amount); + copy.MaxAmount = MaxAmount; - copy.Amount = 1; + copy.Amount = amt; copy.DropTime = 30; copy.bSpecial = copy.bSolid = false; - Amount--; + Amount -= amt; } return copy; } diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 828113ac8b..346f3d1a76 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -174,7 +174,7 @@ class Powerup : Inventory // //=========================================================================== - override Inventory CreateTossable () + override Inventory CreateTossable (int amount) { return NULL; } diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index c1fbf43846..c76aaef54c 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -435,7 +435,7 @@ class Weapon : StateProvider native // //=========================================================================== - override Inventory CreateTossable () + override Inventory CreateTossable (int amt) { // Only drop the weapon that is meant to be placed in a level. That is, // only drop the weapon that normally gives you ammo. @@ -443,9 +443,9 @@ class Weapon : StateProvider native Default.AmmoGive1 == 0 && Default.AmmoGive2 == 0 && (SisterWeapon.Default.AmmoGive1 > 0 || SisterWeapon.Default.AmmoGive2 > 0)) { - return SisterWeapon.CreateTossable (); + return SisterWeapon.CreateTossable (amt); } - let copy = Weapon(Super.CreateTossable ()); + let copy = Weapon(Super.CreateTossable (-1)); if (copy != NULL) { diff --git a/wadsrc/static/zscript/strife/coin.txt b/wadsrc/static/zscript/strife/coin.txt index b6a83ecf2a..6f7815cac2 100644 --- a/wadsrc/static/zscript/strife/coin.txt +++ b/wadsrc/static/zscript/strife/coin.txt @@ -79,7 +79,7 @@ class Coin : Inventory // //=========================================================================== - override Inventory CreateTossable () + override Inventory CreateTossable (int amt) { Coin tossed; @@ -87,17 +87,20 @@ class Coin : Inventory { return NULL; } - if (Amount >= 50) + if (amt == -1) amt = Amount >= 50? 50 : Amount >= 25? 25 : Amount >= 10? 10 : 1; + else if (amt > Amount) amt = Amount; + if (amt > 25) { - Amount -= 50; + Amount -= amt; tossed = Coin(Spawn("Gold50")); + tossed.Amount = amt; } - else if (Amount >= 25) + else if (amt > 10) { Amount -= 25; tossed = Coin(Spawn("Gold25")); } - else if (Amount >= 10) + else if (amt > 1) { Amount -= 10; tossed = Coin(Spawn("Gold10")); From 73cceea99413ce805a73609266ef38d8794ac40f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 20:55:12 +0100 Subject: [PATCH 082/207] - also added the 'amount' parameter to DropInventroy and A_DropInventory script functions. --- src/p_actionfunctions.cpp | 3 ++- src/p_mobj.cpp | 2 +- wadsrc/static/zscript/actor.txt | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 8a062cd189..8f916614bb 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -3663,13 +3663,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_DropInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(drop, AInventory); + PARAM_INT_DEF(amount); if (drop) { AInventory *inv = self->FindInventory(drop); if (inv) { - self->DropInventory(inv); + self->DropInventory(inv, amount); } } return 0; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e2f7b18c35..ef5908fda4 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1059,7 +1059,7 @@ DEFINE_ACTION_FUNCTION(AActor, DropInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT_NOT_NULL(item, AInventory); - PARAM_INT(amt); + PARAM_INT_DEF(amt); ACTION_RETURN_OBJECT(self->DropInventory(item, amt)); } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 0666fce8ba..fc31b75d9e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -496,7 +496,7 @@ class Actor : Thinker native native bool TakeInventory(class itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); native Inventory FindInventory(class itemtype, bool subclass = false); native Inventory GiveInventoryType(class itemtype); - native Inventory DropInventory (Inventory item); + native Inventory DropInventory (Inventory item, int amt = -1); native bool UseInventory(Inventory item); native void ObtainInventory(Actor other); native bool GiveAmmo (Class type, int amount); @@ -787,7 +787,7 @@ class Actor : Thinker native native void A_SpawnDebris(class spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1); native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); - native void A_DropInventory(class itemtype); + native void A_DropInventory(class itemtype, int amount); native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0); deprecated native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); From 06119987a8a89ac0c5afbf316f8fd9f29ec68075 Mon Sep 17 00:00:00 2001 From: Thomas Hume Date: Thu, 23 Feb 2017 16:33:57 +0100 Subject: [PATCH 083/207] Prevents possible pointer miss-alignment error --- src/dobject.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index ce4714010e..41b5e2824d 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -165,10 +165,11 @@ protected: \ _X_CONSTRUCTOR_##isabstract(cls) \ _IMP_PCLASS(cls, _X_POINTERS_##ptrs(cls), _X_ABSTRACT_##isabstract(cls)) -// Taking the address of a field in an object at address 1 instead of +// Taking the address of a field in an object at address > 0 instead of // address 0 keeps GCC from complaining about possible misuse of offsetof. +// Using 8 to avoid unaligned pointer use. #define IMPLEMENT_POINTERS_START(cls) const size_t cls::PointerOffsets[] = { -#define IMPLEMENT_POINTER(field) (size_t)&((ThisClass*)1)->field - 1, +#define IMPLEMENT_POINTER(field) ((size_t)&((ThisClass*)8)->field) - 8, #define IMPLEMENT_POINTERS_END ~(size_t)0 }; // Possible arguments for the IMPLEMENT_CLASS macro From c1cafd3bbcdd02d77936a1a736ced950bc378f2b Mon Sep 17 00:00:00 2001 From: Thomas Hume Date: Thu, 23 Feb 2017 20:19:10 +0100 Subject: [PATCH 084/207] Consistency of indents, removes false-pos warnings Clang reports missleading indentation with non bracketed if in the presence of mixed tabs/spaces --- src/sound/oalsound.cpp | 3218 ++++++++++++++++++++-------------------- 1 file changed, 1611 insertions(+), 1607 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 1b34583f94..aa35b03b5a 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -11,12 +11,12 @@ ** are met: ** ** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. +** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. +** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -99,9 +99,9 @@ bool IsOpenALPresent() void I_BuildALDeviceList(FOptionValues *opt) { - opt->mValues.Resize(1); - opt->mValues[0].TextValue = "Default"; - opt->mValues[0].Text = "Default"; + opt->mValues.Resize(1); + opt->mValues[0].TextValue = "Default"; + opt->mValues[0].Text = "Default"; #ifndef NO_OPENAL if (IsOpenALPresent()) @@ -138,31 +138,31 @@ EXTERN_CVAR (Bool, snd_pitched) static ALenum checkALError(const char *fn, unsigned int ln) { - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - { - if(strchr(fn, '/')) - fn = strrchr(fn, '/')+1; - else if(strchr(fn, '\\')) - fn = strrchr(fn, '\\')+1; - Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); - } - return err; + ALenum err = alGetError(); + if(err != AL_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); + } + return err; } #define getALError() checkALError(__FILE__, __LINE__) static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) { - ALCenum err = alcGetError(device); - if(err != ALC_NO_ERROR) - { - if(strchr(fn, '/')) - fn = strrchr(fn, '/')+1; - else if(strchr(fn, '\\')) - fn = strrchr(fn, '\\')+1; - Printf(">>>>>>>>>>>> Received ALC error %s (%#x), %s:%u\n", alcGetString(device, err), err, fn, ln); - } - return err; + ALCenum err = alcGetError(device); + if(err != ALC_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received ALC error %s (%#x), %s:%u\n", alcGetString(device, err), err, fn, ln); + } + return err; } #define getALCError(d) checkALCError((d), __FILE__, __LINE__) @@ -172,272 +172,272 @@ static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) // where they act as appropriate fallbacks. static ALvoid AL_APIENTRY _wrap_DeferUpdatesSOFT(void) { - alcSuspendContext(alcGetCurrentContext()); + alcSuspendContext(alcGetCurrentContext()); } static ALvoid AL_APIENTRY _wrap_ProcessUpdatesSOFT(void) { - alcProcessContext(alcGetCurrentContext()); + alcProcessContext(alcGetCurrentContext()); } class OpenALSoundStream : public SoundStream { - OpenALSoundRenderer *Renderer; + OpenALSoundRenderer *Renderer; - SoundStreamCallback Callback; - void *UserData; + SoundStreamCallback Callback; + void *UserData; - TArray Data; + TArray Data; - ALsizei SampleRate; - ALenum Format; - ALsizei FrameSize; + ALsizei SampleRate; + ALenum Format; + ALsizei FrameSize; - static const int BufferCount = 4; - ALuint Buffers[BufferCount]; - ALuint Source; + static const int BufferCount = 4; + ALuint Buffers[BufferCount]; + ALuint Source; - std::atomic Playing; - bool Looping; - ALfloat Volume; + std::atomic Playing; + bool Looping; + ALfloat Volume; - FileReader *Reader; - SoundDecoder *Decoder; - static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) - { - OpenALSoundStream *self = static_cast(_sstream); - if(length < 0) return false; + FileReader *Reader; + SoundDecoder *Decoder; + static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) + { + OpenALSoundStream *self = static_cast(_sstream); + if(length < 0) return false; - size_t got = self->Decoder->read((char*)ptr, length); - if(got < (unsigned int)length) - { - if(!self->Looping || !self->Decoder->seek(0)) - return false; - got += self->Decoder->read((char*)ptr+got, length-got); - } + size_t got = self->Decoder->read((char*)ptr, length); + if(got < (unsigned int)length) + { + if(!self->Looping || !self->Decoder->seek(0)) + return false; + got += self->Decoder->read((char*)ptr+got, length-got); + } - return (got == (unsigned int)length); - } + return (got == (unsigned int)length); + } - bool SetupSource() - { - /* Get a source, killing the farthest, lowest-priority sound if needed */ - if(Renderer->FreeSfx.Size() == 0) - { - FSoundChan *lowest = Renderer->FindLowestChannel(); - if(lowest) Renderer->StopChannel(lowest); + bool SetupSource() + { + /* Get a source, killing the farthest, lowest-priority sound if needed */ + if(Renderer->FreeSfx.Size() == 0) + { + FSoundChan *lowest = Renderer->FindLowestChannel(); + if(lowest) Renderer->StopChannel(lowest); - if(Renderer->FreeSfx.Size() == 0) - return false; - } - Renderer->FreeSfx.Pop(Source); + if(Renderer->FreeSfx.Size() == 0) + return false; + } + Renderer->FreeSfx.Pop(Source); - /* Set the default properties for localized playback */ - alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); - alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); - alSourcef(Source, AL_MAX_GAIN, 1.f); - alSourcef(Source, AL_GAIN, 1.f); - alSourcef(Source, AL_PITCH, 1.f); - alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_SEC_OFFSET, 0.f); - alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(Source, AL_LOOPING, AL_FALSE); - if(Renderer->EnvSlot) - { - alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); - alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - if(Renderer->AL.EXT_SOURCE_RADIUS) - alSourcef(Source, AL_SOURCE_RADIUS, 0.f); + /* Set the default properties for localized playback */ + alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); + alSourcef(Source, AL_MAX_GAIN, 1.f); + alSourcef(Source, AL_GAIN, 1.f); + alSourcef(Source, AL_PITCH, 1.f); + alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_SEC_OFFSET, 0.f); + alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(Source, AL_LOOPING, AL_FALSE); + if(Renderer->EnvSlot) + { + alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); + alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + if(Renderer->AL.EXT_SOURCE_RADIUS) + alSourcef(Source, AL_SOURCE_RADIUS, 0.f); - alGenBuffers(BufferCount, Buffers); - return (getALError() == AL_NO_ERROR); - } + alGenBuffers(BufferCount, Buffers); + return (getALError() == AL_NO_ERROR); + } public: - OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f), Reader(NULL), Decoder(NULL) - { - memset(Buffers, 0, sizeof(Buffers)); - Renderer->AddStream(this); - } + OpenALSoundStream(OpenALSoundRenderer *renderer) + : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f), Reader(NULL), Decoder(NULL) + { + memset(Buffers, 0, sizeof(Buffers)); + Renderer->AddStream(this); + } - virtual ~OpenALSoundStream() - { - Renderer->RemoveStream(this); + virtual ~OpenALSoundStream() + { + Renderer->RemoveStream(this); - if(Source) - { - alSourceRewind(Source); - alSourcei(Source, AL_BUFFER, 0); + if(Source) + { + alSourceRewind(Source); + alSourcei(Source, AL_BUFFER, 0); - Renderer->FreeSfx.Push(Source); - Source = 0; - } + Renderer->FreeSfx.Push(Source); + Source = 0; + } - if(Buffers[0]) - { - alDeleteBuffers(BufferCount, &Buffers[0]); - memset(Buffers, 0, sizeof(Buffers)); - } - getALError(); + if(Buffers[0]) + { + alDeleteBuffers(BufferCount, &Buffers[0]); + memset(Buffers, 0, sizeof(Buffers)); + } + getALError(); - delete Decoder; - delete Reader; - } + delete Decoder; + delete Reader; + } - virtual bool Play(bool loop, float vol) - { - SetVolume(vol); + virtual bool Play(bool loop, float vol) + { + SetVolume(vol); - if(Playing.load()) - return true; + if(Playing.load()) + return true; - /* Clear the buffer queue, then fill and queue each buffer */ - alSourcei(Source, AL_BUFFER, 0); - for(int i = 0;i < BufferCount;i++) - { - if(!Callback(this, &Data[0], Data.Size(), UserData)) - { - if(i == 0) - return false; - break; - } + /* Clear the buffer queue, then fill and queue each buffer */ + alSourcei(Source, AL_BUFFER, 0); + for(int i = 0;i < BufferCount;i++) + { + if(!Callback(this, &Data[0], Data.Size(), UserData)) + { + if(i == 0) + return false; + break; + } - alBufferData(Buffers[i], Format, &Data[0], Data.Size(), SampleRate); - alSourceQueueBuffers(Source, 1, &Buffers[i]); - } - if(getALError() != AL_NO_ERROR) - return false; + alBufferData(Buffers[i], Format, &Data[0], Data.Size(), SampleRate); + alSourceQueueBuffers(Source, 1, &Buffers[i]); + } + if(getALError() != AL_NO_ERROR) + return false; - alSourcePlay(Source); - if(getALError() != AL_NO_ERROR) - return false; + alSourcePlay(Source); + if(getALError() != AL_NO_ERROR) + return false; - Playing.store(true); - return true; - } + Playing.store(true); + return true; + } - virtual void Stop() - { - if(!Playing.load()) - return; + virtual void Stop() + { + if(!Playing.load()) + return; - std::unique_lock lock(Renderer->StreamLock); - alSourceStop(Source); - alSourcei(Source, AL_BUFFER, 0); - getALError(); + std::unique_lock lock(Renderer->StreamLock); + alSourceStop(Source); + alSourcei(Source, AL_BUFFER, 0); + getALError(); - Playing.store(false); - } + Playing.store(false); + } - virtual void SetVolume(float vol) - { - Volume = vol; - UpdateVolume(); - } + virtual void SetVolume(float vol) + { + Volume = vol; + UpdateVolume(); + } - void UpdateVolume() - { - alSourcef(Source, AL_GAIN, Renderer->MusicVolume*Volume); - getALError(); - } + void UpdateVolume() + { + alSourcef(Source, AL_GAIN, Renderer->MusicVolume*Volume); + getALError(); + } - virtual bool SetPaused(bool pause) - { - if(pause) - alSourcePause(Source); - else - alSourcePlay(Source); - return (getALError()==AL_NO_ERROR); - } + virtual bool SetPaused(bool pause) + { + if(pause) + alSourcePause(Source); + else + alSourcePlay(Source); + return (getALError()==AL_NO_ERROR); + } - virtual bool SetPosition(unsigned int ms_pos) - { - std::unique_lock lock(Renderer->StreamLock); - if(!Decoder->seek(ms_pos)) - return false; + virtual bool SetPosition(unsigned int ms_pos) + { + std::unique_lock lock(Renderer->StreamLock); + if(!Decoder->seek(ms_pos)) + return false; - if(!Playing.load()) - return true; - // Stop the source so that all buffers become processed, which will - // allow the next update to restart the source queue with the new - // position. - alSourceStop(Source); - getALError(); - lock.unlock(); - Renderer->StreamWake.notify_all(); - return true; - } + if(!Playing.load()) + return true; + // Stop the source so that all buffers become processed, which will + // allow the next update to restart the source queue with the new + // position. + alSourceStop(Source); + getALError(); + lock.unlock(); + Renderer->StreamWake.notify_all(); + return true; + } - virtual unsigned int GetPosition() - { - std::unique_lock lock(Renderer->StreamLock); - ALint offset, queued, state; - alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - alGetSourcei(Source, AL_SOURCE_STATE, &state); - if(getALError() != AL_NO_ERROR) - return 0; + virtual unsigned int GetPosition() + { + std::unique_lock lock(Renderer->StreamLock); + ALint offset, queued, state; + alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_SOURCE_STATE, &state); + if(getALError() != AL_NO_ERROR) + return 0; - size_t pos = Decoder->getSampleOffset(); - lock.unlock(); + size_t pos = Decoder->getSampleOffset(); + lock.unlock(); - if(state != AL_STOPPED) - { - size_t rem = queued*(Data.Size()/FrameSize) - offset; - if(pos > rem) pos -= rem; - else pos = 0; - } - return (unsigned int)(pos * 1000.0 / SampleRate); - } + if(state != AL_STOPPED) + { + size_t rem = queued*(Data.Size()/FrameSize) - offset; + if(pos > rem) pos -= rem; + else pos = 0; + } + return (unsigned int)(pos * 1000.0 / SampleRate); + } - virtual bool IsEnded() - { - return !Playing.load(); - } + virtual bool IsEnded() + { + return !Playing.load(); + } - virtual FString GetStats() - { - FString stats; - size_t pos = 0, len = 0; - ALfloat volume; - ALint offset; - ALint processed; - ALint queued; - ALint state; - ALenum err; + virtual FString GetStats() + { + FString stats; + size_t pos = 0, len = 0; + ALfloat volume; + ALint offset; + ALint processed; + ALint queued; + ALint state; + ALenum err; - std::unique_lock lock(Renderer->StreamLock); - alGetSourcef(Source, AL_GAIN, &volume); - alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); - alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - alGetSourcei(Source, AL_SOURCE_STATE, &state); - if((err=alGetError()) != AL_NO_ERROR) - { - lock.unlock(); - stats = "Error getting stats: "; - stats += alGetString(err); - return stats; - } + std::unique_lock lock(Renderer->StreamLock); + alGetSourcef(Source, AL_GAIN, &volume); + alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_SOURCE_STATE, &state); + if((err=alGetError()) != AL_NO_ERROR) + { + lock.unlock(); + stats = "Error getting stats: "; + stats += alGetString(err); + return stats; + } if (Decoder != nullptr) { pos = Decoder->getSampleOffset(); len = Decoder->getSampleLength(); } - lock.unlock(); + lock.unlock(); - stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : - (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; + stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : + (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; if (Decoder != nullptr) { @@ -457,177 +457,177 @@ public: if (len > 0) stats.AppendFormat(" / %zu.%03zu", len / 1000, len % 1000); } - if(state == AL_PAUSED) - stats += ", paused"; - if(state == AL_PLAYING) - stats += ", playing"; - stats.AppendFormat(", %uHz", SampleRate); - if(!Playing) - stats += " XX"; - return stats; - } + if(state == AL_PAUSED) + stats += ", paused"; + if(state == AL_PLAYING) + stats += ", playing"; + stats.AppendFormat(", %uHz", SampleRate); + if(!Playing) + stats += " XX"; + return stats; + } - bool Process() - { - if(!Playing.load()) - return false; + bool Process() + { + if(!Playing.load()) + return false; - ALint state, processed; - alGetSourcei(Source, AL_SOURCE_STATE, &state); - alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); - if(getALError() != AL_NO_ERROR) - { - Playing.store(false); - return false; - } + ALint state, processed; + alGetSourcei(Source, AL_SOURCE_STATE, &state); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + if(getALError() != AL_NO_ERROR) + { + Playing.store(false); + return false; + } - // For each processed buffer in the queue... - while(processed > 0) - { - ALuint bufid; + // For each processed buffer in the queue... + while(processed > 0) + { + ALuint bufid; - // Unqueue the oldest buffer, fill it with more data, and queue it - // on the end - alSourceUnqueueBuffers(Source, 1, &bufid); - processed--; + // Unqueue the oldest buffer, fill it with more data, and queue it + // on the end + alSourceUnqueueBuffers(Source, 1, &bufid); + processed--; - if(Callback(this, &Data[0], Data.Size(), UserData)) - { - alBufferData(bufid, Format, &Data[0], Data.Size(), SampleRate); - alSourceQueueBuffers(Source, 1, &bufid); - } - } + if(Callback(this, &Data[0], Data.Size(), UserData)) + { + alBufferData(bufid, Format, &Data[0], Data.Size(), SampleRate); + alSourceQueueBuffers(Source, 1, &bufid); + } + } - // If the source is not playing or paused, and there are buffers queued, - // then there was an underrun. Restart the source. - bool ok = (getALError()==AL_NO_ERROR); - if(ok && state != AL_PLAYING && state != AL_PAUSED) - { - ALint queued = 0; - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + // If the source is not playing or paused, and there are buffers queued, + // then there was an underrun. Restart the source. + bool ok = (getALError()==AL_NO_ERROR); + if(ok && state != AL_PLAYING && state != AL_PAUSED) + { + ALint queued = 0; + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - ok = (getALError() == AL_NO_ERROR) && (queued > 0); - if(ok) - { - alSourcePlay(Source); - ok = (getALError()==AL_NO_ERROR); - } - } + ok = (getALError() == AL_NO_ERROR) && (queued > 0); + if(ok) + { + alSourcePlay(Source); + ok = (getALError()==AL_NO_ERROR); + } + } - Playing.store(ok); - return ok; - } + Playing.store(ok); + return ok; + } - bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) - { - if(!SetupSource()) - return false; + bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) + { + if(!SetupSource()) + return false; - Callback = callback; - UserData = userdata; - SampleRate = samplerate; + Callback = callback; + UserData = userdata; + SampleRate = samplerate; - Format = AL_NONE; - if((flags&Bits8)) /* Signed or unsigned? We assume unsigned 8-bit... */ - { - if((flags&Mono)) Format = AL_FORMAT_MONO8; - else Format = AL_FORMAT_STEREO8; - } - else if((flags&Float)) - { - if(alIsExtensionPresent("AL_EXT_FLOAT32")) - { - if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; - else Format = AL_FORMAT_STEREO_FLOAT32; - } - } - else if((flags&Bits32)) - { - } - else - { - if((flags&Mono)) Format = AL_FORMAT_MONO16; - else Format = AL_FORMAT_STEREO16; - } + Format = AL_NONE; + if((flags&Bits8)) /* Signed or unsigned? We assume unsigned 8-bit... */ + { + if((flags&Mono)) Format = AL_FORMAT_MONO8; + else Format = AL_FORMAT_STEREO8; + } + else if((flags&Float)) + { + if(alIsExtensionPresent("AL_EXT_FLOAT32")) + { + if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; + else Format = AL_FORMAT_STEREO_FLOAT32; + } + } + else if((flags&Bits32)) + { + } + else + { + if((flags&Mono)) Format = AL_FORMAT_MONO16; + else Format = AL_FORMAT_STEREO16; + } - if(Format == AL_NONE) - { - Printf("Unsupported format: 0x%x\n", flags); - return false; - } + if(Format == AL_NONE) + { + Printf("Unsupported format: 0x%x\n", flags); + return false; + } - FrameSize = 1; - if((flags&Bits8)) - FrameSize *= 1; - else if((flags&(Bits32|Float))) - FrameSize *= 4; - else - FrameSize *= 2; + FrameSize = 1; + if((flags&Bits8)) + FrameSize *= 1; + else if((flags&(Bits32|Float))) + FrameSize *= 4; + else + FrameSize *= 2; - if((flags&Mono)) - FrameSize *= 1; - else - FrameSize *= 2; + if((flags&Mono)) + FrameSize *= 1; + else + FrameSize *= 2; - buffbytes += FrameSize-1; - buffbytes -= buffbytes%FrameSize; - Data.Resize(buffbytes); + buffbytes += FrameSize-1; + buffbytes -= buffbytes%FrameSize; + Data.Resize(buffbytes); - return true; - } + return true; + } - bool Init(FileReader *reader, bool loop) - { - if(!SetupSource()) - { - delete reader; - return false; - } + bool Init(FileReader *reader, bool loop) + { + if(!SetupSource()) + { + delete reader; + return false; + } - if(Decoder) delete Decoder; - if(Reader) delete Reader; - Reader = reader; - Decoder = Renderer->CreateDecoder(Reader); - if(!Decoder) return false; + if(Decoder) delete Decoder; + if(Reader) delete Reader; + Reader = reader; + Decoder = Renderer->CreateDecoder(Reader); + if(!Decoder) return false; - Callback = DecoderCallback; - UserData = NULL; - Format = AL_NONE; - FrameSize = 1; + Callback = DecoderCallback; + UserData = NULL; + Format = AL_NONE; + FrameSize = 1; - ChannelConfig chans; - SampleType type; - int srate; + ChannelConfig chans; + SampleType type; + int srate; - Decoder->getInfo(&srate, &chans, &type); - if(chans == ChannelConfig_Mono) - { - if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; - if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; - FrameSize *= 1; - } - if(chans == ChannelConfig_Stereo) - { - if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; - if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; - FrameSize *= 2; - } - if(type == SampleType_UInt8) FrameSize *= 1; - if(type == SampleType_Int16) FrameSize *= 2; + Decoder->getInfo(&srate, &chans, &type); + if(chans == ChannelConfig_Mono) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; + if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; + FrameSize *= 1; + } + if(chans == ChannelConfig_Stereo) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; + if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; + FrameSize *= 2; + } + if(type == SampleType_UInt8) FrameSize *= 1; + if(type == SampleType_Int16) FrameSize *= 2; - if(Format == AL_NONE) - { - Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), - GetSampleTypeName(type)); - return false; - } - SampleRate = srate; - Looping = loop; + if(Format == AL_NONE) + { + Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), + GetSampleTypeName(type)); + return false; + } + SampleRate = srate; + Looping = loop; - Data.Resize((SampleRate / 5) * FrameSize); + Data.Resize((SampleRate / 5) * FrameSize); - return true; - } + return true; + } }; @@ -641,32 +641,32 @@ extern ReverbContainer *ForcedEnvironment; static size_t GetChannelCount(ChannelConfig chans) { - switch(chans) - { - case ChannelConfig_Mono: return 1; - case ChannelConfig_Stereo: return 2; - } - return 0; + switch(chans) + { + case ChannelConfig_Mono: return 1; + case ChannelConfig_Stereo: return 2; + } + return 0; } static float GetRolloff(const FRolloffInfo *rolloff, float distance) { - if(distance <= rolloff->MinDistance) - return 1.f; - // Logarithmic rolloff has no max distance where it goes silent. - if(rolloff->RolloffType == ROLLOFF_Log) - return rolloff->MinDistance / - (rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance)); - if(distance >= rolloff->MaxDistance) - return 0.f; + if(distance <= rolloff->MinDistance) + return 1.f; + // Logarithmic rolloff has no max distance where it goes silent. + if(rolloff->RolloffType == ROLLOFF_Log) + return rolloff->MinDistance / + (rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance)); + if(distance >= rolloff->MaxDistance) + return 0.f; - float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance); - if(rolloff->RolloffType == ROLLOFF_Linear) - return volume; + float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance); + if(rolloff->RolloffType == ROLLOFF_Linear) + return volume; - if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve != NULL) - return S_SoundCurve[int(S_SoundCurveSize * (1.f - volume))] / 127.f; - return (powf(10.f, volume) - 1.f) / 9.f; + if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve != NULL) + return S_SoundCurve[int(S_SoundCurveSize * (1.f - volume))] / 127.f; + return (powf(10.f, volume) - 1.f) / 9.f; } ALCdevice *OpenALSoundRenderer::InitDevice() @@ -700,608 +700,612 @@ ALCdevice *OpenALSoundRenderer::InitDevice() template static void LoadALFunc(const char *name, T *x) -{ *x = reinterpret_cast(alGetProcAddress(name)); } +{ + *x = reinterpret_cast(alGetProcAddress(name)); +} template static void LoadALCFunc(ALCdevice *device, const char *name, T *x) -{ *x = reinterpret_cast(alcGetProcAddress(device, name)); } +{ + *x = reinterpret_cast(alcGetProcAddress(device, name)); +} #define LOAD_FUNC(x) (LoadALFunc(#x, &x)) #define LOAD_DEV_FUNC(d, x) (LoadALCFunc(d, #x, &x)) OpenALSoundRenderer::OpenALSoundRenderer() - : QuitThread(false), Device(NULL), Context(NULL), SFXPaused(0), PrevEnvironment(NULL), EnvSlot(0) + : QuitThread(false), Device(NULL), Context(NULL), SFXPaused(0), PrevEnvironment(NULL), EnvSlot(0) { - EnvFilters[0] = EnvFilters[1] = 0; + EnvFilters[0] = EnvFilters[1] = 0; - Printf("I_InitSound: Initializing OpenAL\n"); + Printf("I_InitSound: Initializing OpenAL\n"); Device = InitDevice(); if (Device == NULL) return; - const ALCchar *current = NULL; - if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) - current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); - if(alcGetError(Device) != ALC_NO_ERROR || !current) - current = alcGetString(Device, ALC_DEVICE_SPECIFIER); - Printf(" Opened device " TEXTCOLOR_ORANGE"%s\n", current); + const ALCchar *current = NULL; + if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) + current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); + if(alcGetError(Device) != ALC_NO_ERROR || !current) + current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + Printf(" Opened device " TEXTCOLOR_ORANGE"%s\n", current); - ALCint major=0, minor=0; - alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); - DPrintf(DMSG_SPAMMY, " ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); - DPrintf(DMSG_SPAMMY, " ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + ALCint major=0, minor=0; + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + DPrintf(DMSG_SPAMMY, " ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); + DPrintf(DMSG_SPAMMY, " ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - TArray attribs; - if(*snd_samplerate > 0) - { - attribs.Push(ALC_FREQUENCY); - attribs.Push(*snd_samplerate); - } - // Make sure one source is capable of stereo output with the rest doing - // mono, without running out of voices - attribs.Push(ALC_MONO_SOURCES); - attribs.Push(MAX(*snd_channels, 2) - 1); - attribs.Push(ALC_STEREO_SOURCES); - attribs.Push(1); - // Other attribs..? - attribs.Push(0); + TArray attribs; + if(*snd_samplerate > 0) + { + attribs.Push(ALC_FREQUENCY); + attribs.Push(*snd_samplerate); + } + // Make sure one source is capable of stereo output with the rest doing + // mono, without running out of voices + attribs.Push(ALC_MONO_SOURCES); + attribs.Push(MAX(*snd_channels, 2) - 1); + attribs.Push(ALC_STEREO_SOURCES); + attribs.Push(1); + // Other attribs..? + attribs.Push(0); - Context = alcCreateContext(Device, &attribs[0]); - if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) - { - Printf(TEXTCOLOR_RED" Failed to setup context: %s\n", alcGetString(Device, alcGetError(Device))); - if(Context) - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - attribs.Clear(); + Context = alcCreateContext(Device, &attribs[0]); + if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) + { + Printf(TEXTCOLOR_RED" Failed to setup context: %s\n", alcGetString(Device, alcGetError(Device))); + if(Context) + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + attribs.Clear(); - DPrintf(DMSG_SPAMMY, " Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); - DPrintf(DMSG_SPAMMY, " Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); - DPrintf(DMSG_SPAMMY, " Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); - DPrintf(DMSG_SPAMMY, " Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + DPrintf(DMSG_SPAMMY, " Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + DPrintf(DMSG_SPAMMY, " Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + DPrintf(DMSG_SPAMMY, " Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + DPrintf(DMSG_SPAMMY, " Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - ALC.EXT_EFX = !!alcIsExtensionPresent(Device, "ALC_EXT_EFX"); - ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); - ALC.SOFT_pause_device = !!alcIsExtensionPresent(Device, "ALC_SOFT_pause_device"); - AL.EXT_source_distance_model = !!alIsExtensionPresent("AL_EXT_source_distance_model"); - AL.EXT_SOURCE_RADIUS = !!alIsExtensionPresent("AL_EXT_SOURCE_RADIUS"); - AL.SOFT_deferred_updates = !!alIsExtensionPresent("AL_SOFT_deferred_updates"); - AL.SOFT_loop_points = !!alIsExtensionPresent("AL_SOFT_loop_points"); + ALC.EXT_EFX = !!alcIsExtensionPresent(Device, "ALC_EXT_EFX"); + ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); + ALC.SOFT_pause_device = !!alcIsExtensionPresent(Device, "ALC_SOFT_pause_device"); + AL.EXT_source_distance_model = !!alIsExtensionPresent("AL_EXT_source_distance_model"); + AL.EXT_SOURCE_RADIUS = !!alIsExtensionPresent("AL_EXT_SOURCE_RADIUS"); + AL.SOFT_deferred_updates = !!alIsExtensionPresent("AL_SOFT_deferred_updates"); + AL.SOFT_loop_points = !!alIsExtensionPresent("AL_SOFT_loop_points"); - alDopplerFactor(0.5f); - alSpeedOfSound(343.3f * 96.0f); - alDistanceModel(AL_INVERSE_DISTANCE); - if(AL.EXT_source_distance_model) - alEnable(AL_SOURCE_DISTANCE_MODEL); + alDopplerFactor(0.5f); + alSpeedOfSound(343.3f * 96.0f); + alDistanceModel(AL_INVERSE_DISTANCE); + if(AL.EXT_source_distance_model) + alEnable(AL_SOURCE_DISTANCE_MODEL); - if(AL.SOFT_deferred_updates) - { - LOAD_FUNC(alDeferUpdatesSOFT); - LOAD_FUNC(alProcessUpdatesSOFT); - } - else - { - alDeferUpdatesSOFT = _wrap_DeferUpdatesSOFT; - alProcessUpdatesSOFT = _wrap_ProcessUpdatesSOFT; - } + if(AL.SOFT_deferred_updates) + { + LOAD_FUNC(alDeferUpdatesSOFT); + LOAD_FUNC(alProcessUpdatesSOFT); + } + else + { + alDeferUpdatesSOFT = _wrap_DeferUpdatesSOFT; + alProcessUpdatesSOFT = _wrap_ProcessUpdatesSOFT; + } - if(ALC.SOFT_pause_device) - { - LOAD_DEV_FUNC(Device, alcDevicePauseSOFT); - LOAD_DEV_FUNC(Device, alcDeviceResumeSOFT); - } + if(ALC.SOFT_pause_device) + { + LOAD_DEV_FUNC(Device, alcDevicePauseSOFT); + LOAD_DEV_FUNC(Device, alcDeviceResumeSOFT); + } - ALenum err = getALError(); - if(err != AL_NO_ERROR) - { - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } + ALenum err = getALError(); + if(err != AL_NO_ERROR) + { + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } - ALCint numMono=0, numStereo=0; - alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); - alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); + ALCint numMono=0, numStereo=0; + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); - // OpenAL specification doesn't require alcGetIntegerv() to return - // meaningful values for ALC_MONO_SOURCES and ALC_MONO_SOURCES. - // At least Apple's OpenAL implementation returns zeroes, - // although it can generate reasonable number of sources. + // OpenAL specification doesn't require alcGetIntegerv() to return + // meaningful values for ALC_MONO_SOURCES and ALC_MONO_SOURCES. + // At least Apple's OpenAL implementation returns zeroes, + // although it can generate reasonable number of sources. - const int numChannels = MAX(*snd_channels, 2); - int numSources = numMono + numStereo; + const int numChannels = MAX(*snd_channels, 2); + int numSources = numMono + numStereo; - if (0 == numSources) - { - numSources = numChannels; - } + if (0 == numSources) + { + numSources = numChannels; + } - Sources.Resize(MIN(numChannels, numSources)); - for(unsigned i = 0;i < Sources.Size();i++) - { - alGenSources(1, &Sources[i]); - if(getALError() != AL_NO_ERROR) - { - Sources.Resize(i); - Sources.ShrinkToFit(); - break; - } - } - if(Sources.Size() == 0) - { - Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - FreeSfx = Sources; - DPrintf(DMSG_NOTIFY, " Allocated " TEXTCOLOR_BLUE"%u" TEXTCOLOR_NORMAL" sources\n", Sources.Size()); + Sources.Resize(MIN(numChannels, numSources)); + for(unsigned i = 0;i < Sources.Size();i++) + { + alGenSources(1, &Sources[i]); + if(getALError() != AL_NO_ERROR) + { + Sources.Resize(i); + Sources.ShrinkToFit(); + break; + } + } + if(Sources.Size() == 0) + { + Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + FreeSfx = Sources; + DPrintf(DMSG_NOTIFY, " Allocated " TEXTCOLOR_BLUE"%u" TEXTCOLOR_NORMAL" sources\n", Sources.Size()); - WasInWater = false; - if(*snd_efx && ALC.EXT_EFX) - { - // EFX function pointers - LOAD_FUNC(alGenEffects); - LOAD_FUNC(alDeleteEffects); - LOAD_FUNC(alIsEffect); - LOAD_FUNC(alEffecti); - LOAD_FUNC(alEffectiv); - LOAD_FUNC(alEffectf); - LOAD_FUNC(alEffectfv); - LOAD_FUNC(alGetEffecti); - LOAD_FUNC(alGetEffectiv); - LOAD_FUNC(alGetEffectf); - LOAD_FUNC(alGetEffectfv); + WasInWater = false; + if(*snd_efx && ALC.EXT_EFX) + { + // EFX function pointers + LOAD_FUNC(alGenEffects); + LOAD_FUNC(alDeleteEffects); + LOAD_FUNC(alIsEffect); + LOAD_FUNC(alEffecti); + LOAD_FUNC(alEffectiv); + LOAD_FUNC(alEffectf); + LOAD_FUNC(alEffectfv); + LOAD_FUNC(alGetEffecti); + LOAD_FUNC(alGetEffectiv); + LOAD_FUNC(alGetEffectf); + LOAD_FUNC(alGetEffectfv); - LOAD_FUNC(alGenFilters); - LOAD_FUNC(alDeleteFilters); - LOAD_FUNC(alIsFilter); - LOAD_FUNC(alFilteri); - LOAD_FUNC(alFilteriv); - LOAD_FUNC(alFilterf); - LOAD_FUNC(alFilterfv); - LOAD_FUNC(alGetFilteri); - LOAD_FUNC(alGetFilteriv); - LOAD_FUNC(alGetFilterf); - LOAD_FUNC(alGetFilterfv); + LOAD_FUNC(alGenFilters); + LOAD_FUNC(alDeleteFilters); + LOAD_FUNC(alIsFilter); + LOAD_FUNC(alFilteri); + LOAD_FUNC(alFilteriv); + LOAD_FUNC(alFilterf); + LOAD_FUNC(alFilterfv); + LOAD_FUNC(alGetFilteri); + LOAD_FUNC(alGetFilteriv); + LOAD_FUNC(alGetFilterf); + LOAD_FUNC(alGetFilterfv); - LOAD_FUNC(alGenAuxiliaryEffectSlots); - LOAD_FUNC(alDeleteAuxiliaryEffectSlots); - LOAD_FUNC(alIsAuxiliaryEffectSlot); - LOAD_FUNC(alAuxiliaryEffectSloti); - LOAD_FUNC(alAuxiliaryEffectSlotiv); - LOAD_FUNC(alAuxiliaryEffectSlotf); - LOAD_FUNC(alAuxiliaryEffectSlotfv); - LOAD_FUNC(alGetAuxiliaryEffectSloti); - LOAD_FUNC(alGetAuxiliaryEffectSlotiv); - LOAD_FUNC(alGetAuxiliaryEffectSlotf); - LOAD_FUNC(alGetAuxiliaryEffectSlotfv); - if(getALError() == AL_NO_ERROR) - { - ALuint envReverb; - alGenEffects(1, &envReverb); - if(getALError() == AL_NO_ERROR) - { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - if(alGetError() == AL_NO_ERROR) - DPrintf(DMSG_SPAMMY, " EAX Reverb found\n"); - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - if(alGetError() == AL_NO_ERROR) - DPrintf(DMSG_SPAMMY, " Standard Reverb found\n"); + LOAD_FUNC(alGenAuxiliaryEffectSlots); + LOAD_FUNC(alDeleteAuxiliaryEffectSlots); + LOAD_FUNC(alIsAuxiliaryEffectSlot); + LOAD_FUNC(alAuxiliaryEffectSloti); + LOAD_FUNC(alAuxiliaryEffectSlotiv); + LOAD_FUNC(alAuxiliaryEffectSlotf); + LOAD_FUNC(alAuxiliaryEffectSlotfv); + LOAD_FUNC(alGetAuxiliaryEffectSloti); + LOAD_FUNC(alGetAuxiliaryEffectSlotiv); + LOAD_FUNC(alGetAuxiliaryEffectSlotf); + LOAD_FUNC(alGetAuxiliaryEffectSlotfv); + if(getALError() == AL_NO_ERROR) + { + ALuint envReverb; + alGenEffects(1, &envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(DMSG_SPAMMY, " EAX Reverb found\n"); + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(DMSG_SPAMMY, " Standard Reverb found\n"); - alDeleteEffects(1, &envReverb); - getALError(); - } + alDeleteEffects(1, &envReverb); + getALError(); + } - alGenAuxiliaryEffectSlots(1, &EnvSlot); - alGenFilters(2, EnvFilters); - if(getALError() == AL_NO_ERROR) - { - alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); - alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); - if(getALError() == AL_NO_ERROR) - DPrintf(DMSG_SPAMMY, " Lowpass found\n"); - else - { - alDeleteFilters(2, EnvFilters); - EnvFilters[0] = EnvFilters[1] = 0; - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - EnvSlot = 0; - getALError(); - } - } - else - { - alDeleteFilters(2, EnvFilters); - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - EnvFilters[0] = EnvFilters[1] = 0; - EnvSlot = 0; - getALError(); - } - } - } + alGenAuxiliaryEffectSlots(1, &EnvSlot); + alGenFilters(2, EnvFilters); + if(getALError() == AL_NO_ERROR) + { + alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + if(getALError() == AL_NO_ERROR) + DPrintf(DMSG_SPAMMY, " Lowpass found\n"); + else + { + alDeleteFilters(2, EnvFilters); + EnvFilters[0] = EnvFilters[1] = 0; + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvSlot = 0; + getALError(); + } + } + else + { + alDeleteFilters(2, EnvFilters); + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvFilters[0] = EnvFilters[1] = 0; + EnvSlot = 0; + getALError(); + } + } + } - if(EnvSlot) - Printf(" EFX enabled\n"); + if(EnvSlot) + Printf(" EFX enabled\n"); } #undef LOAD_DEV_FUNC #undef LOAD_FUNC OpenALSoundRenderer::~OpenALSoundRenderer() { - if(!Device) - return; + if(!Device) + return; - if(StreamThread.joinable()) - { - std::unique_lock lock(StreamLock); - QuitThread.store(true); - lock.unlock(); - StreamWake.notify_all(); - StreamThread.join(); - } + if(StreamThread.joinable()) + { + std::unique_lock lock(StreamLock); + QuitThread.store(true); + lock.unlock(); + StreamWake.notify_all(); + StreamThread.join(); + } - while(Streams.Size() > 0) - delete Streams[0]; + while(Streams.Size() > 0) + delete Streams[0]; - alDeleteSources(Sources.Size(), &Sources[0]); - Sources.Clear(); - FreeSfx.Clear(); - SfxGroup.Clear(); - PausableSfx.Clear(); - ReverbSfx.Clear(); + alDeleteSources(Sources.Size(), &Sources[0]); + Sources.Clear(); + FreeSfx.Clear(); + SfxGroup.Clear(); + PausableSfx.Clear(); + ReverbSfx.Clear(); - if(EnvEffects.CountUsed() > 0) - { - EffectMapIter iter(EnvEffects); - EffectMap::Pair *pair; - while(iter.NextPair(pair)) - alDeleteEffects(1, &(pair->Value)); - } - EnvEffects.Clear(); + if(EnvEffects.CountUsed() > 0) + { + EffectMapIter iter(EnvEffects); + EffectMap::Pair *pair; + while(iter.NextPair(pair)) + alDeleteEffects(1, &(pair->Value)); + } + EnvEffects.Clear(); - if(EnvSlot) - { - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - alDeleteFilters(2, EnvFilters); - } - EnvSlot = 0; - EnvFilters[0] = EnvFilters[1] = 0; + if(EnvSlot) + { + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + alDeleteFilters(2, EnvFilters); + } + EnvSlot = 0; + EnvFilters[0] = EnvFilters[1] = 0; - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; } void OpenALSoundRenderer::BackgroundProc() { - std::unique_lock lock(StreamLock); - while(!QuitThread.load()) - { - if(Streams.Size() == 0) - { - // If there's nothing to play, wait indefinitely. - StreamWake.wait(lock); - } - else - { - // Else, process all active streams and sleep for 100ms - for(size_t i = 0;i < Streams.Size();i++) - Streams[i]->Process(); - StreamWake.wait_for(lock, std::chrono::milliseconds(100)); - } - } + std::unique_lock lock(StreamLock); + while(!QuitThread.load()) + { + if(Streams.Size() == 0) + { + // If there's nothing to play, wait indefinitely. + StreamWake.wait(lock); + } + else + { + // Else, process all active streams and sleep for 100ms + for(size_t i = 0;i < Streams.Size();i++) + Streams[i]->Process(); + StreamWake.wait_for(lock, std::chrono::milliseconds(100)); + } + } } void OpenALSoundRenderer::AddStream(OpenALSoundStream *stream) { - std::unique_lock lock(StreamLock); - Streams.Push(stream); - lock.unlock(); - // There's a stream to play, make sure the background thread is aware - StreamWake.notify_all(); + std::unique_lock lock(StreamLock); + Streams.Push(stream); + lock.unlock(); + // There's a stream to play, make sure the background thread is aware + StreamWake.notify_all(); } void OpenALSoundRenderer::RemoveStream(OpenALSoundStream *stream) { - std::unique_lock lock(StreamLock); - unsigned int idx = Streams.Find(stream); - if(idx < Streams.Size()) - Streams.Delete(idx); + std::unique_lock lock(StreamLock); + unsigned int idx = Streams.Find(stream); + if(idx < Streams.Size()) + Streams.Delete(idx); } void OpenALSoundRenderer::SetSfxVolume(float volume) { - SfxVolume = volume; + SfxVolume = volume; - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel != NULL) - { - ALuint source = GET_PTRID(schan->SysChannel); - volume = SfxVolume; + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL) + { + ALuint source = GET_PTRID(schan->SysChannel); + volume = SfxVolume; - alDeferUpdatesSOFT(); - alSourcef(source, AL_MAX_GAIN, volume); - alSourcef(source, AL_GAIN, volume * schan->Volume); - } - schan = schan->NextChan; - } + alDeferUpdatesSOFT(); + alSourcef(source, AL_MAX_GAIN, volume); + alSourcef(source, AL_GAIN, volume * schan->Volume); + } + schan = schan->NextChan; + } - alProcessUpdatesSOFT(); + alProcessUpdatesSOFT(); - getALError(); + getALError(); } void OpenALSoundRenderer::SetMusicVolume(float volume) { - MusicVolume = volume; - for(uint32 i = 0;i < Streams.Size();++i) - Streams[i]->UpdateVolume(); + MusicVolume = volume; + for(uint32 i = 0;i < Streams.Size();++i) + Streams[i]->UpdateVolume(); } unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) { - if(sfx.data) - { - ALuint buffer = GET_PTRID(sfx.data); - if(alIsBuffer(buffer)) - { - ALint bits, channels, freq, size; - alGetBufferi(buffer, AL_BITS, &bits); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_FREQUENCY, &freq); - alGetBufferi(buffer, AL_SIZE, &size); - if(getALError() == AL_NO_ERROR) - return (unsigned int)(size / (channels*bits/8) * 1000. / freq); - } - } - return 0; + if(sfx.data) + { + ALuint buffer = GET_PTRID(sfx.data); + if(alIsBuffer(buffer)) + { + ALint bits, channels, freq, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_FREQUENCY, &freq); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (unsigned int)(size / (channels*bits/8) * 1000. / freq); + } + } + return 0; } unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) { - if(sfx.data) - { - ALuint buffer = GET_PTRID(sfx.data); - ALint bits, channels, size; - alGetBufferi(buffer, AL_BITS, &bits); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_SIZE, &size); - if(getALError() == AL_NO_ERROR) - return (ALsizei)(size / (channels * bits / 8)); - } - return 0; + if(sfx.data) + { + ALuint buffer = GET_PTRID(sfx.data); + ALint bits, channels, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (ALsizei)(size / (channels * bits / 8)); + } + return 0; } float OpenALSoundRenderer::GetOutputRate() { - ALCint rate = 44100; // Default, just in case - alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); - return (float)rate; + ALCint rate = 44100; // Default, just in case + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); + return (float)rate; } std::pair OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend, bool monoize) { - SoundHandle retval = { NULL }; + SoundHandle retval = { NULL }; - if(length == 0) return std::make_pair(retval, true); + if(length == 0) return std::make_pair(retval, true); - if(bits == -8) - { - // Simple signed->unsigned conversion - for(int i = 0;i < length;i++) - sfxdata[i] ^= 0x80; - bits = -bits; - } + if(bits == -8) + { + // Simple signed->unsigned conversion + for(int i = 0;i < length;i++) + sfxdata[i] ^= 0x80; + bits = -bits; + } - if(channels > 1 && monoize) - { - size_t frames = length / channels * 8 / bits; - if(bits == 16) - { - for(size_t i = 0;i < frames;i++) - { - int sum = 0; - for(int c = 0;c < channels;c++) - sum += ((short*)sfxdata)[i*channels + c]; - ((short*)sfxdata)[i] = sum / channels; - } - } - else if(bits == 8) - { - for(size_t i = 0;i < frames;i++) - { - int sum = 0; - for(int c = 0;c < channels;c++) - sum += sfxdata[i*channels + c] - 128; - sfxdata[i] = (sum / channels) + 128; - } - } - length /= channels; - channels = 1; - } + if(channels > 1 && monoize) + { + size_t frames = length / channels * 8 / bits; + if(bits == 16) + { + for(size_t i = 0;i < frames;i++) + { + int sum = 0; + for(int c = 0;c < channels;c++) + sum += ((short*)sfxdata)[i*channels + c]; + ((short*)sfxdata)[i] = sum / channels; + } + } + else if(bits == 8) + { + for(size_t i = 0;i < frames;i++) + { + int sum = 0; + for(int c = 0;c < channels;c++) + sum += sfxdata[i*channels + c] - 128; + sfxdata[i] = (sum / channels) + 128; + } + } + length /= channels; + channels = 1; + } - ALenum format = AL_NONE; - if(bits == 16) - { - if(channels == 1) format = AL_FORMAT_MONO16; - if(channels == 2) format = AL_FORMAT_STEREO16; - } - else if(bits == 8) - { - if(channels == 1) format = AL_FORMAT_MONO8; - if(channels == 2) format = AL_FORMAT_STEREO8; - } + ALenum format = AL_NONE; + if(bits == 16) + { + if(channels == 1) format = AL_FORMAT_MONO16; + if(channels == 2) format = AL_FORMAT_STEREO16; + } + else if(bits == 8) + { + if(channels == 1) format = AL_FORMAT_MONO8; + if(channels == 2) format = AL_FORMAT_STEREO8; + } - if(format == AL_NONE || frequency <= 0) - { - Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); - return std::make_pair(retval, true); - } - length -= length%(channels*bits/8); + if(format == AL_NONE || frequency <= 0) + { + Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); + return std::make_pair(retval, true); + } + length -= length%(channels*bits/8); - ALenum err; - ALuint buffer = 0; - alGenBuffers(1, &buffer); - alBufferData(buffer, format, sfxdata, length, frequency); - if((err=getALError()) != AL_NO_ERROR) - { - Printf("Failed to buffer data: %s\n", alGetString(err)); - alDeleteBuffers(1, &buffer); - getALError(); - return std::make_pair(retval, true); - } + ALenum err; + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, sfxdata, length, frequency); + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + return std::make_pair(retval, true); + } - if((loopstart > 0 || loopend > 0) && AL.SOFT_loop_points) - { - if(loopstart < 0) - loopstart = 0; - if(loopend < loopstart) - loopend = length / (channels*bits/8); + if((loopstart > 0 || loopend > 0) && AL.SOFT_loop_points) + { + if(loopstart < 0) + loopstart = 0; + if(loopend < loopstart) + loopend = length / (channels*bits/8); - ALint loops[2] = { loopstart, loopend }; - DPrintf(DMSG_NOTIFY, "Setting loop points %d -> %d\n", loops[0], loops[1]); - alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); - getALError(); - } - else if(loopstart > 0 || loopend > 0) - { - static bool warned = false; - if(!warned) - Printf(DMSG_WARNING, "Loop points not supported!\n"); - warned = true; - } + ALint loops[2] = { loopstart, loopend }; + DPrintf(DMSG_NOTIFY, "Setting loop points %d -> %d\n", loops[0], loops[1]); + alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); + getALError(); + } + else if(loopstart > 0 || loopend > 0) + { + static bool warned = false; + if(!warned) + Printf(DMSG_WARNING, "Loop points not supported!\n"); + warned = true; + } - retval.data = MAKE_PTRID(buffer); - return std::make_pair(retval, channels==1); + retval.data = MAKE_PTRID(buffer); + return std::make_pair(retval, channels==1); } std::pair OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length, bool monoize) { - SoundHandle retval = { NULL }; - MemoryReader reader((const char*)sfxdata, length); - ALenum format = AL_NONE; - ChannelConfig chans; - SampleType type; - int srate; + SoundHandle retval = { NULL }; + MemoryReader reader((const char*)sfxdata, length); + ALenum format = AL_NONE; + ChannelConfig chans; + SampleType type; + int srate; - std::unique_ptr decoder(CreateDecoder(&reader)); - if(!decoder) return std::make_pair(retval, true); + std::unique_ptr decoder(CreateDecoder(&reader)); + if(!decoder) return std::make_pair(retval, true); - decoder->getInfo(&srate, &chans, &type); - if(chans == ChannelConfig_Mono || monoize) - { - if(type == SampleType_UInt8) format = AL_FORMAT_MONO8; - if(type == SampleType_Int16) format = AL_FORMAT_MONO16; - } - else if(chans == ChannelConfig_Stereo) - { - if(type == SampleType_UInt8) format = AL_FORMAT_STEREO8; - if(type == SampleType_Int16) format = AL_FORMAT_STEREO16; - } + decoder->getInfo(&srate, &chans, &type); + if(chans == ChannelConfig_Mono || monoize) + { + if(type == SampleType_UInt8) format = AL_FORMAT_MONO8; + if(type == SampleType_Int16) format = AL_FORMAT_MONO16; + } + else if(chans == ChannelConfig_Stereo) + { + if(type == SampleType_UInt8) format = AL_FORMAT_STEREO8; + if(type == SampleType_Int16) format = AL_FORMAT_STEREO16; + } - if(format == AL_NONE) - { - Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), - GetSampleTypeName(type)); - return std::make_pair(retval, true); - } + if(format == AL_NONE) + { + Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), + GetSampleTypeName(type)); + return std::make_pair(retval, true); + } - TArray data = decoder->readAll(); - if(chans != ChannelConfig_Mono && monoize) - { - size_t chancount = GetChannelCount(chans); - size_t frames = data.Size() / chancount / - (type == SampleType_Int16 ? 2 : 1); - if(type == SampleType_Int16) - { - short *sfxdata = (short*)&data[0]; - for(size_t i = 0;i < frames;i++) - { - int sum = 0; - for(size_t c = 0;c < chancount;c++) - sum += sfxdata[i*chancount + c]; - sfxdata[i] = short(sum / chancount); - } - } - else if(type == SampleType_UInt8) - { - BYTE *sfxdata = (BYTE*)&data[0]; - for(size_t i = 0;i < frames;i++) - { - int sum = 0; - for(size_t c = 0;c < chancount;c++) - sum += sfxdata[i*chancount + c] - 128; - sfxdata[i] = BYTE((sum / chancount) + 128); - } - } - data.Resize(unsigned(data.Size()/chancount)); - } + TArray data = decoder->readAll(); + if(chans != ChannelConfig_Mono && monoize) + { + size_t chancount = GetChannelCount(chans); + size_t frames = data.Size() / chancount / + (type == SampleType_Int16 ? 2 : 1); + if(type == SampleType_Int16) + { + short *sfxdata = (short*)&data[0]; + for(size_t i = 0;i < frames;i++) + { + int sum = 0; + for(size_t c = 0;c < chancount;c++) + sum += sfxdata[i*chancount + c]; + sfxdata[i] = short(sum / chancount); + } + } + else if(type == SampleType_UInt8) + { + BYTE *sfxdata = (BYTE*)&data[0]; + for(size_t i = 0;i < frames;i++) + { + int sum = 0; + for(size_t c = 0;c < chancount;c++) + sum += sfxdata[i*chancount + c] - 128; + sfxdata[i] = BYTE((sum / chancount) + 128); + } + } + data.Resize(unsigned(data.Size()/chancount)); + } - ALenum err; - ALuint buffer = 0; - alGenBuffers(1, &buffer); - alBufferData(buffer, format, &data[0], data.Size(), srate); - if((err=getALError()) != AL_NO_ERROR) - { - Printf("Failed to buffer data: %s\n", alGetString(err)); - alDeleteBuffers(1, &buffer); - getALError(); - return std::make_pair(retval, true); - } + ALenum err; + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, &data[0], data.Size(), srate); + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + return std::make_pair(retval, true); + } - retval.data = MAKE_PTRID(buffer); - return std::make_pair(retval, (chans == ChannelConfig_Mono || monoize)); + retval.data = MAKE_PTRID(buffer); + return std::make_pair(retval, (chans == ChannelConfig_Mono || monoize)); } void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) { - if(!sfx.data) - return; + if(!sfx.data) + return; - ALuint buffer = GET_PTRID(sfx.data); - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel) - { - ALint bufID = 0; - alGetSourcei(GET_PTRID(schan->SysChannel), AL_BUFFER, &bufID); - if((ALuint)bufID == buffer) - { - FSoundChan *next = schan->NextChan; - StopChannel(schan); - schan = next; - continue; - } - } - schan = schan->NextChan; - } + ALuint buffer = GET_PTRID(sfx.data); + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel) + { + ALint bufID = 0; + alGetSourcei(GET_PTRID(schan->SysChannel), AL_BUFFER, &bufID); + if((ALuint)bufID == buffer) + { + FSoundChan *next = schan->NextChan; + StopChannel(schan); + schan = next; + continue; + } + } + schan = schan->NextChan; + } - alDeleteBuffers(1, &buffer); - getALError(); + alDeleteBuffers(1, &buffer); + getALError(); } SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) { - if(StreamThread.get_id() == std::thread::id()) - StreamThread = std::thread(std::mem_fn(&OpenALSoundRenderer::BackgroundProc), this); + if(StreamThread.get_id() == std::thread::id()) + StreamThread = std::thread(std::mem_fn(&OpenALSoundRenderer::BackgroundProc), this); OpenALSoundStream *stream = new OpenALSoundStream(this); if (!stream->Init(callback, buffbytes, flags, samplerate, userdata)) { @@ -1313,8 +1317,8 @@ SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int SoundStream *OpenALSoundRenderer::OpenStream(FileReader *reader, int flags) { - if(StreamThread.get_id() == std::thread::id()) - StreamThread = std::thread(std::mem_fn(&OpenALSoundRenderer::BackgroundProc), this); + if(StreamThread.get_id() == std::thread::id()) + StreamThread = std::thread(std::mem_fn(&OpenALSoundRenderer::BackgroundProc), this); OpenALSoundStream *stream = new OpenALSoundStream(this); if (!stream->Init(reader, !!(flags&SoundStream::Loop))) { @@ -1326,875 +1330,875 @@ SoundStream *OpenALSoundRenderer::OpenStream(FileReader *reader, int flags) FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) { - if(FreeSfx.Size() == 0) - { - FSoundChan *lowest = FindLowestChannel(); - if(lowest) StopChannel(lowest); + if(FreeSfx.Size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) StopChannel(lowest); - if(FreeSfx.Size() == 0) - return NULL; - } + if(FreeSfx.Size() == 0) + return NULL; + } - ALuint buffer = GET_PTRID(sfx.data); - ALuint source = FreeSfx.Last(); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); - alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + ALuint buffer = GET_PTRID(sfx.data); + ALuint source = FreeSfx.Last(); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); + alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 1000.f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.f); - alSourcef(source, AL_MAX_GAIN, SfxVolume); - alSourcef(source, AL_GAIN, SfxVolume*vol); - if(AL.EXT_SOURCE_RADIUS) - alSourcef(source, AL_SOURCE_RADIUS, 0.f); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); + alSourcef(source, AL_MAX_DISTANCE, 1000.f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume*vol); + if(AL.EXT_SOURCE_RADIUS) + alSourcef(source, AL_SOURCE_RADIUS, 0.f); - if(EnvSlot) - { - if(!(chanflags&SNDF_NOREVERB)) - { - alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - else - { - alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - } - if(WasInWater && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); - else - alSourcef(source, AL_PITCH, PITCH(pitch)); + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + } + if(WasInWater && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); - if(!reuse_chan || reuse_chan->StartTime.AsOne == 0) - alSourcef(source, AL_SEC_OFFSET, 0.f); - else - { - if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); - else - { - float offset = std::chrono::duration_cast>( - std::chrono::steady_clock::now().time_since_epoch() - - std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime.AsOne) - ).count(); - if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset); - } - } - if(getALError() != AL_NO_ERROR) - return NULL; + if(!reuse_chan || reuse_chan->StartTime.AsOne == 0) + alSourcef(source, AL_SEC_OFFSET, 0.f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); + else + { + float offset = std::chrono::duration_cast>( + std::chrono::steady_clock::now().time_since_epoch() - + std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime.AsOne) + ).count(); + if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; - alSourcei(source, AL_BUFFER, buffer); - if((chanflags&SNDF_NOPAUSE) || !SFXPaused) - alSourcePlay(source); - if(getALError() != AL_NO_ERROR) - { - alSourcei(source, AL_BUFFER, 0); - getALError(); - return NULL; - } + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } - if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.Push(source); - if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.Push(source); - SfxGroup.Push(source); - FreeSfx.Pop(); + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.Push(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.Push(source); + SfxGroup.Push(source); + FreeSfx.Pop(); - FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); - else chan->SysChannel = MAKE_PTRID(source); + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); + else chan->SysChannel = MAKE_PTRID(source); - chan->Rolloff.RolloffType = ROLLOFF_Log; - chan->Rolloff.RolloffFactor = 0.f; - chan->Rolloff.MinDistance = 1.f; - chan->DistanceSqr = 0.f; - chan->ManualRolloff = false; + chan->Rolloff.RolloffType = ROLLOFF_Log; + chan->Rolloff.RolloffFactor = 0.f; + chan->Rolloff.MinDistance = 1.f; + chan->DistanceSqr = 0.f; + chan->ManualRolloff = false; - return chan; + return chan; } FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, - FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, - int channum, int chanflags, FISoundChannel *reuse_chan) + FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, + int channum, int chanflags, FISoundChannel *reuse_chan) { - float dist_sqr = (float)(pos - listener->position).LengthSquared(); + float dist_sqr = (float)(pos - listener->position).LengthSquared(); - if(FreeSfx.Size() == 0) - { - FSoundChan *lowest = FindLowestChannel(); - if(lowest) - { - if(lowest->Priority < priority || (lowest->Priority == priority && - lowest->DistanceSqr > dist_sqr)) - StopChannel(lowest); - } - if(FreeSfx.Size() == 0) - return NULL; - } + if(FreeSfx.Size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) + { + if(lowest->Priority < priority || (lowest->Priority == priority && + lowest->DistanceSqr > dist_sqr)) + StopChannel(lowest); + } + if(FreeSfx.Size() == 0) + return NULL; + } - bool manualRolloff = true; - ALuint buffer = GET_PTRID(sfx.data); - ALuint source = FreeSfx.Last(); - if(rolloff->RolloffType == ROLLOFF_Log) - { - if(AL.EXT_source_distance_model) - alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); - alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); - manualRolloff = false; - } - else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) - { - alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); - manualRolloff = false; - } - if(manualRolloff) - { - // How manual rolloff works: - // - // If a sound is using Custom or Doom style rolloff, or Linear style - // when AL_EXT_source_distance_model is not supported, we have to play - // around a bit to get appropriate distance attenation. What we do is - // calculate the attenuation that should be applied, then given an - // Inverse Distance rolloff model with OpenAL, reverse the calculation - // to get the distance needed for that much attenuation. The Inverse - // Distance calculation is: - // - // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) - // - // Thus, the reverse is: - // - // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist - // - // This can be simplified by using a MinDist and RolloffFactor of 1, - // which makes it: - // - // Distance = 1.0f/Gain; - // - // The source position is then set that many units away from the - // listener position, and OpenAL takes care of the rest. - if(AL.EXT_source_distance_model) - alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 100000.f); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + bool manualRolloff = true; + ALuint buffer = GET_PTRID(sfx.data); + ALuint source = FreeSfx.Last(); + if(rolloff->RolloffType == ROLLOFF_Log) + { + if(AL.EXT_source_distance_model) + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); + manualRolloff = false; + } + else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) + { + alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + manualRolloff = false; + } + if(manualRolloff) + { + // How manual rolloff works: + // + // If a sound is using Custom or Doom style rolloff, or Linear style + // when AL_EXT_source_distance_model is not supported, we have to play + // around a bit to get appropriate distance attenation. What we do is + // calculate the attenuation that should be applied, then given an + // Inverse Distance rolloff model with OpenAL, reverse the calculation + // to get the distance needed for that much attenuation. The Inverse + // Distance calculation is: + // + // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) + // + // Thus, the reverse is: + // + // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist + // + // This can be simplified by using a MinDist and RolloffFactor of 1, + // which makes it: + // + // Distance = 1.0f/Gain; + // + // The source position is then set that many units away from the + // listener position, and OpenAL takes care of the rest. + if(AL.EXT_source_distance_model) + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); + alSourcef(source, AL_MAX_DISTANCE, 100000.f); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); - FVector3 dir = pos - listener->position; - if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) - { - float gain = GetRolloff(rolloff, sqrtf(dist_sqr) * distscale); - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); - } - if(AL.EXT_SOURCE_RADIUS) - { - /* Since the OpenAL distance is decoupled from the sound's distance, get the OpenAL - * distance that corresponds to the area radius. */ - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? - // Clamp in case the max distance is <= the area radius - 1.f/MAX(GetRolloff(rolloff, AREA_SOUND_RADIUS), 0.00001f) : 0.f - ); - } - else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); - float a = sqrtf(dist_sqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; - } - dir += listener->position; + FVector3 dir = pos - listener->position; + if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) + { + float gain = GetRolloff(rolloff, sqrtf(dist_sqr) * distscale); + dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); + } + if(AL.EXT_SOURCE_RADIUS) + { + /* Since the OpenAL distance is decoupled from the sound's distance, get the OpenAL + * distance that corresponds to the area radius. */ + alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? + // Clamp in case the max distance is <= the area radius + 1.f/MAX(GetRolloff(rolloff, AREA_SOUND_RADIUS), 0.00001f) : 0.f + ); + } + else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + float a = sqrtf(dist_sqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + } + dir += listener->position; - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } - } - else - { - FVector3 dir = pos; - if(AL.EXT_SOURCE_RADIUS) - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); - else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - dir -= listener->position; + if(dist_sqr < (0.0004f*0.0004f)) + { + // Head relative + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); + } + else + { + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } + } + else + { + FVector3 dir = pos; + if(AL.EXT_SOURCE_RADIUS) + alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); + else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + dir -= listener->position; + + float mindist = rolloff->MinDistance/distscale; + FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + float a = sqrtf(dist_sqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + + dir += listener->position; + } + if(dist_sqr < (0.0004f*0.0004f)) + { + // Head relative + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); + } + else + { + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } + } + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); - float mindist = rolloff->MinDistance/distscale; - FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); - float a = sqrtf(dist_sqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); - dir += listener->position; - } - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } - } - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume*vol); - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + } + if(WasInWater && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); - alSourcef(source, AL_MAX_GAIN, SfxVolume); - alSourcef(source, AL_GAIN, SfxVolume*vol); + if(!reuse_chan || reuse_chan->StartTime.AsOne == 0) + alSourcef(source, AL_SEC_OFFSET, 0.f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); + else + { + float offset = std::chrono::duration_cast>( + std::chrono::steady_clock::now().time_since_epoch() - + std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime.AsOne) + ).count(); + if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; - if(EnvSlot) - { - if(!(chanflags&SNDF_NOREVERB)) - { - alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - else - { - alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - } - if(WasInWater && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); - else - alSourcef(source, AL_PITCH, PITCH(pitch)); + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } - if(!reuse_chan || reuse_chan->StartTime.AsOne == 0) - alSourcef(source, AL_SEC_OFFSET, 0.f); - else - { - if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); - else - { - float offset = std::chrono::duration_cast>( - std::chrono::steady_clock::now().time_since_epoch() - - std::chrono::steady_clock::time_point::duration(reuse_chan->StartTime.AsOne) - ).count(); - if(offset > 0.f) alSourcef(source, AL_SEC_OFFSET, offset); - } - } - if(getALError() != AL_NO_ERROR) - return NULL; + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.Push(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.Push(source); + SfxGroup.Push(source); + FreeSfx.Pop(); - alSourcei(source, AL_BUFFER, buffer); - if((chanflags&SNDF_NOPAUSE) || !SFXPaused) - alSourcePlay(source); - if(getALError() != AL_NO_ERROR) - { - alSourcei(source, AL_BUFFER, 0); - getALError(); - return NULL; - } + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); + else chan->SysChannel = MAKE_PTRID(source); - if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.Push(source); - if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.Push(source); - SfxGroup.Push(source); - FreeSfx.Pop(); + chan->Rolloff = *rolloff; + chan->DistanceSqr = dist_sqr; + chan->ManualRolloff = manualRolloff; - FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); - else chan->SysChannel = MAKE_PTRID(source); - - chan->Rolloff = *rolloff; - chan->DistanceSqr = dist_sqr; - chan->ManualRolloff = manualRolloff; - - return chan; + return chan; } void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) { - if(chan == NULL || chan->SysChannel == NULL) - return; + if(chan == NULL || chan->SysChannel == NULL) + return; - alDeferUpdatesSOFT(); + alDeferUpdatesSOFT(); - ALuint source = GET_PTRID(chan->SysChannel); - alSourcef(source, AL_GAIN, SfxVolume * volume); + ALuint source = GET_PTRID(chan->SysChannel); + alSourcef(source, AL_GAIN, SfxVolume * volume); } void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) { - if(chan == NULL || chan->SysChannel == NULL) - return; + if(chan == NULL || chan->SysChannel == NULL) + return; - ALuint source = GET_PTRID(chan->SysChannel); - // Release first, so it can be properly marked as evicted if it's being - // forcefully killed - S_ChannelEnded(chan); + ALuint source = GET_PTRID(chan->SysChannel); + // Release first, so it can be properly marked as evicted if it's being + // forcefully killed + S_ChannelEnded(chan); - alSourceRewind(source); - alSourcei(source, AL_BUFFER, 0); - getALError(); + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + getALError(); - uint32 i; - if((i=PausableSfx.Find(source)) < PausableSfx.Size()) - PausableSfx.Delete(i); - if((i=ReverbSfx.Find(source)) < ReverbSfx.Size()) - ReverbSfx.Delete(i); + uint32 i; + if((i=PausableSfx.Find(source)) < PausableSfx.Size()) + PausableSfx.Delete(i); + if((i=ReverbSfx.Find(source)) < ReverbSfx.Size()) + ReverbSfx.Delete(i); - SfxGroup.Delete(SfxGroup.Find(source)); - FreeSfx.Push(source); + SfxGroup.Delete(SfxGroup.Find(source)); + FreeSfx.Push(source); } unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) { - if(chan == NULL || chan->SysChannel == NULL) - return 0; + if(chan == NULL || chan->SysChannel == NULL) + return 0; - ALint pos; - alGetSourcei(GET_PTRID(chan->SysChannel), AL_SAMPLE_OFFSET, &pos); - if(getALError() == AL_NO_ERROR) - return pos; - return 0; + ALint pos; + alGetSourcei(GET_PTRID(chan->SysChannel), AL_SAMPLE_OFFSET, &pos); + if(getALError() == AL_NO_ERROR) + return pos; + return 0; } void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) { - int oldslots = SFXPaused; + int oldslots = SFXPaused; - if(paused) - { - SFXPaused |= 1 << slot; - if(oldslots == 0 && PausableSfx.Size() > 0) - { - alSourcePausev(PausableSfx.Size(), &PausableSfx[0]); - getALError(); - PurgeStoppedSources(); - } - } - else - { - SFXPaused &= ~(1 << slot); - if(SFXPaused == 0 && oldslots != 0 && PausableSfx.Size() > 0) - { - alSourcePlayv(PausableSfx.Size(), &PausableSfx[0]); - getALError(); - } - } + if(paused) + { + SFXPaused |= 1 << slot; + if(oldslots == 0 && PausableSfx.Size() > 0) + { + alSourcePausev(PausableSfx.Size(), &PausableSfx[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + SFXPaused &= ~(1 << slot); + if(SFXPaused == 0 && oldslots != 0 && PausableSfx.Size() > 0) + { + alSourcePlayv(PausableSfx.Size(), &PausableSfx[0]); + getALError(); + } + } } void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState state) { - switch(state) - { - case SoundRenderer::INACTIVE_Active: - alListenerf(AL_GAIN, 1.0f); - if(ALC.SOFT_pause_device) - { - alcDeviceResumeSOFT(Device); - getALCError(Device); - } - break; + switch(state) + { + case SoundRenderer::INACTIVE_Active: + alListenerf(AL_GAIN, 1.0f); + if(ALC.SOFT_pause_device) + { + alcDeviceResumeSOFT(Device); + getALCError(Device); + } + break; - case SoundRenderer::INACTIVE_Complete: - if(ALC.SOFT_pause_device) - { - alcDevicePauseSOFT(Device); - getALCError(Device); - } - /* fall-through */ - case SoundRenderer::INACTIVE_Mute: - alListenerf(AL_GAIN, 0.0f); - break; - } + case SoundRenderer::INACTIVE_Complete: + if(ALC.SOFT_pause_device) + { + alcDevicePauseSOFT(Device); + getALCError(Device); + } + /* fall-through */ + case SoundRenderer::INACTIVE_Mute: + alListenerf(AL_GAIN, 0.0f); + break; + } } void OpenALSoundRenderer::Sync(bool sync) { - if(sync) - { - if(SfxGroup.Size() > 0) - { - alSourcePausev(SfxGroup.Size(), &SfxGroup[0]); - getALError(); - PurgeStoppedSources(); - } - } - else - { - // Might already be something to handle this; basically, get a vector - // of all values in SfxGroup that are not also in PausableSfx (when - // SFXPaused is non-0). - TArray toplay = SfxGroup; - if(SFXPaused) - { - uint32 i = 0; - while(i < toplay.Size()) - { - uint32 p = PausableSfx.Find(toplay[i]); - if(p < PausableSfx.Size()) - toplay.Delete(i); - else - i++; - } - } - if(toplay.Size() > 0) - { - alSourcePlayv(toplay.Size(), &toplay[0]); - getALError(); - } - } + if(sync) + { + if(SfxGroup.Size() > 0) + { + alSourcePausev(SfxGroup.Size(), &SfxGroup[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + // Might already be something to handle this; basically, get a vector + // of all values in SfxGroup that are not also in PausableSfx (when + // SFXPaused is non-0). + TArray toplay = SfxGroup; + if(SFXPaused) + { + uint32 i = 0; + while(i < toplay.Size()) + { + uint32 p = PausableSfx.Find(toplay[i]); + if(p < PausableSfx.Size()) + toplay.Delete(i); + else + i++; + } + } + if(toplay.Size() > 0) + { + alSourcePlayv(toplay.Size(), &toplay[0]); + getALError(); + } + } } void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) { - if(chan == NULL || chan->SysChannel == NULL) - return; + if(chan == NULL || chan->SysChannel == NULL) + return; - FVector3 dir = pos - listener->position; - chan->DistanceSqr = (float)dir.LengthSquared(); + FVector3 dir = pos - listener->position; + chan->DistanceSqr = (float)dir.LengthSquared(); - if(chan->ManualRolloff) - { - if(!AL.EXT_SOURCE_RADIUS && areasound && - chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); - float a = sqrtf(chan->DistanceSqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; - } - if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) - { - float gain = GetRolloff(&chan->Rolloff, sqrtf(chan->DistanceSqr)*chan->DistanceScale); - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); - } - } - else if(!AL.EXT_SOURCE_RADIUS && areasound && - chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) - { - float mindist = chan->Rolloff.MinDistance / chan->DistanceScale; - FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); - float a = sqrtf(chan->DistanceSqr) / AREA_SOUND_RADIUS; - dir = amb + (dir-amb)*a; - } - dir += listener->position; + if(chan->ManualRolloff) + { + if(!AL.EXT_SOURCE_RADIUS && areasound && + chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + float a = sqrtf(chan->DistanceSqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + } + if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) + { + float gain = GetRolloff(&chan->Rolloff, sqrtf(chan->DistanceSqr)*chan->DistanceScale); + dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); + } + } + else if(!AL.EXT_SOURCE_RADIUS && areasound && + chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + float mindist = chan->Rolloff.MinDistance / chan->DistanceScale; + FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + float a = sqrtf(chan->DistanceSqr) / AREA_SOUND_RADIUS; + dir = amb + (dir-amb)*a; + } + dir += listener->position; - alDeferUpdatesSOFT(); - ALuint source = GET_PTRID(chan->SysChannel); + alDeferUpdatesSOFT(); + ALuint source = GET_PTRID(chan->SysChannel); - if(chan->DistanceSqr < (0.0004f*0.0004f)) - { - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - getALError(); + if(chan->DistanceSqr < (0.0004f*0.0004f)) + { + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); + } + else + { + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + getALError(); } void OpenALSoundRenderer::UpdateListener(SoundListener *listener) { - if(!listener->valid) - return; + if(!listener->valid) + return; - alDeferUpdatesSOFT(); + alDeferUpdatesSOFT(); - float angle = listener->angle; - ALfloat orient[6]; - // forward - orient[0] = cosf(angle); - orient[1] = 0.f; - orient[2] = -sinf(angle); - // up - orient[3] = 0.f; - orient[4] = 1.f; - orient[5] = 0.f; + float angle = listener->angle; + ALfloat orient[6]; + // forward + orient[0] = cosf(angle); + orient[1] = 0.f; + orient[2] = -sinf(angle); + // up + orient[3] = 0.f; + orient[4] = 1.f; + orient[5] = 0.f; - alListenerfv(AL_ORIENTATION, orient); - alListener3f(AL_POSITION, listener->position.X, - listener->position.Y, - -listener->position.Z); - alListener3f(AL_VELOCITY, listener->velocity.X, - listener->velocity.Y, - -listener->velocity.Z); - getALError(); + alListenerfv(AL_ORIENTATION, orient); + alListener3f(AL_POSITION, listener->position.X, + listener->position.Y, + -listener->position.Z); + alListener3f(AL_VELOCITY, listener->velocity.X, + listener->velocity.Y, + -listener->velocity.Z); + getALError(); - const ReverbContainer *env = ForcedEnvironment; - if(!env) - { - env = listener->Environment; - if(!env) - env = DefaultEnvironments[0]; - } - if(env != PrevEnvironment || env->Modified) - { - PrevEnvironment = env; - DPrintf(DMSG_NOTIFY, "Reverb Environment %s\n", env->Name); + const ReverbContainer *env = ForcedEnvironment; + if(!env) + { + env = listener->Environment; + if(!env) + env = DefaultEnvironments[0]; + } + if(env != PrevEnvironment || env->Modified) + { + PrevEnvironment = env; + DPrintf(DMSG_NOTIFY, "Reverb Environment %s\n", env->Name); - if(EnvSlot != 0) - LoadReverb(env); + if(EnvSlot != 0) + LoadReverb(env); - const_cast(env)->Modified = false; - } + const_cast(env)->Modified = false; + } - // NOTE: Moving into and out of water will undo pitch variations on sounds. - if(listener->underwater || env->SoftwareWater) - { - if(!WasInWater) - { - WasInWater = true; + // NOTE: Moving into and out of water will undo pitch variations on sounds. + if(listener->underwater || env->SoftwareWater) + { + if(!WasInWater) + { + WasInWater = true; - if(EnvSlot != 0 && *snd_waterreverb) - { - // Find the "Underwater" reverb environment - env = S_FindEnvironment(0x1600); - LoadReverb(env ? env : DefaultEnvironments[0]); + if(EnvSlot != 0 && *snd_waterreverb) + { + // Find the "Underwater" reverb environment + env = S_FindEnvironment(0x1600); + LoadReverb(env ? env : DefaultEnvironments[0]); - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.125f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.125f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - // Apply the updated filters on the sources - for(uint32 i = 0;i < ReverbSfx.Size();++i) - { - alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - } + // Apply the updated filters on the sources + for(uint32 i = 0;i < ReverbSfx.Size();++i) + { + alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } - for(uint32 i = 0;i < ReverbSfx.Size();++i) - alSourcef(ReverbSfx[i], AL_PITCH, PITCH_MULT); - getALError(); - } - } - else if(WasInWater) - { - WasInWater = false; + for(uint32 i = 0;i < ReverbSfx.Size();++i) + alSourcef(ReverbSfx[i], AL_PITCH, PITCH_MULT); + getALError(); + } + } + else if(WasInWater) + { + WasInWater = false; - if(EnvSlot != 0) - { - LoadReverb(env); + if(EnvSlot != 0) + { + LoadReverb(env); - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - for(uint32 i = 0;i < ReverbSfx.Size();++i) - { - alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - } + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); + for(uint32 i = 0;i < ReverbSfx.Size();++i) + { + alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } - for(uint32 i = 0;i < ReverbSfx.Size();++i) - alSourcef(ReverbSfx[i], AL_PITCH, 1.f); - getALError(); - } + for(uint32 i = 0;i < ReverbSfx.Size();++i) + alSourcef(ReverbSfx[i], AL_PITCH, 1.f); + getALError(); + } } void OpenALSoundRenderer::UpdateSounds() { - alProcessUpdatesSOFT(); + alProcessUpdatesSOFT(); - if(ALC.EXT_disconnect) - { - ALCint connected = ALC_TRUE; - alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); - if(connected == ALC_FALSE) - { - Printf("Sound device disconnected; restarting...\n"); - static char snd_reset[] = "snd_reset"; - AddCommandString(snd_reset); - return; - } - } + if(ALC.EXT_disconnect) + { + ALCint connected = ALC_TRUE; + alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); + if(connected == ALC_FALSE) + { + Printf("Sound device disconnected; restarting...\n"); + static char snd_reset[] = "snd_reset"; + AddCommandString(snd_reset); + return; + } + } - PurgeStoppedSources(); + PurgeStoppedSources(); } bool OpenALSoundRenderer::IsValid() { - return Device != NULL; + return Device != NULL; } void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan) { - // FIXME: Get current time (preferably from the audio clock, but the system - // time will have to do) - chan->StartTime.AsOne = std::chrono::steady_clock::now().time_since_epoch().count(); + // FIXME: Get current time (preferably from the audio clock, but the system + // time will have to do) + chan->StartTime.AsOne = std::chrono::steady_clock::now().time_since_epoch().count(); } float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) { - if(chan == NULL || chan->SysChannel == NULL) - return 0.f; + if(chan == NULL || chan->SysChannel == NULL) + return 0.f; - ALuint source = GET_PTRID(chan->SysChannel); - ALfloat volume = 0.f; + ALuint source = GET_PTRID(chan->SysChannel); + ALfloat volume = 0.f; - alGetSourcef(source, AL_GAIN, &volume); - getALError(); + alGetSourcef(source, AL_GAIN, &volume); + getALError(); - volume *= GetRolloff(&chan->Rolloff, sqrtf(chan->DistanceSqr) * chan->DistanceScale); - return volume; + volume *= GetRolloff(&chan->Rolloff, sqrtf(chan->DistanceSqr) * chan->DistanceScale); + return volume; } void OpenALSoundRenderer::PrintStatus() { - Printf("Output device: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); - getALCError(Device); + Printf("Output device: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); + getALCError(Device); - ALCint frequency, major, minor, mono, stereo; - alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); - alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); - alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &mono); - alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &stereo); - if(getALCError(Device) == AL_NO_ERROR) - { - Printf("Device sample rate: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL"hz\n", frequency); - Printf("ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); - Printf("ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - Printf("Available sources: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" (" TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" mono, " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" stereo)\n", mono+stereo, mono, stereo); - } - if(!alcIsExtensionPresent(Device, "ALC_EXT_EFX")) - Printf("EFX not found\n"); - else - { - ALCint sends; - alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &minor); - alcGetIntegerv(Device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); - if(getALCError(Device) == AL_NO_ERROR) - { - Printf("EFX Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); - Printf("Auxiliary sends: " TEXTCOLOR_BLUE"%d\n", sends); - } - } - Printf("Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); - Printf("Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); - Printf("Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); - Printf("Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - getALError(); + ALCint frequency, major, minor, mono, stereo; + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &mono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &stereo); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("Device sample rate: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL"hz\n", frequency); + Printf("ALC Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("ALC Extensions: " TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + Printf("Available sources: " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" (" TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" mono, " TEXTCOLOR_BLUE"%d" TEXTCOLOR_NORMAL" stereo)\n", mono+stereo, mono, stereo); + } + if(!alcIsExtensionPresent(Device, "ALC_EXT_EFX")) + Printf("EFX not found\n"); + else + { + ALCint sends; + alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("EFX Version: " TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("Auxiliary sends: " TEXTCOLOR_BLUE"%d\n", sends); + } + } + Printf("Vendor: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + Printf("Renderer: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + Printf("Version: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + Printf("Extensions: " TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + getALError(); } FString OpenALSoundRenderer::GatherStats() { - ALCint updates = 1; - alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); - getALCError(Device); + ALCint updates = 1; + alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); + getALCError(Device); - uint32 total = Sources.Size(); - uint32 used = SfxGroup.Size()+Streams.Size(); - uint32 unused = FreeSfx.Size(); + uint32 total = Sources.Size(); + uint32 used = SfxGroup.Size()+Streams.Size(); + uint32 unused = FreeSfx.Size(); - FString out; - out.Format("%u sources (" TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" active, " TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" free), Update interval: " TEXTCOLOR_YELLOW"%d" TEXTCOLOR_NORMAL"ms", - total, used, unused, 1000/updates); - return out; + FString out; + out.Format("%u sources (" TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" active, " TEXTCOLOR_YELLOW"%u" TEXTCOLOR_NORMAL" free), Update interval: " TEXTCOLOR_YELLOW"%d" TEXTCOLOR_NORMAL"ms", + total, used, unused, 1000/updates); + return out; } void OpenALSoundRenderer::PrintDriversList() { - const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? - alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : - alcGetString(NULL, ALC_DEVICE_SPECIFIER)); - if(drivers == NULL) - { - Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); - return; - } + const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + if(drivers == NULL) + { + Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + return; + } - const ALCchar *current = NULL; - if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) - current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); - if(alcGetError(Device) != ALC_NO_ERROR || !current) - current = alcGetString(Device, ALC_DEVICE_SPECIFIER); - if(current == NULL) - { - Printf(TEXTCOLOR_YELLOW"Failed to retrieve device name: %s\n", alcGetString(Device, alcGetError(Device))); - return; - } + const ALCchar *current = NULL; + if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) + current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); + if(alcGetError(Device) != ALC_NO_ERROR || !current) + current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + if(current == NULL) + { + Printf(TEXTCOLOR_YELLOW"Failed to retrieve device name: %s\n", alcGetString(Device, alcGetError(Device))); + return; + } - Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, - "Default"); - for(int i = 1;*drivers;i++) - { - Printf("%c%s%2d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), - ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, - drivers); - drivers += strlen(drivers)+1; - } + Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, + "Default"); + for(int i = 1;*drivers;i++) + { + Printf("%c%s%2d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), + ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, + drivers); + drivers += strlen(drivers)+1; + } } void OpenALSoundRenderer::PurgeStoppedSources() { - // Release channels that are stopped - for(uint32 i = 0;i < SfxGroup.Size();++i) - { - ALuint src = SfxGroup[i]; - ALint state = AL_INITIAL; - alGetSourcei(src, AL_SOURCE_STATE, &state); - if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED) - continue; + // Release channels that are stopped + for(uint32 i = 0;i < SfxGroup.Size();++i) + { + ALuint src = SfxGroup[i]; + ALint state = AL_INITIAL; + alGetSourcei(src, AL_SOURCE_STATE, &state); + if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED) + continue; - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel)) - { - StopChannel(schan); - break; - } - schan = schan->NextChan; - } - } - getALError(); + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel)) + { + StopChannel(schan); + break; + } + schan = schan->NextChan; + } + } + getALError(); } void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) { - ALuint *envReverb = EnvEffects.CheckKey(env->ID); - bool doLoad = (env->Modified || !envReverb); + ALuint *envReverb = EnvEffects.CheckKey(env->ID); + bool doLoad = (env->Modified || !envReverb); - if(!envReverb) - { - bool ok = false; + if(!envReverb) + { + bool ok = false; - envReverb = &EnvEffects.Insert(env->ID, 0); - alGenEffects(1, envReverb); - if(getALError() == AL_NO_ERROR) - { - alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - ok = (alGetError() == AL_NO_ERROR); - if(!ok) - { - alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - ok = (alGetError() == AL_NO_ERROR); - } - if(!ok) - { - alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); - ok = (alGetError() == AL_NO_ERROR); - } - if(!ok) - { - alDeleteEffects(1, envReverb); - getALError(); - } - } - if(!ok) - { - *envReverb = 0; - doLoad = false; - } - } + envReverb = &EnvEffects.Insert(env->ID, 0); + alGenEffects(1, envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + ok = (alGetError() == AL_NO_ERROR); + if(!ok) + { + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alDeleteEffects(1, envReverb); + getALError(); + } + } + if(!ok) + { + *envReverb = 0; + doLoad = false; + } + } - if(doLoad) - { - const REVERB_PROPERTIES &props = env->Properties; - ALint type = AL_EFFECT_NULL; + if(doLoad) + { + const REVERB_PROPERTIES &props = env->Properties; + ALint type = AL_EFFECT_NULL; - alGetEffecti(*envReverb, AL_EFFECT_TYPE, &type); + alGetEffecti(*envReverb, AL_EFFECT_TYPE, &type); #define mB2Gain(x) ((float)pow(10., (x)/2000.)) - if(type == AL_EFFECT_EAXREVERB) - { - ALfloat reflectpan[3] = { props.ReflectionsPan0, - props.ReflectionsPan1, - props.ReflectionsPan2 }; - ALfloat latepan[3] = { props.ReverbPan0, props.ReverbPan1, - props.ReverbPan2 }; + if(type == AL_EFFECT_EAXREVERB) + { + ALfloat reflectpan[3] = { props.ReflectionsPan0, + props.ReflectionsPan1, + props.ReflectionsPan2 }; + ALfloat latepan[3] = { props.ReverbPan0, props.ReverbPan1, + props.ReverbPan2 }; #undef SETPARAM #define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) - SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); - SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); - SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(*envReverb, GAINLF, mB2Gain(props.RoomLF)); - SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(*envReverb, DECAY_LFRATIO, props.DecayLFRatio); - SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - alEffectfv(*envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); - SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - alEffectfv(*envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); - SETPARAM(*envReverb, ECHO_TIME, props.EchoTime); - SETPARAM(*envReverb, ECHO_DEPTH, props.EchoDepth); - SETPARAM(*envReverb, MODULATION_TIME, props.ModulationTime); - SETPARAM(*envReverb, MODULATION_DEPTH, props.ModulationDepth); - SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(*envReverb, HFREFERENCE, props.HFReference); - SETPARAM(*envReverb, LFREFERENCE, props.LFReference); - SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(*envReverb, AL_EAXREVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); + SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); + SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(*envReverb, GAINLF, mB2Gain(props.RoomLF)); + SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(*envReverb, DECAY_LFRATIO, props.DecayLFRatio); + SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + alEffectfv(*envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); + SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + alEffectfv(*envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); + SETPARAM(*envReverb, ECHO_TIME, props.EchoTime); + SETPARAM(*envReverb, ECHO_DEPTH, props.EchoDepth); + SETPARAM(*envReverb, MODULATION_TIME, props.ModulationTime); + SETPARAM(*envReverb, MODULATION_DEPTH, props.ModulationDepth); + SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(*envReverb, HFREFERENCE, props.HFReference); + SETPARAM(*envReverb, LFREFERENCE, props.LFReference); + SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(*envReverb, AL_EAXREVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); #undef SETPARAM - } - else if(type == AL_EFFECT_REVERB) - { + } + else if(type == AL_EFFECT_REVERB) + { #define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) - SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); - SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); - SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(*envReverb, AL_REVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); + SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); + SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(*envReverb, AL_REVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); #undef SETPARAM - } + } #undef mB2Gain - } + } - alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, *envReverb); - getALError(); + alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, *envReverb); + getALError(); } FSoundChan *OpenALSoundRenderer::FindLowestChannel() { - FSoundChan *schan = Channels; - FSoundChan *lowest = NULL; - while(schan) - { - if(schan->SysChannel != NULL) - { - if(!lowest || schan->Priority < lowest->Priority || - (schan->Priority == lowest->Priority && - schan->DistanceSqr > lowest->DistanceSqr)) - lowest = schan; - } - schan = schan->NextChan; - } - return lowest; + FSoundChan *schan = Channels; + FSoundChan *lowest = NULL; + while(schan) + { + if(schan->SysChannel != NULL) + { + if(!lowest || schan->Priority < lowest->Priority || + (schan->Priority == lowest->Priority && + schan->DistanceSqr > lowest->DistanceSqr)) + lowest = schan; + } + schan = schan->NextChan; + } + return lowest; } #endif // NO_OPENAL From c4cb94123f0a6eb78144ab0cbcd00b43f1a05698 Mon Sep 17 00:00:00 2001 From: Thomas Hume Date: Thu, 23 Feb 2017 20:26:26 +0100 Subject: [PATCH 085/207] Do not change indentation of the licence... --- src/sound/oalsound.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index aa35b03b5a..601ec72002 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -11,12 +11,12 @@ ** are met: ** ** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. +** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. +** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES From 5bc26763cbb445bfddd7bf0b3363ec1a36b3624d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 22:01:01 +0100 Subject: [PATCH 086/207] - fixed: String CVARs get stored as a const char *, not an FString, so the ls opcode cannot be used to read their content. --- src/scripting/backend/codegen.cpp | 2 +- src/scripting/vm/vmexec.h | 10 ++++++++++ src/scripting/vm/vmops.h | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 252788023a..cc93c22156 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6522,7 +6522,7 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) case CVAR_String: build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); - build->Emit(OP_LS, dest.RegNum, addr.RegNum, nul); + build->Emit(OP_LCS, dest.RegNum, addr.RegNum, nul); break; case CVAR_DummyBool: diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 8da2c4d8d0..3082abf802 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -197,6 +197,16 @@ begin: GETADDR(PB,RC,X_READ_NIL); reg.s[a] = *(FString *)ptr; NEXTOP; + OP(LCS): + ASSERTS(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + reg.s[a] = *(const char **)ptr; + NEXTOP; + OP(LCS_R): + ASSERTS(a); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + reg.s[a] = *(const char **)ptr; + NEXTOP; OP(LO): ASSERTA(a); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 6f3931531b..b058dc94b6 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -52,6 +52,8 @@ xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2 xx(LV2_R, lv2, RVRPRI, NOP, 0, 0), xx(LV3, lv3, RVRPKI, LV3_R, 4, REGT_INT), // load vector3 xx(LV3_R, lv3, RVRPRI, NOP, 0, 0), +xx(LCS, lcs, RSRPKI, LCS_R, 4, REGT_INT), // load string from char ptr. +xx(LCS_R, lcs, RSRPRI, NOP, 0, 0), xx(LBIT, lbit, RIRPI8, NOP, 0, 0), // rA = !!(*rB & C) -- *rB is a byte From a1328b4c6ec25d9d834e2630e77ed8b0601b02a8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 22:09:50 +0100 Subject: [PATCH 087/207] - do not adjust the sprite offset for the WolfSS's attack and pain states. This will cause problems with sprite clipping off. --- wadsrc/static/filter/doom.doom1/sprofs.txt | 2 -- wadsrc/static/filter/doom.doom2/sprofs.txt | 2 -- 2 files changed, 4 deletions(-) diff --git a/wadsrc/static/filter/doom.doom1/sprofs.txt b/wadsrc/static/filter/doom.doom1/sprofs.txt index eab3dc4ef0..1485959efd 100644 --- a/wadsrc/static/filter/doom.doom1/sprofs.txt +++ b/wadsrc/static/filter/doom.doom1/sprofs.txt @@ -111,8 +111,6 @@ SPIDR0, 110, 111, iwad SPIDS0, 98, 35, iwad SPOSH0, 14, 60, iwad SPOSL0, 24, 15, iwad -SSWVG0, 17, 55, iwad -SSWVH0, 17, 52, iwad SSWVI0, 18, 54, iwad SSWVJ0, 15, 44, iwad SSWVK0, 15, 40, iwad diff --git a/wadsrc/static/filter/doom.doom2/sprofs.txt b/wadsrc/static/filter/doom.doom2/sprofs.txt index eab3dc4ef0..1485959efd 100644 --- a/wadsrc/static/filter/doom.doom2/sprofs.txt +++ b/wadsrc/static/filter/doom.doom2/sprofs.txt @@ -111,8 +111,6 @@ SPIDR0, 110, 111, iwad SPIDS0, 98, 35, iwad SPOSH0, 14, 60, iwad SPOSL0, 24, 15, iwad -SSWVG0, 17, 55, iwad -SSWVH0, 17, 52, iwad SSWVI0, 18, 54, iwad SSWVJ0, 15, 44, iwad SSWVK0, 15, 40, iwad From 58be506a73411f1307b30507aeca509cb2076cb2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 24 Feb 2017 00:28:33 +0100 Subject: [PATCH 088/207] - made intermission screen more scripting friendly. --- src/g_hub.cpp | 3 +- src/g_level.cpp | 1 - src/wi_stuff.cpp | 84 ++++++++++++++-------- src/wi_stuff.h | 2 - wadsrc/static/zscript.txt | 2 + wadsrc/static/zscript/statscreen/types.txt | 43 +++++++++++ 6 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 wadsrc/static/zscript/statscreen/types.txt diff --git a/src/g_hub.cpp b/src/g_hub.cpp index e87dcff7d9..ecf3106ce4 100644 --- a/src/g_hub.cpp +++ b/src/g_hub.cpp @@ -154,8 +154,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, wbplayerstruct_t &h, w { if (arc.BeginObject(key)) { - arc("in", h.in) - ("kills", h.skills) + arc("kills", h.skills) ("items", h.sitems) ("secrets", h.ssecret) ("time", h.stime) diff --git a/src/g_level.cpp b/src/g_level.cpp index 5f074ddb35..ab97ced006 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -816,7 +816,6 @@ void G_DoCompleted (void) for (i=0 ; ipnum EState state; // specifies current state wbstartstruct_t *wbs; // contains information passed into intermission - wbplayerstruct_t*plrs; // wbs->plyr[] + wbplayerstruct_t* Plrs[MAXPLAYERS]; // wbs->plyr[] int cnt; // used for general timing int bcnt; // used for timing of background animation int cnt_kills[MAXPLAYERS]; @@ -1192,12 +1192,12 @@ public: if (playeringame[i] && i!=playernum) { - frags += plrs[playernum].frags[i]; + frags += Plrs[playernum]->frags[i]; } } // JDC hack - negative frags. - frags -= plrs[playernum].frags[playernum]; + frags -= Plrs[playernum]->frags[playernum]; return frags; } @@ -1225,9 +1225,9 @@ public: { for (j = 0; j < MAXPLAYERS; j++) if (playeringame[j]) - player_deaths[i] += plrs[j].frags[i]; + player_deaths[i] += Plrs[j]->frags[i]; total_deaths += player_deaths[i]; - total_frags += plrs[i].fragcount; + total_frags += Plrs[i]->fragcount; } } } @@ -1250,7 +1250,7 @@ public: if (!playeringame[i]) continue; - cnt_frags[i] = plrs[i].fragcount; + cnt_frags[i] = Plrs[i]->fragcount; cnt_deaths[i] = player_deaths[i]; } S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); @@ -1271,8 +1271,8 @@ public: cnt_frags[i] += 2; - if (cnt_frags[i] > plrs[i].fragcount) - cnt_frags[i] = plrs[i].fragcount; + if (cnt_frags[i] > Plrs[i]->fragcount) + cnt_frags[i] = Plrs[i]->fragcount; else stillticking = true; } @@ -1443,7 +1443,7 @@ public: // Draw game time y += height + CleanYfac; - int seconds = Tics2Seconds(plrs[me].stime); + int seconds = Tics2Seconds(Plrs[me]->stime); int hours = seconds / 3600; int minutes = (seconds % 3600) / 60; seconds = seconds % 60; @@ -1502,9 +1502,9 @@ public: if (!playeringame[i]) continue; - cnt_kills[i] = plrs[i].skills; - cnt_items[i] = plrs[i].sitems; - cnt_secret[i] = plrs[i].ssecret; + cnt_kills[i] = Plrs[i]->skills; + cnt_items[i] = Plrs[i]->sitems; + cnt_secret[i] = Plrs[i]->ssecret; if (dofrags) cnt_frags[i] = WI_fragSum (i); @@ -1527,8 +1527,8 @@ public: cnt_kills[i] += 2; - if (cnt_kills[i] > plrs[i].skills) - cnt_kills[i] = plrs[i].skills; + if (cnt_kills[i] > Plrs[i]->skills) + cnt_kills[i] = Plrs[i]->skills; else stillticking = true; } @@ -1552,8 +1552,8 @@ public: continue; cnt_items[i] += 2; - if (cnt_items[i] > plrs[i].sitems) - cnt_items[i] = plrs[i].sitems; + if (cnt_items[i] > Plrs[i]->sitems) + cnt_items[i] = Plrs[i]->sitems; else stillticking = true; } @@ -1577,8 +1577,8 @@ public: cnt_secret[i] += 2; - if (cnt_secret[i] > plrs[i].ssecret) - cnt_secret[i] = plrs[i].ssecret; + if (cnt_secret[i] > Plrs[i]->ssecret) + cnt_secret[i] = Plrs[i]->ssecret; else stillticking = true; } @@ -1794,10 +1794,10 @@ public: sp_state = 10; S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - cnt_kills[0] = plrs[me].skills; - cnt_items[0] = plrs[me].sitems; - cnt_secret[0] = plrs[me].ssecret; - cnt_time = Tics2Seconds(plrs[me].stime); + cnt_kills[0] = Plrs[me]->skills; + cnt_items[0] = Plrs[me]->sitems; + cnt_secret[0] = Plrs[me]->ssecret; + cnt_time = Tics2Seconds(Plrs[me]->stime); cnt_par = wbs->partime / TICRATE; cnt_total_time = Tics2Seconds(wbs->totaltime); } @@ -1811,9 +1811,9 @@ public: if (!(bcnt&3)) S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); } - if (!gameinfo.intermissioncounter || cnt_kills[0] >= plrs[me].skills) + if (!gameinfo.intermissioncounter || cnt_kills[0] >= Plrs[me]->skills) { - cnt_kills[0] = plrs[me].skills; + cnt_kills[0] = Plrs[me]->skills; S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); sp_state++; } @@ -1827,9 +1827,9 @@ public: if (!(bcnt&3)) S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); } - if (!gameinfo.intermissioncounter || cnt_items[0] >= plrs[me].sitems) + if (!gameinfo.intermissioncounter || cnt_items[0] >= Plrs[me]->sitems) { - cnt_items[0] = plrs[me].sitems; + cnt_items[0] = Plrs[me]->sitems; S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); sp_state++; } @@ -1843,9 +1843,9 @@ public: if (!(bcnt&3)) S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); } - if (!gameinfo.intermissioncounter || cnt_secret[0] >= plrs[me].ssecret) + if (!gameinfo.intermissioncounter || cnt_secret[0] >= Plrs[me]->ssecret) { - cnt_secret[0] = plrs[me].ssecret; + cnt_secret[0] = Plrs[me]->ssecret; S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); sp_state++; } @@ -1862,7 +1862,7 @@ public: cnt_total_time += 3; } - int sec = Tics2Seconds(plrs[me].stime); + int sec = Tics2Seconds(Plrs[me]->stime); if (!gameinfo.intermissioncounter || cnt_time >= sec) cnt_time = sec; @@ -2141,7 +2141,7 @@ public: acceleratestage = 0; cnt = bcnt = 0; me = wbs->pnum; - plrs = wbs->plyr; + for (int i = 0; i < 8; i++) Plrs[i] = &wbs->plyr[i]; } void WI_Start (wbstartstruct_t *wbstartstruct) @@ -2180,3 +2180,27 @@ void WI_Start(wbstartstruct_t *wbstartstruct) { WI_Screen.WI_Start(wbstartstruct); } + + +DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, skills); +DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, sitems); +DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, ssecret); +DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, stime); +DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, frags); +DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, fragcount); + +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, finished_ep); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, next_ep); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, current); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, next); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName0); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName1); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxkills); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxitems); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxsecret); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxfrags); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, partime); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, sucktime); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, totaltime); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, pnum); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, plyr); diff --git a/src/wi_stuff.h b/src/wi_stuff.h index 8670b759f7..04acb1231e 100644 --- a/src/wi_stuff.h +++ b/src/wi_stuff.h @@ -32,8 +32,6 @@ class FTexture; // struct wbplayerstruct_t { - bool in; // whether the player is in game - // Player stats, kills, collected items etc. int skills; int sitems; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 528431575a..bf7f75f188 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -25,6 +25,8 @@ #include "zscript/menu/readthis.txt" #include "zscript/menu/conversationmenu.txt" +#include "zscript/statscreen/types.txt" + #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt" #include "zscript/inventory/stateprovider.txt" diff --git a/wadsrc/static/zscript/statscreen/types.txt b/wadsrc/static/zscript/statscreen/types.txt new file mode 100644 index 0000000000..57080643e4 --- /dev/null +++ b/wadsrc/static/zscript/statscreen/types.txt @@ -0,0 +1,43 @@ + +// +// INTERMISSION +// Structure passed e.g. to WI_Start(wb) +// +struct WBPlayerStruct native +{ + // Player stats, kills, collected items etc. + native int skills; + native int sitems; + native int ssecret; + native int stime; + native int frags[MAXPLAYERS]; + native int fragcount; // [RH] Cumulative frags for this player +} + +struct WBStartStruct native +{ + native int finished_ep; + native int next_ep; + + native String current; // [RH] Name of map just finished + native String next; // next level, [RH] actual map name + + native TextureID LName0; + native TextureID LName1; + + native int maxkills; + native int maxitems; + native int maxsecret; + native int maxfrags; + + // the par time and sucktime + native int partime; // in tics + native int sucktime; // in minutes + + // total time for the entire current game + native int totaltime; + + // index of this player in game + native int pnum; +} + From 202c192e1135ad30031381e3be19710db7cd2b1f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 24 Feb 2017 10:15:32 +0200 Subject: [PATCH 089/207] Added default value for amount argument of A_DropInventory() https://mantis.zdoom.org/view.php?id=330 --- wadsrc/static/zscript/actor.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index fc31b75d9e..815ffd4796 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -787,7 +787,7 @@ class Actor : Thinker native native void A_SpawnDebris(class spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1); native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); - native void A_DropInventory(class itemtype, int amount); + native void A_DropInventory(class itemtype, int amount = -1); native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0); deprecated native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); From fd615713d532c3f571fd95144bd493d41e3e0486 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 24 Feb 2017 11:09:25 +0200 Subject: [PATCH 090/207] Fixed handling of default values for Menu.SetMenu() and Menu.StartMessage() arguments --- src/menu/menu.cpp | 2 +- src/menu/messagebox.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index e4920ef55a..71c0ff6453 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -496,7 +496,7 @@ DEFINE_ACTION_FUNCTION(DMenu, SetMenu) { PARAM_PROLOGUE; PARAM_NAME(menu); - PARAM_INT(mparam); + PARAM_INT_DEF(mparam); M_SetMenu(menu, mparam); return 0; } diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index b3b0e1fe78..a1a0fda769 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -267,7 +267,7 @@ DEFINE_ACTION_FUNCTION(DMenu, StartMessage) { PARAM_PROLOGUE; PARAM_STRING(msg); - PARAM_INT(mode); + PARAM_INT_DEF(mode); PARAM_NAME_DEF(action); M_StartMessage(msg, mode, action); return 0; From c6a5e74c75b638e8743469024bf578405bc0104a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 9 Feb 2017 14:35:45 +0100 Subject: [PATCH 091/207] - added GC support to the events. OF_Fixed is not recommended because it can seriously impede the GC's functionality if just being used as a lazy means to avoid collection. --- src/dobjgc.cpp | 3 +++ src/events.cpp | 30 ++++++++++++++++++++++++++---- src/events.h | 3 +++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 3d683aff11..4f0aa20db4 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -78,6 +78,7 @@ #include "menu/menu.h" #include "intermission/intermission.h" #include "g_levellocals.h" +#include "events.h" // MACROS ------------------------------------------------------------------ @@ -331,6 +332,8 @@ static void MarkRoot() DThinker::MarkRoots(); FCanvasTextureInfo::Mark(); Mark(DACSThinker::ActiveThinker); + Mark(E_FirstEventHandler); + Mark(E_LastEventHandler); for (auto &s : level.sectorPortals) { Mark(s.mSkybox); diff --git a/src/events.cpp b/src/events.cpp index 4522f19892..afa98c99d2 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -37,32 +37,42 @@ bool E_RegisterHandler(DStaticEventHandler* handler) // 2. MyHandler3->2: // E_FirstEventHandler = MyHandler2, E_LastEventHandler = MyHandler3 + // (Yes, all those write barriers here are really needed!) if (before != nullptr) { // if before is not null, link it before the existing handler. // note that before can be first handler, check for this. handler->next = before; + GC::WriteBarrier(handler, before); handler->prev = before->prev; + GC::WriteBarrier(handler, before->prev); before->prev = handler; + GC::WriteBarrier(before, handler); if (before == E_FirstEventHandler) + { E_FirstEventHandler = handler; + GC::WriteBarrier(handler); + } } else { // so if before is null, it means add last. // it can also mean that we have no handlers at all yet. handler->prev = E_LastEventHandler; + GC::WriteBarrier(handler, E_LastEventHandler); handler->next = nullptr; - if (E_FirstEventHandler == nullptr) - E_FirstEventHandler = handler; + if (E_FirstEventHandler == nullptr) E_FirstEventHandler = handler; E_LastEventHandler = handler; + GC::WriteBarrier(handler); if (handler->prev != nullptr) + { handler->prev->next = handler; + GC::WriteBarrier(handler->prev, handler); + } } if (handler->IsStatic()) { - handler->ObjectFlags |= OF_Fixed; handler->ObjectFlags |= OF_Transient; } @@ -80,16 +90,28 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) // link out of normal list if (handler->prev) + { handler->prev->next = handler->next; + GC::WriteBarrier(handler->prev, handler->next); + } if (handler->next) + { handler->next->prev = handler->prev; + GC::WriteBarrier(handler->next, handler->prev); + } if (handler == E_FirstEventHandler) + { E_FirstEventHandler = handler->next; + GC::WriteBarrier(handler->next); + } if (handler == E_LastEventHandler) + { E_LastEventHandler = handler->prev; + GC::WriteBarrier(handler->prev); + } if (handler->IsStatic()) { - handler->ObjectFlags &= ~(OF_Fixed|OF_Transient); + handler->ObjectFlags &= ~OF_Transient; handler->Destroy(); } return true; diff --git a/src/events.h b/src/events.h index 71c8a27f67..f51a9ae6fc 100755 --- a/src/events.h +++ b/src/events.h @@ -77,6 +77,7 @@ void E_SerializeEvents(FSerializer& arc); class DStaticEventHandler : public DObject // make it a part of normal GC process { DECLARE_CLASS(DStaticEventHandler, DObject) + HAS_OBJECT_POINTERS public: DStaticEventHandler() { @@ -99,6 +100,7 @@ public: void Serialize(FSerializer& arc) override { Super::Serialize(arc); + /* if (arc.isReading()) { Printf("DStaticEventHandler::Serialize: reading object %s\n", GetClass()->TypeName.GetChars()); @@ -107,6 +109,7 @@ public: { Printf("DStaticEventHandler::Serialize: store object %s\n", GetClass()->TypeName.GetChars()); } + */ arc("Order", Order); arc("IsUiProcessor", IsUiProcessor); From 555f33992487b21b8a6591c94a728ab2733938d4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 24 Feb 2017 19:00:10 +0100 Subject: [PATCH 092/207] - fixed: Sight checks through portals must disable all early-outs. These can also be triggered from lines outside the actually valid range because the checks are done before the lines get ordered by distance. --- src/events.h | 1 + src/p_sight.cpp | 77 ++++++++++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/events.h b/src/events.h index f51a9ae6fc..46ed88b957 100755 --- a/src/events.h +++ b/src/events.h @@ -158,6 +158,7 @@ public: bool IsStatic() override { return false; } }; extern DStaticEventHandler* E_FirstEventHandler; +extern DStaticEventHandler* E_LastEventHandler; // we cannot call this DEvent because in ZScript, 'event' is a keyword class DBaseEvent : public DObject diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 74b9fe1658..68bf2ed3d0 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -107,6 +107,7 @@ class SightCheck bool P_SightCheckLine (line_t *ld); int P_SightBlockLinesIterator (int x, int y); bool P_SightTraverseIntercepts (); + bool LineBlocksSight(line_t *ld); public: bool P_SightPathTraverse (); @@ -211,7 +212,14 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) double trX = Trace.x + Trace.dx * in->frac; double trY = Trace.y + Trace.dy * in->frac; - P_SightOpening (open, li, trX, trY); + + P_SightOpening(open, li, trX, trY); + if (LineBlocksSight(in->d.line)) + { + // This may not skip P_SightOpening, but only reduce the open range to 0. + open.range = 0; + open.bottom = open.top; + } FLinePortal *lport = li->getPortal(); @@ -362,6 +370,42 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) } +// performs trivial visibility checks. +bool SightCheck::LineBlocksSight(line_t *ld) +{ + // try to early out the check + if (!ld->backsector || !(ld->flags & ML_TWOSIDED) || (ld->flags & ML_BLOCKSIGHT)) + return true; // stop checking + + // [RH] don't see past block everything lines + if (ld->flags & ML_BLOCKEVERYTHING) + { + if (!(Flags & SF_SEEPASTBLOCKEVERYTHING)) + { + return true; + } + // Pretend the other side is invisible if this is not an impact line + // that runs a script on the current map. Used to prevent monsters + // from trying to attack through a block everything line unless + // there's a chance their attack will make it nonblocking. + if (!(Flags & SF_SEEPASTSHOOTABLELINES)) + { + if (!(ld->activation & SPAC_Impact)) + { + return true; + } + if (ld->special != ACS_Execute && ld->special != ACS_ExecuteAlways) + { + return true; + } + if (ld->args[1] != 0 && ld->args[1] != level.levelnum) + { + return true; + } + } + } + return false; +} /* ================== @@ -392,36 +436,9 @@ bool SightCheck::P_SightCheckLine (line_t *ld) return true; // line isn't crossed } - // try to early out the check - if (!ld->backsector || !(ld->flags & ML_TWOSIDED) || (ld->flags & ML_BLOCKSIGHT)) - return false; // stop checking - - // [RH] don't see past block everything lines - if (ld->flags & ML_BLOCKEVERYTHING) + if (!portalfound) // when portals come into play, the quick-outs here may not be performed { - if (!(Flags & SF_SEEPASTBLOCKEVERYTHING)) - { - return false; - } - // Pretend the other side is invisible if this is not an impact line - // that runs a script on the current map. Used to prevent monsters - // from trying to attack through a block everything line unless - // there's a chance their attack will make it nonblocking. - if (!(Flags & SF_SEEPASTSHOOTABLELINES)) - { - if (!(ld->activation & SPAC_Impact)) - { - return false; - } - if (ld->special != ACS_Execute && ld->special != ACS_ExecuteAlways) - { - return false; - } - if (ld->args[1] != 0 && ld->args[1] != level.levelnum) - { - return false; - } - } + if (LineBlocksSight(ld)) return false; } sightcounts[3]++; From 43c5fa93f93f09d9c13d69d9fe09b23237548b52 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 24 Feb 2017 21:45:53 +0100 Subject: [PATCH 093/207] - fixed handling of PlayerEntered event. This was done in P_SpawnPlayer where it would be called not only on voodoo dolls but also on temporary player pawns. The second case was attempted to avoid, but this would break intra-hub travels to unvisited levels. Moved the handling to G_DoLoadLevel for all cases where we have a clear and unambiguous situation with all players being set up and no voodoo dolls that might trigger an event. --- src/g_level.cpp | 36 ++++++++++++++++++------------------ src/p_mobj.cpp | 3 --- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index ab97ced006..b811c12153 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -125,6 +125,7 @@ int starttime; extern FString BackupSaveName; bool savegamerestore; +int finishstate; extern int mousex, mousey; extern bool sendpause, sendsave, sendturn180, SendLand; @@ -160,6 +161,7 @@ void G_DeferedInitNew (FGameStartup *gs) d_skill = gs->Skill; CheckWarpTransMap (d_mapname, true); gameaction = ga_newgame2; + finishstate = FINISH_NoHub; } //========================================================================== @@ -897,6 +899,7 @@ void G_DoCompleted (void) } gamestate = GS_INTERMISSION; + finishstate = mode; viewactive = false; automapactive = false; @@ -1068,11 +1071,24 @@ void G_DoLoadLevel (int position, bool autosave) // For each player, if they are viewing through a player, make sure it is themselves. for (int ii = 0; ii < MAXPLAYERS; ++ii) { - if (playeringame[ii] && (players[ii].camera == NULL || players[ii].camera->player != NULL)) + if (playeringame[ii]) { - players[ii].camera = players[ii].mo; + if (players[ii].camera == NULL || players[ii].camera->player != NULL) + { + players[ii].camera = players[ii].mo; + } + E_PlayerEntered(ii, finishstate == FINISH_SameHub); + // ENTER scripts are being handled when the player gets spawned, this cannot be changed due to its effect on voodoo dolls. + if (level.FromSnapshot) FBehavior::StaticStartTypedScripts(SCRIPT_Return, players[ii].mo, true); } } + + if (level.FromSnapshot) + { + // [Nash] run REOPEN scripts upon map re-entry + FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); + } + StatusBar->AttachToPlayer (&players[consoleplayer]); // unsafe world load E_WorldLoadedUnsafe(); @@ -1354,22 +1370,6 @@ void G_FinishTravel () pawns[pawnsnum++] = pawn; } - // [ZZ] fire the reopen hook. - // if level is loaded from snapshot, and we don't have savegamerestore, this means we returned from a hub. - if (level.FromSnapshot) - { - // [Nash] run REOPEN scripts upon map re-entry - FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); - - for (int i = 0; i < pawnsnum; i++) - { - // [ZZ] fire the enter hook. - E_PlayerEntered(int(pawns[i]->player - players), true); - // - FBehavior::StaticStartTypedScripts(SCRIPT_Return, pawns[i], true); - } - } - bglobal.FinishTravel (); // make sure that, after travelling has completed, no travelling thinkers are left. diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ef5908fda4..fd0df678b9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5511,9 +5511,6 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) { if (state == PST_ENTER || (state == PST_LIVE && !savegamerestore)) { - // [ZZ] fire non-hub ENTER event - // level.time is a hack to make sure that we don't call it on dummy player initialization during hub return. - if (!level.time) E_PlayerEntered(int(p - players), false); FBehavior::StaticStartTypedScripts (SCRIPT_Enter, p->mo, true); } else if (state == PST_REBORN) From 10c6b7a80bb3471b35af5045b48371ba23ad0d9b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 10:57:12 +0100 Subject: [PATCH 094/207] - added a NULL check to the VM's entry point, in case some bad but non-fatal DECORATE results in a function not having generated any code. --- src/scripting/vm/vmframe.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index d5eaed5bd8..10fed9abb6 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -446,7 +446,8 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur { auto code = static_cast(func)->Code; // handle empty functions consisting of a single return explicitly so that empty virtual callbacks do not need to set up an entire VM frame. - if (code->word == 0x0080804e) + // code cann be null here in case of some non-fatal DECORATE errors. + if (code == nullptr || code->word == 0x0080804e) { return 0; } From d39ee1daf328a61f324abde7c94fc921a7b93981 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 16:56:49 +0100 Subject: [PATCH 095/207] - added a new thinker statnum STAT_STATIC which do not get deleted between levels. --- src/d_main.cpp | 1 + src/dthinker.cpp | 2 +- src/g_level.cpp | 1 + src/p_actionfunctions.cpp | 2 +- src/p_setup.cpp | 1 + src/statnums.h | 1 + 6 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index c7a001dfe1..02cbca73a6 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2708,6 +2708,7 @@ void D_DoomMain (void) // clean up game state ST_Clear(); D_ErrorCleanup (); + DThinker::DestroyThinkersInList(STAT_STATIC); P_FreeLevelData(); P_FreeExtraLevelData(); diff --git a/src/dthinker.cpp b/src/dthinker.cpp index da68d83886..fddc283177 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -422,7 +422,7 @@ void DThinker::DestroyAllThinkers () for (i = 0; i <= MAX_STATNUM; i++) { - if (i != STAT_TRAVELLING) + if (i != STAT_TRAVELLING && i != STAT_STATIC) { DestroyThinkersInList (Thinkers[i]); DestroyThinkersInList (FreshThinkers[i]); diff --git a/src/g_level.cpp b/src/g_level.cpp index b811c12153..01911f7423 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -427,6 +427,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) UnlatchCVars (); G_VerifySkill(); UnlatchCVars (); + DThinker::DestroyThinkersInList(STAT_STATIC); if (paused) { diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 8f916614bb..16c8c3267a 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1124,7 +1124,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SeekerMissile) PARAM_INT_DEF(chance); PARAM_INT_DEF(distance); - if ((flags & SMF_LOOK) && (self->tracer == 0) && (pr_seekermissile()tracer == nullptr) && (pr_seekermissile()tracer = P_RoughMonsterSearch (self, distance, true); } diff --git a/src/p_setup.cpp b/src/p_setup.cpp index ac7faea765..308054a8b3 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -4202,6 +4202,7 @@ void P_Init () static void P_Shutdown () { // [ZZ] delete global event handlers + DThinker::DestroyThinkersInList(STAT_STATIC); E_Shutdown(false); P_DeinitKeyMessages (); P_FreeLevelData (); diff --git a/src/statnums.h b/src/statnums.h index 7f691e232a..dd868bbe13 100644 --- a/src/statnums.h +++ b/src/statnums.h @@ -45,6 +45,7 @@ enum STAT_AUTODECAL, // A decal that can be automatically deleted STAT_CORPSEPOINTER, // An entry in Hexen's corpse queue STAT_TRAVELLING, // An actor temporarily travelling to a new map + STAT_STATIC, // persistent across maps. // Thinkers that do think STAT_FIRST_THINKING=32, From 13c6cebef3fbf0f76af6c2b3f6cecf1fdb5bbab2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 16:57:46 +0100 Subject: [PATCH 096/207] - call WI_updateAnimatedBack only once from WI_Ticker instead of from each single WI_update function. --- src/wi_stuff.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 7e7fe4d155..a7f6b8f17c 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1090,8 +1090,6 @@ public: void WI_updateNoState () { - WI_updateAnimatedBack(); - if (acceleratestage) { cnt = 0; @@ -1140,8 +1138,6 @@ public: void WI_updateShowNextLoc () { - WI_updateAnimatedBack(); - if (!--cnt || acceleratestage) WI_initNoState(); else @@ -1239,8 +1235,6 @@ public: bool stillticking; bool autoskip = WI_autoSkip(); - WI_updateAnimatedBack(); - if ((acceleratestage || autoskip) && ng_state != 6) { acceleratestage = 0; @@ -1491,8 +1485,6 @@ public: bool stillticking; bool autoskip = WI_autoSkip(); - WI_updateAnimatedBack (); - if ((acceleratestage || autoskip) && ng_state != 10) { acceleratestage = 0; @@ -1786,8 +1778,6 @@ public: void WI_updateStats () { - WI_updateAnimatedBack (); - if (acceleratestage && sp_state != 10) { acceleratestage = 0; @@ -2165,6 +2155,7 @@ static FIntermissionScreen WI_Screen; void WI_Ticker() { + WI_Screen.WI_updateAnimatedBack(); WI_Screen.WI_Ticker(); } From b2a1e03d7e09ec368a818b75177dd29c24334c59 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 17:14:03 +0100 Subject: [PATCH 097/207] - fprgot to commit the script-side definition of STAT_STATIC. --- wadsrc/static/zscript/base.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 0aba717cb1..d8fed2f28a 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -353,6 +353,7 @@ class Thinker : Object native STAT_AUTODECAL, // A decal that can be automatically deleted STAT_CORPSEPOINTER, // An entry in Hexen's corpse queue STAT_TRAVELLING, // An actor temporarily travelling to a new map + STAT_STATIC, // Thinkers that do think STAT_FIRST_THINKING=32, From 89a43feb7aa5363d75cb397221c53232ab05379a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 17:55:20 +0100 Subject: [PATCH 098/207] - split the intermission background handling into its own class. This means that 1/3 of wi_stuff can be left as-is when scriptifying the rest. --- src/wi_stuff.cpp | 543 ++++++++++++++++++++++++----------------------- 1 file changed, 281 insertions(+), 262 deletions(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index a7f6b8f17c..525d0c577b 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -59,6 +59,14 @@ CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE) CVAR(Bool, wi_noautostartmap, false, CVAR_USERINFO | CVAR_ARCHIVE) CVAR(Int, wi_autoadvance, 0, CVAR_SERVERINFO) +// States for the intermission +enum EState +{ + NoState = -1, + StatCount, + ShowNextLoc, + LeavingIntermission +}; static const char *WI_Cmd[] = { "Background", @@ -83,67 +91,8 @@ static const char *WI_Cmd[] = { NULL }; - -struct FPatchInfo +struct FInterBackground { - FFont *mFont; - FTexture *mPatch; - EColorRange mColor; - - void Init(FGIFont &gifont) - { - if (gifont.color == NAME_Null) - { - mPatch = TexMan[gifont.fontname]; // "entering" - mColor = mPatch == NULL ? CR_UNTRANSLATED : CR_UNDEFINED; - mFont = NULL; - } - else - { - mFont = V_GetFont(gifont.fontname); - mColor = V_FindFontColor(gifont.color); - mPatch = NULL; - } - if (mFont == NULL) - { - mFont = BigFont; - } - } -}; - - - -class FIntermissionScreen -{ -public: - // States for the intermission - enum EState - { - NoState = -1, - StatCount, - ShowNextLoc, - LeavingIntermission - }; - - - enum EValues - { - // GLOBAL LOCATIONS - WI_TITLEY = 2, - - // SINGPLE-PLAYER STUFF - SP_STATSX = 50, - SP_STATSY = 50, - - SP_TIMEX = 8, - SP_TIMEY = (200 - 32), - - // NET GAME STUFF - NG_STATSY = 50, - }; - - - // These animation variables, structures, etc. are used for the // DOOM/Ultimate DOOM intermission screen animations. This is // totally different from any sprite or texture/flat animations @@ -167,18 +116,6 @@ public: }; - // States for single-player - enum ESPState - { - SP_KILLS = 0, - SP_ITEMS = 2, - SP_SECRET = 4, - SP_FRAGS = 6, - SP_TIME = 8, - }; - - static const int SHOWNEXTLOCDELAY = 4; // in seconds - struct yahpt_t { int x, y; @@ -188,16 +125,9 @@ public: { int x; // x/y coordinate pair structure int y; - char level[9]; + FString Level; }; - - // - // Animation. - // There is another anim_t used in p_spec. - // (which is why I have renamed this one!) - // - struct in_anim_t { int type; // Made an int so I can use '|' @@ -206,7 +136,7 @@ public: int data; // ALWAYS: n/a, RANDOM: period deviation (<256) TArray frames; // actual graphics for frames of animations - // following must be initialized to zero before use! + // following must be initialized to zero before use! int nexttic; // next value of bcnt (used in conjunction with period) int ctr; // next frame number to animate int state; // used by RANDOM and LEVEL when animating @@ -223,71 +153,21 @@ public: } }; +private: TArray lnodes; TArray anims; - - int acceleratestage; // used to accelerate or skip a stage - bool playerready[MAXPLAYERS]; - int me; // wbs->pnum - EState state; // specifies current state - wbstartstruct_t *wbs; // contains information passed into intermission - wbplayerstruct_t* Plrs[MAXPLAYERS]; // wbs->plyr[] - int cnt; // used for general timing - int bcnt; // used for timing of background animation - int cnt_kills[MAXPLAYERS]; - int cnt_items[MAXPLAYERS]; - int cnt_secret[MAXPLAYERS]; - int cnt_frags[MAXPLAYERS]; - int cnt_deaths[MAXPLAYERS]; - int cnt_time; - int cnt_total_time; - int cnt_par; - int cnt_pause; - int total_frags; - int total_deaths; - bool noautostartmap; - int dofrags; - int ng_state; - - // - // GRAPHICS - // - - FPatchInfo mapname; - FPatchInfo finished; - FPatchInfo entering; - + int bcnt = 0; // used for timing of background animation TArray yah; // You Are Here graphic - FTexture* splat; // splat - FTexture* sp_secret; // "secret" - FTexture* kills; // "Kills", "Scrt", "Items", "Frags" - FTexture* secret; - FTexture* items; - FTexture* frags; - FTexture* timepic; // Time sucks. - FTexture* par; - FTexture* sucks; - FTexture* killers; // "killers", "victims" - FTexture* victims; - FTexture* total; // "Total", your face, your dead face - FTexture* p; // Player graphic - FTexture* lnames[2]; // Name graphics of each level (centered) - - // [RH] Info to dynamically generate the level name graphics - FString lnametexts[2]; - - FTexture *background; - - bool snl_pointeron = false; - - int player_deaths[MAXPLAYERS]; - int sp_state; - - // - // CODE - // + FTexture* splat = nullptr; // splat + FTexture *background = nullptr; + wbstartstruct_t *wbs; +public: + FInterBackground(wbstartstruct_t *wbst) + { + wbs = wbst; + }; //==================================================================== // // Loads the background - either from a single texture @@ -297,22 +177,23 @@ public: // MAPINFO. // //==================================================================== - static bool IsExMy(const char * name) + bool IsExMy(const char * name) { // Only check for the first 3 episodes. They are the only ones with default intermission scripts. // Level names can be upper- and lower case so use tolower to check! - return (tolower(name[0])=='e' && name[1]>='1' && name[1]<='3' && tolower(name[2])=='m'); + return (tolower(name[0]) == 'e' && name[1] >= '1' && name[1] <= '3' && tolower(name[2]) == 'm'); } - void WI_LoadBackground(bool isenterpic) + bool LoadBackground(bool isenterpic) { const char *lumpname = NULL; char buffer[10]; in_anim_t an; lnode_t pt; FTextureID texture; + bool noautostartmap = false; - bcnt=0; + bcnt = 0; texture.SetInvalid(); if (isenterpic) @@ -326,10 +207,10 @@ public: } // Try to get a default if nothing specified - if (lumpname == NULL || lumpname[0]==0) + if (lumpname == NULL || lumpname[0] == 0) { lumpname = NULL; - switch(gameinfo.gametype) + switch (gameinfo.gametype) { case GAME_Chex: case GAME_Doom: @@ -342,24 +223,24 @@ public: lumpname = buffer; } } - if (!lumpname) + if (!lumpname) { - if (isenterpic) + if (isenterpic) { // One special case needs to be handled here! // If going from E1-E3 to E4 the default should be used, not the exit pic. // Not if the exit pic is user defined! - if (level.info->ExitPic.IsNotEmpty()) return; + if (level.info->ExitPic.IsNotEmpty()) return false; // E1-E3 need special treatment when playing Doom 1. if (!(gameinfo.flags & GI_MAPxx)) { // not if the last level is not from the first 3 episodes - if (!IsExMy(wbs->current)) return; + if (!IsExMy(wbs->current)) return false; // not if the next level is one of the first 3 episodes - if (IsExMy(wbs->next)) return; + if (IsExMy(wbs->next)) return false; } } lumpname = "INTERPIC"; @@ -375,22 +256,22 @@ public: lumpname = buffer; } } - if (!lumpname) + if (!lumpname) { - if (isenterpic) return; + if (isenterpic) return false; lumpname = "FLOOR16"; } break; case GAME_Hexen: - if (isenterpic) return; + if (isenterpic) return false; lumpname = "INTERPIC"; break; case GAME_Strife: default: // Strife doesn't have an intermission pic so choose something neutral. - if (isenterpic) return; + if (isenterpic) return false; lumpname = gameinfo.BorderFlat; break; } @@ -399,7 +280,7 @@ public: { // shouldn't happen! background = NULL; - return; + return false; } lnodes.Clear(); @@ -408,21 +289,21 @@ public: splat = NULL; // a name with a starting '$' indicates an intermission script - if (*lumpname!='$') + if (*lumpname != '$') { texture = TexMan.CheckForTexture(lumpname, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); } else { - int lumpnum=Wads.CheckNumForFullName(lumpname+1, true); - if (lumpnum>=0) + int lumpnum = Wads.CheckNumForFullName(lumpname + 1, true); + if (lumpnum >= 0) { FScanner sc(lumpnum); while (sc.GetString()) { an.Reset(); int caseval = sc.MustMatchString(WI_Cmd); - switch(caseval) + switch (caseval) { case 0: // Background sc.MustGetString(); @@ -448,8 +329,7 @@ public: while (!sc.CheckString("}")) { sc.MustGetString(); - strncpy(pt.level, sc.String,8); - pt.level[8] = 0; + pt.Level = sc.String; sc.MustGetNumber(); pt.x = sc.Number; sc.MustGetNumber(); @@ -477,7 +357,7 @@ public: case 8: // IfLeaving an.type = ANIM_IFLEAVING; goto readanimation; - + case 9: // IfNotLeaving an.type = ANIM_IFNOTLEAVING; goto readanimation; @@ -502,7 +382,7 @@ public: sc.MustGetString(); an.LevelName = sc.String; sc.MustGetString(); - caseval=sc.MustMatchString(WI_Cmd); + caseval = sc.MustMatchString(WI_Cmd); default: switch (caseval) @@ -562,13 +442,14 @@ public: } } } - else + else { - Printf("Intermission script %s not found!\n", lumpname+1); + Printf("Intermission script %s not found!\n", lumpname + 1); texture = TexMan.GetTexture("INTERPIC", FTexture::TEX_MiscPatch); } } - background=TexMan[texture]; + background = TexMan[texture]; + return noautostartmap; } //==================================================================== @@ -578,11 +459,12 @@ public: // //==================================================================== - void WI_updateAnimatedBack() + void updateAnimatedBack() { unsigned int i; - for(i=0;itype & ANIM_TYPE) @@ -590,19 +472,19 @@ public: case ANIM_ALWAYS: if (bcnt >= a->nexttic) { - if (++a->ctr >= (int)a->frames.Size()) + if (++a->ctr >= (int)a->frames.Size()) { - if (a->data==0) a->ctr = 0; + if (a->data == 0) a->ctr = 0; else a->ctr--; } a->nexttic = bcnt + a->period; } break; - + case ANIM_PIC: a->ctr = 0; break; - + } } } @@ -613,11 +495,11 @@ public: // //==================================================================== - void WI_drawBackground() + void drawBackground(int state, bool drawsplat, bool snl_pointeron) { unsigned int i; - double animwidth=320; // For a flat fill or clear background scale animations to 320x200 - double animheight=200; + double animwidth = 320; // For a flat fill or clear background scale animations to 320x200 + double animheight = 200; if (background) { @@ -629,20 +511,20 @@ public: // placing the animations precisely where they belong on the base pic animwidth = background->GetScaledWidthDouble(); animheight = background->GetScaledHeightDouble(); - screen->FillBorder (NULL); + screen->FillBorder(NULL); screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); } - else + else { screen->FlatFill(0, 0, SCREENWIDTH, SCREENHEIGHT, background); } } - else + else { - screen->Clear(0,0, SCREENWIDTH, SCREENHEIGHT, 0, 0); + screen->Clear(0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0); } - for(i=0;ictr >= 0) - screen->DrawTexture(a->frames[a->ctr], a->loc.x, a->loc.y, - DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); + screen->DrawTexture(a->frames[a->ctr], a->loc.x, a->loc.y, + DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); + } + + if (drawsplat) + { + for (i = 0; iflags & LEVEL_VISITED) drawOnLnode(i, &splat, 1); // draw a splat on taken cities. + } + } + + // draw flashing ptr + if (snl_pointeron && yah.Size()) + { + unsigned int v = MapToIndex(wbs->next); + // Draw only if it points to a valid level on the current screen! + if (vGetScaledWidth(); + bottom = c[i]->GetScaledHeight(); + left = lnodes[n].x - c[i]->GetScaledLeftOffset(); + top = lnodes[n].y - c[i]->GetScaledTopOffset(); + right += left; + bottom += top; + + if (left >= 0 && right < 320 && top >= 0 && bottom < 200) + { + screen->DrawTexture(c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE); + break; + } } } +}; + +struct FPatchInfo +{ + FFont *mFont; + FTexture *mPatch; + EColorRange mColor; + + void Init(FGIFont &gifont) + { + if (gifont.color == NAME_Null) + { + mPatch = TexMan[gifont.fontname]; // "entering" + mColor = mPatch == NULL ? CR_UNTRANSLATED : CR_UNDEFINED; + mFont = NULL; + } + else + { + mFont = V_GetFont(gifont.fontname); + mColor = V_FindFontColor(gifont.color); + mPatch = NULL; + } + if (mFont == NULL) + { + mFont = BigFont; + } + } +}; + + + +class FIntermissionScreen +{ +public: + + enum EValues + { + // GLOBAL LOCATIONS + WI_TITLEY = 2, + + // SINGPLE-PLAYER STUFF + SP_STATSX = 50, + SP_STATSY = 50, + + SP_TIMEX = 8, + SP_TIMEY = (200 - 32), + + // NET GAME STUFF + NG_STATSY = 50, + }; + + + + // States for single-player + enum ESPState + { + SP_KILLS = 0, + SP_ITEMS = 2, + SP_SECRET = 4, + SP_FRAGS = 6, + SP_TIME = 8, + }; + + static const int SHOWNEXTLOCDELAY = 4; // in seconds + + // + // Animation. + // There is another anim_t used in p_spec. + // (which is why I have renamed this one!) + // + + + FInterBackground *bg; + int acceleratestage; // used to accelerate or skip a stage + bool playerready[MAXPLAYERS]; + int me; // wbs->pnum + int bcnt; + EState state; // specifies current state + wbstartstruct_t *wbs; // contains information passed into intermission + wbplayerstruct_t* Plrs[MAXPLAYERS]; // wbs->plyr[] + int cnt; // used for general timing + int cnt_kills[MAXPLAYERS]; + int cnt_items[MAXPLAYERS]; + int cnt_secret[MAXPLAYERS]; + int cnt_frags[MAXPLAYERS]; + int cnt_deaths[MAXPLAYERS]; + int cnt_time; + int cnt_total_time; + int cnt_par; + int cnt_pause; + int total_frags; + int total_deaths; + bool noautostartmap; + int dofrags; + int ng_state; + + // + // GRAPHICS + // + + FPatchInfo mapname; + FPatchInfo finished; + FPatchInfo entering; + + FTexture* sp_secret; // "secret" + FTexture* kills; // "Kills", "Scrt", "Items", "Frags" + FTexture* secret; + FTexture* items; + FTexture* frags; + FTexture* timepic; // Time sucks. + FTexture* par; + FTexture* sucks; + FTexture* killers; // "killers", "victims" + FTexture* victims; + FTexture* total; // "Total", your face, your dead face + FTexture* p; // Player graphic + FTexture* lnames[2]; // Name graphics of each level (centered) + + // [RH] Info to dynamically generate the level name graphics + FString lnametexts[2]; + + + bool snl_pointeron = false; + + int player_deaths[MAXPLAYERS]; + int sp_state; + + // + // CODE + // + + + + //==================================================================== // // Draws a single character with a shadow @@ -870,57 +956,6 @@ public: } - //==================================================================== - // - // Draws the splats and the 'You are here' arrows - // - //==================================================================== - - int WI_MapToIndex (const char *map) - { - unsigned int i; - - for (i = 0; i < lnodes.Size(); i++) - { - if (!strnicmp (lnodes[i].level, map, 8)) - break; - } - return i; - } - - - //==================================================================== - // - // Draws the splats and the 'You are here' arrows - // - //==================================================================== - - void WI_drawOnLnode( int n, FTexture * c[] ,int numc) - { - int i; - for(i=0;iGetScaledWidth(); - bottom = c[i]->GetScaledHeight(); - left = lnodes[n].x - c[i]->GetScaledLeftOffset(); - top = lnodes[n].y - c[i]->GetScaledTopOffset(); - right += left; - bottom += top; - - if (left >= 0 && right < 320 && top >= 0 && bottom < 200) - { - screen->DrawTexture (c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE); - break; - } - } - } - //==================================================================== // // Draws a number. @@ -1133,7 +1168,7 @@ public: state = ShowNextLoc; acceleratestage = 0; cnt = SHOWNEXTLOCDELAY * TICRATE; - WI_LoadBackground(true); + bg->LoadBackground(true); } void WI_updateShowNextLoc () @@ -1146,26 +1181,7 @@ public: void WI_drawShowNextLoc(void) { - unsigned int i; - - WI_drawBackground(); - - if (splat) - { - for (i=0 ; iflags & LEVEL_VISITED) WI_drawOnLnode(i, &splat,1); // draw a splat on taken cities. - } - } - - // draw flashing ptr - if (snl_pointeron && yah.Size()) - { - unsigned int v = WI_MapToIndex (wbs->next); - // Draw only if it points to a valid level on the current screen! - if (vdrawBackground(state, true, snl_pointeron); // draws which level you are entering.. WI_drawEL (); @@ -1344,7 +1360,7 @@ public: player_t *sortedplayers[MAXPLAYERS]; // draw animated background - WI_drawBackground(); + bg->drawBackground(state, false, false); y = WI_drawLF(); @@ -1648,7 +1664,7 @@ public: FTexture *readyico = TexMan.FindTexture("READYICO"); // draw animated background - WI_drawBackground(); + bg->drawBackground(state, false, false); y = WI_drawLF(); @@ -1898,8 +1914,8 @@ public: lh = IntermissionFont->GetHeight() * 3 / 2; // draw animated background - WI_drawBackground(); - + bg->drawBackground(state, false, false); + WI_drawLF(); if (gameinfo.gametype & GAME_DoomChex) @@ -2089,12 +2105,15 @@ public: if (li) lnametexts[1] = li->LookupLevelName(); else lnametexts[1] = ""; - WI_LoadBackground(false); + bg = new FInterBackground(wbs); + noautostartmap = bg->LoadBackground(false); } void WI_unloadData () { // [RH] The texture data gets unloaded at pre-map time, so there's nothing to do here + if (bg != nullptr) delete bg; + bg = nullptr; return; } @@ -2155,7 +2174,7 @@ static FIntermissionScreen WI_Screen; void WI_Ticker() { - WI_Screen.WI_updateAnimatedBack(); + WI_Screen.bg->updateAnimatedBack(); WI_Screen.WI_Ticker(); } From 8dac6782003f84e1a62b2274ec7d47f09c84bf15 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 19:10:49 +0100 Subject: [PATCH 099/207] - added DAMAGE_NO_ARMOR flag for ACS's SectorDamage function. --- src/p_spec.cpp | 3 ++- src/p_spec.h | 1 + src/v_draw.cpp | 8 ++++---- src/v_video.h | 2 +- src/wi_stuff.cpp | 32 +++++++++++++++----------------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 0eb6197234..b3ce7e3e31 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -466,7 +466,8 @@ static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, return; } - P_DamageMobj (actor, NULL, NULL, amount, type); + int dflags = (flags & DAMAGE_NO_ARMOR) ? DMG_NO_ARMOR : 0; + P_DamageMobj (actor, NULL, NULL, amount, type, dflags); } void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass, int flags) diff --git a/src/p_spec.h b/src/p_spec.h index 5cb8861e44..b00e5cacf9 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -76,6 +76,7 @@ const double CARRYFACTOR = 3 / 32.; #define DAMAGE_NONPLAYERS 2 #define DAMAGE_IN_AIR 4 #define DAMAGE_SUBCLASSES_PROTECT 8 +#define DAMAGE_NO_ARMOR 16 // [RH] If a deathmatch game, checks to see if noexit is enabled. diff --git a/src/v_draw.cpp b/src/v_draw.cpp index ca5e1fa372..0a9b75b19f 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -572,7 +572,7 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, parms->colorOverlay = 0; parms->alphaChannel = false; parms->flipX = false; - parms->shadowAlpha = 0; + //parms->shadowAlpha = 0; parms->shadowColor = 0; parms->virtWidth = this->GetWidth(); parms->virtHeight = this->GetHeight(); @@ -845,7 +845,7 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, break; case DTA_ShadowAlpha: - parms->shadowAlpha = (float)MIN(1., ListGetDouble(tags)); + //parms->shadowAlpha = (float)MIN(1., ListGetDouble(tags)); break; case DTA_ShadowColor: @@ -856,12 +856,12 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, DWORD tag, boolval = ListGetInt(tags); if (boolval) { - parms->shadowAlpha = 0.5; + //parms->shadowAlpha = 0.5; parms->shadowColor = 0; } else { - parms->shadowAlpha = 0; + //parms->shadowAlpha = 0; } break; diff --git a/src/v_video.h b/src/v_video.h index 72474ee288..8618f95ba7 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -162,7 +162,7 @@ struct DrawParms uint32 colorOverlay; INTBOOL alphaChannel; INTBOOL flipX; - float shadowAlpha; + //float shadowAlpha; int shadowColor; INTBOOL keepratio; INTBOOL masked; diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 525d0c577b..d5c5554dab 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -738,6 +738,7 @@ public: bool noautostartmap; int dofrags; int ng_state; + float shadowalpha; // // GRAPHICS @@ -777,23 +778,6 @@ public: - //==================================================================== - // - // Draws a single character with a shadow - // - //==================================================================== - - int WI_DrawCharPatch (FFont *font, int charcode, int x, int y, EColorRange translation=CR_UNTRANSLATED, bool nomove=false) - { - int width; - font->GetChar(charcode, &width); - screen->DrawChar(font, translation, x, y, charcode, - nomove ? DTA_CleanNoMove : DTA_Clean, true, - DTA_ShadowAlpha, (gameinfo.gametype & GAME_DoomChex) ? 0 : 0.5, - TAG_DONE); - return x - width; - } - //==================================================================== // // CheckRealHeight @@ -830,6 +814,20 @@ public: return maxy; } + //==================================================================== + // + // Draws a single character with a shadow + // + //==================================================================== + + int WI_DrawCharPatch(FFont *font, int charcode, int x, int y, EColorRange translation = CR_UNTRANSLATED, bool nomove = false) + { + int width; + font->GetChar(charcode, &width); + screen->DrawChar(font, translation, x, y, charcode, nomove ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE); + return x - width; + } + //==================================================================== // // Draws a level name with the big font From 5ea8ad54a46c67546aefdae17abfbcafc73b5768 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 19:56:22 +0100 Subject: [PATCH 100/207] - added tags to all ammo types. --- wadsrc/static/language.enu | 17 +++++++++++++++++ wadsrc/static/zscript/doom/doomammo.txt | 4 ++++ wadsrc/static/zscript/heretic/hereticammo.txt | 6 ++++++ wadsrc/static/zscript/hexen/mana.txt | 2 ++ 4 files changed, 29 insertions(+) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index b1a8172d71..224aa24f0f 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1566,6 +1566,23 @@ TXT_COMM0 = "Incoming Message"; TXT_COMM1 = "Incoming Message from BlackBird"; +AMMO_CLIP = "Bullets"; +AMMO_SHELLS = "Shotgun Shells"; +AMMO_ROCKETS = "Rockets"; +AMMO_CELLS = "Energy Cells"; +AMMO_GOLDWAND = "Wand Crystals"; +AMMO_CROSSBOW = "Ethereal Arrows"; +AMMO_BLASTER = "Claw Orbs"; +AMMO_MACE = "Mace Spheres"; +AMMO_SKULLROD = "Hellstaff Runes"; +AMMO_PHOENIXROD = "Flame Orbs"; +AMMO_MANA1 = "Blue Mana"; +AMMO_MANA2 = "Green Mana"; +$ifgame(chex) AMMO_CLIP = "Mini Zorch Charge"; +$ifgame(chex) AMMO_SHELLS = "Large Zorcher Charge"; +$ifgame(chex) AMMO_ROCKETS = "Propulsor Charge"; +$ifgame(chex) AMMO_CELLS = "Phasing Zorcher Charge"; + // Menu Strings // Main Menu diff --git a/wadsrc/static/zscript/doom/doomammo.txt b/wadsrc/static/zscript/doom/doomammo.txt index 394f13e94f..950fd2122a 100644 --- a/wadsrc/static/zscript/doom/doomammo.txt +++ b/wadsrc/static/zscript/doom/doomammo.txt @@ -10,6 +10,7 @@ class Clip : Ammo Ammo.BackpackAmount 10; Ammo.BackpackMaxAmount 400; Inventory.Icon "CLIPA0"; + Tag "$AMMO_CLIP"; } States { @@ -48,6 +49,7 @@ class RocketAmmo : Ammo Ammo.BackpackAmount 1; Ammo.BackpackMaxAmount 100; Inventory.Icon "ROCKA0"; + Tag "$AMMO_ROCKETS"; } States { @@ -86,6 +88,7 @@ class Cell : Ammo Ammo.BackpackAmount 20; Ammo.BackpackMaxAmount 600; Inventory.Icon "CELLA0"; + Tag "$AMMO_CELLS"; } States { @@ -124,6 +127,7 @@ class Shell : Ammo Ammo.BackpackAmount 4; Ammo.BackpackMaxAmount 100; Inventory.Icon "SHELA0"; + Tag "$AMMO_SHELLS"; } States { diff --git a/wadsrc/static/zscript/heretic/hereticammo.txt b/wadsrc/static/zscript/heretic/hereticammo.txt index cf1e50a3d7..c5ea831aaf 100644 --- a/wadsrc/static/zscript/heretic/hereticammo.txt +++ b/wadsrc/static/zscript/heretic/hereticammo.txt @@ -11,6 +11,7 @@ Class GoldWandAmmo : Ammo Ammo.BackpackAmount 10; Ammo.BackpackMaxAmount 200; Inventory.Icon "INAMGLD"; + Tag "$AMMO_GOLDWAND"; } States { @@ -48,6 +49,7 @@ Class CrossbowAmmo : Ammo Ammo.BackpackAmount 5; Ammo.BackpackMaxAmount 100; Inventory.Icon "INAMBOW"; + Tag "$AMMO_CROSSBOW"; } States { @@ -85,6 +87,7 @@ Class MaceAmmo : Ammo Ammo.BackpackAmount 20; Ammo.BackpackMaxAmount 300; Inventory.Icon "INAMLOB"; + Tag "$AMMO_MACE"; } States { @@ -123,6 +126,7 @@ Class BlasterAmmo : Ammo Ammo.BackpackAmount 10; Ammo.BackpackMaxAmount 400; Inventory.Icon "INAMBST"; + Tag "$AMMO_BLASTER"; } States { @@ -161,6 +165,7 @@ Class SkullRodAmmo : Ammo Ammo.BackpackAmount 20; Ammo.BackpackMaxAmount 400; Inventory.Icon "INAMRAM"; + Tag "$AMMO_SKULLROD"; } States { @@ -199,6 +204,7 @@ Class PhoenixRodAmmo : Ammo Ammo.BackpackAmount 1; Ammo.BackpackMaxAmount 40; Inventory.Icon "INAMPNX"; + Tag "$AMMO_PHOENIXROD"; } States { diff --git a/wadsrc/static/zscript/hexen/mana.txt b/wadsrc/static/zscript/hexen/mana.txt index 0a43a21ddd..ad3d6d66be 100644 --- a/wadsrc/static/zscript/hexen/mana.txt +++ b/wadsrc/static/zscript/hexen/mana.txt @@ -13,6 +13,7 @@ class Mana1 : Ammo +FLOATBOB Inventory.Icon "MAN1I0"; Inventory.PickupMessage "$TXT_MANA_1"; + Tag "$AMMO_MANA1"; } States { @@ -37,6 +38,7 @@ class Mana2 : Ammo +FLOATBOB Inventory.Icon "MAN2G0"; Inventory.PickupMessage "$TXT_MANA_2"; + Tag "$AMMO_MANA2"; } States { From 35033891ace78be7dc4623cfbe3e51960830a5fc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 20:12:30 +0100 Subject: [PATCH 101/207] - added MF7_NOINFIGHTSPECIES flag. --- src/actor.h | 1 + src/p_interaction.cpp | 3 +++ src/scripting/thingdef_data.cpp | 1 + 3 files changed, 5 insertions(+) diff --git a/src/actor.h b/src/actor.h index d387da2c88..c8c7cbc5ff 100644 --- a/src/actor.h +++ b/src/actor.h @@ -388,6 +388,7 @@ enum ActorFlag7 MF7_SMASHABLE = 0x04000000, // dies if hitting the floor. MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields. MF7_FORCEZERORADIUSDMG = 0x10000000, // passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. + MF7_NOINFIGHTSPECIES = 0x20000000, // don't start infights with one's own species. }; // --- mobj.renderflags --- diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 28df6e761f..e940c259f8 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1714,6 +1714,9 @@ bool AActor::OkayToSwitchTarget (AActor *other) } } + if ((flags7 & MF7_NOINFIGHTSPECIES) && GetSpecies() == target->GetSpecies()) + return false; // Don't fight own species. + if ((other->flags3 & MF3_NOTARGET) && (other->tid != TIDtoHate || TIDtoHate == 0) && !IsHostile (other)) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 735fddba78..a737ce4143 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -317,6 +317,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7), DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7), DEFINE_FLAG(MF7, FORCEZERORADIUSDMG, AActor, flags7), + DEFINE_FLAG(MF7, NOINFIGHTSPECIES, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), From 7f78b42f21964379d7b0948d278d7fee2f5ba409 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 20:20:43 +0100 Subject: [PATCH 102/207] - added an 'inventory change' and 'weapon change' sound, which by default are not defined. --- src/g_game.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/g_game.cpp b/src/g_game.cpp index d93d6743bf..b4e4973116 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -347,6 +347,10 @@ CCMD (weapnext) StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(), 1.5f, 0.90f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' )); } + if (SendItemUse != players[consoleplayer].ReadyWeapon) + { + S_Sound(CHAN_AUTO, "misc/weaponchange", 1.0, ATTN_NONE); + } } CCMD (weapprev) @@ -358,6 +362,10 @@ CCMD (weapprev) StatusBar->AttachMessage(new DHUDMessageFadeOut(SmallFont, SendItemUse->GetTag(), 1.5f, 0.90f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID( 'W', 'E', 'P', 'N' )); } + if (SendItemUse != players[consoleplayer].ReadyWeapon) + { + S_Sound(CHAN_AUTO, "misc/weaponchange", 1.0, ATTN_NONE); + } } CCMD (invnext) @@ -367,6 +375,7 @@ CCMD (invnext) if (who == NULL) return; + auto old = who->InvSel; if (who->InvSel != NULL) { if ((next = who->InvSel->NextInv()) != NULL) @@ -390,6 +399,10 @@ CCMD (invnext) 1.5f, 0.80f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID('S','I','N','V')); } who->player->inventorytics = 5*TICRATE; + if (old != who->InvSel) + { + S_Sound(CHAN_AUTO, "misc/invchange", 1.0, ATTN_NONE); + } } CCMD (invprev) @@ -399,6 +412,7 @@ CCMD (invprev) if (who == NULL) return; + auto old = who->InvSel; if (who->InvSel != NULL) { if ((item = who->InvSel->PrevInv()) != NULL) @@ -420,6 +434,10 @@ CCMD (invprev) 1.5f, 0.80f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID('S','I','N','V')); } who->player->inventorytics = 5*TICRATE; + if (old != who->InvSel) + { + S_Sound(CHAN_AUTO, "misc/invchange", 1.0, ATTN_NONE); + } } CCMD (invuseall) From 35552ce0cb82e919cab57331880dfe082260f697 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 20:45:28 +0100 Subject: [PATCH 103/207] - added a Death.Sky state for missiles that gets used when they hit a sky plane. - fixed: The Alt HUD did not draw the crosshair in HUD off mode. --- src/d_main.cpp | 4 ++ src/g_shared/shared_hud.cpp | 4 -- src/namedef.h | 1 + src/p_local.h | 2 +- src/p_mobj.cpp | 70 +++++++++++++++++++++------------ wadsrc/static/zscript/actor.txt | 3 +- 6 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 02cbca73a6..b430c7f04b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -810,6 +810,10 @@ void D_Display () { StatusBar->DrawBottomStuff (HUD_AltHud); if (DrawFSHUD || automapactive) DrawHUD(); + if (players[consoleplayer].camera && players[consoleplayer].camera->player) + { + StatusBar->DrawCrosshair(); + } StatusBar->Draw (HUD_AltHud); StatusBar->DrawTopStuff (HUD_AltHud); } diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index d39c16d88e..7fea7b014d 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -1136,10 +1136,6 @@ void DrawHUD() i=DrawAmmo(CPlayer, hudwidth-5, i); if (hud_showweapons) DrawWeapons(CPlayer, hudwidth - 5, i); DrawInventory(CPlayer, 144, hudheight-28); - if (CPlayer->camera && CPlayer->camera->player) - { - StatusBar->DrawCrosshair(); - } if (idmypos) DrawCoordinates(CPlayer); DrawTime(); diff --git a/src/namedef.h b/src/namedef.h index 105d29cddf..13e9096bc3 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -654,6 +654,7 @@ xx(Goodbye) xx(Require) xx(Exclude) xx(Userstring) +xx(Sky) // Special menus xx(Mainmenu) diff --git a/src/p_local.h b/src/p_local.h index 89346328e8..677de09fcd 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -111,7 +111,7 @@ void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle); void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle); void P_RipperBlood (AActor *mo, AActor *bleeder); int P_GetThingFloorType (AActor *thing); -void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); +void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target, bool onsky = false); AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type); AActor *P_SpawnMissile (AActor* source, AActor* dest, PClassActor *type, AActor* owner = NULL); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index fd0df678b9..a908e115e8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1804,7 +1804,7 @@ bool AActor::Massacre () // //---------------------------------------------------------------------------- -void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) +void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target, bool onsky) { if (mo->flags3 & MF3_EXPLOCOUNT) { @@ -1832,11 +1832,15 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) } if (nextstate == NULL) nextstate = mo->FindState(NAME_Death); - if (line != NULL && line->special == Line_Horizon && !(mo->flags3 & MF3_SKYEXPLODE)) + if (onsky || (line != NULL && line->special == Line_Horizon)) { - // [RH] Don't explode missiles on horizon lines. - mo->Destroy (); - return; + if (!(mo->flags3 & MF3_SKYEXPLODE)) + { + // [RH] Don't explode missiles on horizon lines. + mo->Destroy(); + return; + } + nextstate = mo->FindState(NAME_Death, NAME_Sky); } if (line != NULL && cl_missiledecals) @@ -2557,26 +2561,32 @@ double P_XYMovement (AActor *mo, DVector2 scroll) } explode: // explode a missile - if (!(mo->flags3 & MF3_SKYEXPLODE)) - { + bool onsky = false; if (tm.ceilingline && tm.ceilingline->backsector && tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum && mo->Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo->PosRelative(tm.ceilingline))) { - // Hack to prevent missiles exploding against the sky. - // Does not handle sky floors. - mo->Destroy (); - return Oldfloorz; + if (!(mo->flags3 & MF3_SKYEXPLODE)) + { + // Hack to prevent missiles exploding against the sky. + // Does not handle sky floors. + mo->Destroy(); + return Oldfloorz; + } + else onsky = true; } // [RH] Don't explode on horizon lines. if (mo->BlockingLine != NULL && mo->BlockingLine->special == Line_Horizon) { - mo->Destroy (); - return Oldfloorz; + if (!(mo->flags3 & MF3_SKYEXPLODE)) + { + mo->Destroy(); + return Oldfloorz; + } + else onsky = true; } - } - P_ExplodeMissile (mo, mo->BlockingLine, BlockingMobj); + P_ExplodeMissile (mo, mo->BlockingLine, BlockingMobj, onsky); return Oldfloorz; } else @@ -2955,15 +2965,20 @@ void P_ZMovement (AActor *mo, double oldfloorz) } else { - if (mo->floorpic == skyflatnum && !(mo->flags3 & MF3_SKYEXPLODE)) + bool onsky = false; + if (mo->floorpic == skyflatnum) { - // [RH] Just remove the missile without exploding it - // if this is a sky floor. - mo->Destroy (); - return; + if (!(mo->flags3 & MF3_SKYEXPLODE)) + { + // [RH] Just remove the missile without exploding it + // if this is a sky floor. + mo->Destroy(); + return; + } + else onsky = true; } P_HitFloor (mo); - P_ExplodeMissile (mo, NULL, NULL); + P_ExplodeMissile (mo, NULL, NULL, onsky); return; } } @@ -3056,12 +3071,17 @@ void P_ZMovement (AActor *mo, double oldfloorz) { return; } - if (mo->ceilingpic == skyflatnum && !(mo->flags3 & MF3_SKYEXPLODE)) + bool onsky = false; + if (mo->ceilingpic == skyflatnum) { - mo->Destroy (); - return; + if (!(mo->flags3 & MF3_SKYEXPLODE)) + { + mo->Destroy(); + return; + } + else onsky = true; } - P_ExplodeMissile (mo, NULL, NULL); + P_ExplodeMissile (mo, NULL, NULL, onsky); return; } } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 815ffd4796..2e9752b977 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -230,7 +230,6 @@ class Actor : Thinker native native deprecated double ScaleX; native deprecated double ScaleY; - //int ConversationRoot; // THe root of the current dialogue; //FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is used.; @@ -368,7 +367,7 @@ class Actor : Thinker native native Vector3 PosRelative(sector sec); native void HandleSpawnFlags(); - native void ExplodeMissile(line lin = null, Actor target = null); + native void ExplodeMissile(line lin = null, Actor target = null, bool onsky = false); native void RestoreDamage(); native int SpawnHealth(); native void SetDamage(int dmg); From 43e5f035e4cd591b442245d7ffe23f560187459e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Feb 2017 21:48:15 +0100 Subject: [PATCH 104/207] - added a 'brief' mode to linetarget and info. --- src/c_cmds.cpp | 6 +++--- src/c_functions.cpp | 4 ++-- src/c_functions.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index e8f9509e56..ff83d8342d 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -880,7 +880,7 @@ CCMD(linetarget) if (CheckCheatmode () || players[consoleplayer].mo == NULL) return; C_AimLine(&t, false); if (t.linetarget) - C_PrintInfo(t.linetarget); + C_PrintInfo(t.linetarget, argv.argc() > 1 && atoi(argv[1]) != 0); else Printf("No target found\n"); } @@ -893,7 +893,7 @@ CCMD(info) if (CheckCheatmode () || players[consoleplayer].mo == NULL) return; C_AimLine(&t, true); if (t.linetarget) - C_PrintInfo(t.linetarget); + C_PrintInfo(t.linetarget, !(argv.argc() > 1 && atoi(argv[1]) == 0)); else Printf("No target found. Info cannot find actors that have " "the NOBLOCKMAP flag or have height/radius of 0.\n"); @@ -902,7 +902,7 @@ CCMD(info) CCMD(myinfo) { if (CheckCheatmode () || players[consoleplayer].mo == NULL) return; - C_PrintInfo(players[consoleplayer].mo); + C_PrintInfo(players[consoleplayer].mo, true); } typedef bool (*ActorTypeChecker) (AActor *); diff --git a/src/c_functions.cpp b/src/c_functions.cpp index 1d1b35a454..ba3eb11755 100644 --- a/src/c_functions.cpp +++ b/src/c_functions.cpp @@ -39,7 +39,7 @@ #include "c_functions.h" -void C_PrintInfo(AActor *target) +void C_PrintInfo(AActor *target, bool verbose) { if (target->player) Printf("Player=%s, ", target->player->userinfo.GetName()); @@ -47,7 +47,7 @@ void C_PrintInfo(AActor *target) target->GetClass()->TypeName.GetChars(), target->health, target->SpawnHealth()); - PrintMiscActorInfo(target); + if (verbose) PrintMiscActorInfo(target); } void C_AimLine(FTranslatedLineTarget *t, bool nonshootable) diff --git a/src/c_functions.h b/src/c_functions.h index 3d8ab6fc81..4989469a66 100644 --- a/src/c_functions.h +++ b/src/c_functions.h @@ -34,6 +34,6 @@ void C_PrintInv(AActor *target); void C_AimLine(FTranslatedLineTarget *t, bool nonshootable); -void C_PrintInfo(AActor *target); +void C_PrintInfo(AActor *target, bool verbose); struct FTranslatedLineTarget; \ No newline at end of file From 6ae91ac9ea1184e9016a3037e3097000bfb99a11 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 26 Feb 2017 10:36:03 +0200 Subject: [PATCH 105/207] Fixed scripting type of demoplayback global variable https://mantis.zdoom.org/view.php?id=334 --- src/scripting/thingdef_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index a737ce4143..f68667bbbe 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -917,7 +917,7 @@ void InitThingdef() fieldptr = new PField("gametic", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gametic); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); - fieldptr = new PField("demoplayback", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&demoplayback); + fieldptr = new PField("demoplayback", TypeBool, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&demoplayback); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); fieldptr = new PField("BackbuttonTime", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&BackbuttonTime); From c150f9d737031afd9584a0baba1ab58facc99aac Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 26 Feb 2017 11:37:43 +0200 Subject: [PATCH 106/207] Fixed incorrect pointers for Actor.Used() https://mantis.zdoom.org/view.php?id=340 --- src/p_map.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 789a070767..13f566b1f4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5276,20 +5276,22 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end, // [RH] Check for things to talk with or use a puzzle item on if (!in->isaline) { - if (usething == in->d.thing) + AActor * const mobj = in->d.thing; + + if (mobj == usething) continue; // Check thing // Check for puzzle item use or USESPECIAL flag // Extended to use the same activationtype mechanism as BUMPSPECIAL does - if (in->d.thing->flags5 & MF5_USESPECIAL || in->d.thing->special == UsePuzzleItem) + if (mobj->flags5 & MF5_USESPECIAL || mobj->special == UsePuzzleItem) { - if (P_ActivateThingSpecial(in->d.thing, usething)) + if (P_ActivateThingSpecial(mobj, usething)) return true; } - IFVIRTUALPTR(usething, AActor, Used) + IFVIRTUALPTR(mobj, AActor, Used) { - VMValue params[] = { usething, in->d.thing }; + VMValue params[] = { mobj, usething }; int ret; VMReturn vret(&ret); GlobalVMStack.Call(func, params, 2, &vret, 1); From bfa7a2d737c654da06eba8b7a59bedeaabb8c65a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 10:58:22 +0100 Subject: [PATCH 107/207] - fixed: DStaticEventHandler did not declare its pointers. --- src/events.cpp | 8 +++++++- src/events.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index afa98c99d2..d714eefce4 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -449,7 +449,13 @@ DEFINE_EVENT_LOOPER(WorldLightning) DEFINE_EVENT_LOOPER(WorldTick) // declarations -IMPLEMENT_CLASS(DStaticEventHandler, false, false); +IMPLEMENT_CLASS(DStaticEventHandler, false, true); + +IMPLEMENT_POINTERS_START(DStaticEventHandler) +IMPLEMENT_POINTER(next) +IMPLEMENT_POINTER(prev) +IMPLEMENT_POINTERS_END + IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DBaseEvent, false, false) IMPLEMENT_CLASS(DRenderEvent, false, false) diff --git a/src/events.h b/src/events.h index 46ed88b957..fa63e73258 100755 --- a/src/events.h +++ b/src/events.h @@ -76,7 +76,7 @@ void E_SerializeEvents(FSerializer& arc); class DStaticEventHandler : public DObject // make it a part of normal GC process { - DECLARE_CLASS(DStaticEventHandler, DObject) + DECLARE_CLASS(DStaticEventHandler, DObject); HAS_OBJECT_POINTERS public: DStaticEventHandler() From 76a44ebf9cdef82a3d1dc08bd43e5a960163de54 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 26 Feb 2017 12:04:34 +0200 Subject: [PATCH 108/207] Fixed splitting of long lines in message box menu https://mantis.zdoom.org/view.php?id=338 --- src/menu/messagebox.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index a1a0fda769..a68bbc5f10 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -67,7 +67,8 @@ DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, { auto c = PClass::FindClass("MessageBoxMenu"); auto p = c->CreateNew(); - VMValue params[] = { p, parent, FString(message), messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; + const FString msg = '$' == message[0] ? GStrings(message + 1) : message; + VMValue params[] = { p, parent, msg, messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); From 90b8dbb096c1f44df96d9e579c4a587fd3883dcd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 12:47:16 +0100 Subject: [PATCH 109/207] - removed the separate SSE2 version of the node builder's ClassifyLine function and all code associated with it. Like everything else related to doing standard math with SSE2 vs. x87, there's nothing to be gained here with anything but first generation SSE2 systems which are irrelevant these days. Taking 'thespir2.wad' from https://forum.zdoom.org/viewtopic.php?f=1&t=10655 the SSE2 version is reproducably ~3% slower than the x87 version on my Core i7, which quite closely mirrors all my previous tests since 2007. Overall this just looks like an optimization not worth doing. --- src/CMakeLists.txt | 32 ------- src/nodebuild.cpp | 92 ------------------- src/nodebuild.h | 43 +-------- src/nodebuild_classify_nosse2.cpp | 2 +- src/nodebuild_classify_sse2.cpp | 144 ------------------------------ 5 files changed, 2 insertions(+), 311 deletions(-) delete mode 100644 src/nodebuild_classify_sse2.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5149121c4..4ff73e32c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -397,22 +397,6 @@ if (NOT ZDOOM_USE_SSE2) endif() endif() -if( SSE_MATTERS ) - if( WIN32 ) - set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) - else() - CHECK_FUNCTION_EXISTS(mprotect HAVE_MPROTECT) - if( HAVE_MPROTECT ) - set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) - else() - set( BACKPATCH 0 ) - endif() - endif() - set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." ) -else() - set( BACKPATCH 0 ) -endif() - if( X64 ) set( HAVE_MMX 1 ) else( X64 ) @@ -577,10 +561,6 @@ endif() # Flags -if( BACKPATCH ) - add_definitions( -DBACKPATCH ) -endif() - # Update gitinfo.h add_custom_target( revision_check ALL @@ -726,18 +706,6 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) -if( SSE_MATTERS ) - if( SSE ) - set( X86_SOURCES nodebuild_classify_sse2.cpp ) - set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_ENABLE}" ) - else() - add_definitions( -DDISABLE_SSE ) - endif() -else() - add_definitions( -DDISABLE_SSE ) - set( X86_SOURCES ) -endif() - if( SNDFILE_FOUND ) add_definitions( -DHAVE_SNDFILE ) endif() diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 19dc16b615..6b17c9629d 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -1062,95 +1062,3 @@ void FNodeBuilder::PrintSet (int l, DWORD set) } Printf (PRINT_LOG, "*\n"); } - - - -#ifdef BACKPATCH -#ifdef _WIN32 -extern "C" { -__declspec(dllimport) int __stdcall VirtualProtect(void *, unsigned long, unsigned long, unsigned long *); -} -#define PAGE_EXECUTE_READWRITE 64 -#else -#include -#include -#include -#endif - -#ifdef __GNUC__ -extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -#else -static int *CallerOffset; -int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -#endif -{ - // Select the routine based on SSE2 availability and patch the caller so that - // they call that routine directly next time instead of going through here. - int *calleroffset; - int diff; - int (*func)(node_t &, const FSimpleVert *, const FSimpleVert *, int[2]); - -#ifdef __GNUC__ - calleroffset = (int *)__builtin_return_address(0); -#else - calleroffset = CallerOffset; -#endif -// printf ("Patching for SSE %d @ %p %d\n", SSELevel, calleroffset, *calleroffset); - -#ifndef DISABLE_SSE - if (CPU.bSSE2) - { - func = ClassifyLineSSE2; - diff = int((char *)ClassifyLineSSE2 - (char *)calleroffset); - } - else -#endif - { - func = ClassifyLine2; - diff = int((char *)ClassifyLine2 - (char *)calleroffset); - } - - calleroffset--; - // Patch the caller. -#ifdef _WIN32 - unsigned long oldprotect; - if (VirtualProtect (calleroffset, 4, PAGE_EXECUTE_READWRITE, &oldprotect)) -#else - // must make this page-aligned for mprotect - long pagesize = sysconf(_SC_PAGESIZE); - char *callerpage = (char *)((intptr_t)calleroffset & ~(pagesize - 1)); - size_t protectlen = (intptr_t)calleroffset + sizeof(void*) - (intptr_t)callerpage; - int ptect; - if (!(ptect = mprotect(callerpage, protectlen, PROT_READ|PROT_WRITE|PROT_EXEC))) -#endif - { - *calleroffset = diff; -#ifdef _WIN32 - VirtualProtect (calleroffset, sizeof(void*), oldprotect, &oldprotect); -#else - mprotect(callerpage, protectlen, PROT_READ|PROT_EXEC); -#endif - } - - // And return by calling the real function. - return func (node, v1, v2, sidev); -} - -#ifndef __GNUC__ -// The ClassifyLineBackpatch() function here is a stub that uses inline assembly and nakedness -// to retrieve the return address of the stack before sending control to the real -// ClassifyLineBackpatchC() function. Since BACKPATCH shouldn't be defined on 64-bit builds, -// we're okay that VC++ can't do inline assembly on that target. - -extern "C" __declspec(noinline) __declspec(naked) int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -{ - // We store the return address in a global, so as not to need to mess with the parameter list. - __asm - { - mov eax, [esp] - mov CallerOffset, eax - jmp ClassifyLineBackpatchC - } -} -#endif -#endif diff --git a/src/nodebuild.h b/src/nodebuild.h index 9599bc0d2e..6d730644e2 100644 --- a/src/nodebuild.h +++ b/src/nodebuild.h @@ -53,22 +53,6 @@ struct FSimpleVert fixed_t x, y; }; -extern "C" -{ - int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); -#ifndef DISABLE_SSE - int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); - int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); -#ifdef BACKPATCH -#ifdef __GNUC__ - int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline)); -#else - int __declspec(noinline) ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); -#endif -#endif -#endif -} - class FNodeBuilder { struct FPrivSeg @@ -282,7 +266,7 @@ private: // 1 = seg is in back // -1 = seg cuts the node - inline int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]); + int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]); void FixSplitSharers (const node_t &node); double AddIntersection (const node_t &node, int vertex); @@ -341,28 +325,3 @@ inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int } return s_num > 0.0 ? -1 : 1; } - -inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]) -{ -#ifdef DISABLE_SSE - return ClassifyLine2 (node, v1, v2, sidev); -#else -#if defined(__SSE2__) || defined(_M_X64) - // If compiling with SSE2 support everywhere, just use the SSE2 version. - return ClassifyLineSSE2 (node, v1, v2, sidev); -#elif defined(_MSC_VER) && _MSC_VER < 1300 - // VC 6 does not support SSE optimizations. - return ClassifyLine2 (node, v1, v2, sidev); -#else - // Select the routine based on our flag. -#ifdef BACKPATCH - return ClassifyLineBackpatch (node, v1, v2, sidev); -#else - if (CPU.bSSE2) - return ClassifyLineSSE2 (node, v1, v2, sidev); - else - return ClassifyLine2 (node, v1, v2, sidev); -#endif -#endif -#endif -} diff --git a/src/nodebuild_classify_nosse2.cpp b/src/nodebuild_classify_nosse2.cpp index 2d2c8edea4..44f7e709f4 100644 --- a/src/nodebuild_classify_nosse2.cpp +++ b/src/nodebuild_classify_nosse2.cpp @@ -3,7 +3,7 @@ #define FAR_ENOUGH 17179869184.f // 4<<32 -extern "C" int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) +int FNodeBuilder::ClassifyLine(node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]) { double d_x1 = double(node.x); double d_y1 = double(node.y); diff --git a/src/nodebuild_classify_sse2.cpp b/src/nodebuild_classify_sse2.cpp deleted file mode 100644 index 52429ecb81..0000000000 --- a/src/nodebuild_classify_sse2.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef DISABLE_SSE - -#include "doomtype.h" -#include "nodebuild.h" - -#define FAR_ENOUGH 17179869184.f // 4<<32 - -// You may notice that this function is identical to ClassifyLine2. -// The reason it is SSE2 is because this file is explicitly compiled -// with SSE2 math enabled, but the other files are not. - -extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -{ - double d_x1 = double(node.x); - double d_y1 = double(node.y); - double d_dx = double(node.dx); - double d_dy = double(node.dy); - double d_xv1 = double(v1->x); - double d_xv2 = double(v2->x); - double d_yv1 = double(v1->y); - double d_yv2 = double(v2->y); - - double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy; - double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy; - - int nears = 0; - - if (s_num1 <= -FAR_ENOUGH) - { - if (s_num2 <= -FAR_ENOUGH) - { - sidev[0] = sidev[1] = 1; - return 1; - } - if (s_num2 >= FAR_ENOUGH) - { - sidev[0] = 1; - sidev[1] = -1; - return -1; - } - nears = 1; - } - else if (s_num1 >= FAR_ENOUGH) - { - if (s_num2 >= FAR_ENOUGH) - { - sidev[0] = sidev[1] = -1; - return 0; - } - if (s_num2 <= -FAR_ENOUGH) - { - sidev[0] = -1; - sidev[1] = 1; - return -1; - } - nears = 1; - } - else - { - nears = 2 | int(fabs(s_num2) < FAR_ENOUGH); - } - - if (nears) - { - double l = 1.f / (d_dx*d_dx + d_dy*d_dy); - if (nears & 2) - { - double dist = s_num1 * s_num1 * l; - if (dist < SIDE_EPSILON*SIDE_EPSILON) - { - sidev[0] = 0; - } - else - { - sidev[0] = s_num1 > 0.0 ? -1 : 1; - } - } - else - { - sidev[0] = s_num1 > 0.0 ? -1 : 1; - } - if (nears & 1) - { - double dist = s_num2 * s_num2 * l; - if (dist < SIDE_EPSILON*SIDE_EPSILON) - { - sidev[1] = 0; - } - else - { - sidev[1] = s_num2 > 0.0 ? -1 : 1; - } - } - else - { - sidev[1] = s_num2 > 0.0 ? -1 : 1; - } - } - else - { - sidev[0] = s_num1 > 0.0 ? -1 : 1; - sidev[1] = s_num2 > 0.0 ? -1 : 1; - } - - if ((sidev[0] | sidev[1]) == 0) - { // seg is coplanar with the splitter, so use its orientation to determine - // which child it ends up in. If it faces the same direction as the splitter, - // it goes in front. Otherwise, it goes in back. - - if (node.dx != 0) - { - if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x)) - { - return 0; - } - else - { - return 1; - } - } - else - { - if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y)) - { - return 0; - } - else - { - return 1; - } - } - } - else if (sidev[0] <= 0 && sidev[1] <= 0) - { - return 0; - } - else if (sidev[0] >= 0 && sidev[1] >= 0) - { - return 1; - } - return -1; -} - -#endif From 6210a67f855c664fef01a792fadc1c38d7aedc0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 12:50:11 +0100 Subject: [PATCH 110/207] - fixed messagebox correctly. --- wadsrc/static/zscript/menu/messagebox.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt index b7b611f415..f5a60d9d40 100644 --- a/wadsrc/static/zscript/menu/messagebox.txt +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -61,7 +61,7 @@ class MessageBoxMenu : Menu int mr2 = 170 + SmallFont.StringWidth(Stringtable.Localize("$TXT_NO")); mMouseRight = MAX(mr1, mr2); mParentMenu = parent; - mMessage = SmallFont.BreakLines(message, 300); + mMessage = SmallFont.BreakLines(Stringtable.Localize(message), 300); mMessageMode = messagemode; if (playsound) { From 3412bdf5dc8e01afa7fb84b059d8fe1cc2759d67 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 12:51:24 +0100 Subject: [PATCH 111/207] Revert "Fixed splitting of long lines in message box menu" This reverts commit 76a44ebf9cdef82a3d1dc08bd43e5a960163de54. Fix was done in the wrong place, it should be inside the script so that script-side calls to open a confirmation screen also get proper treatment. --- src/menu/messagebox.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index a68bbc5f10..a1a0fda769 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -67,8 +67,7 @@ DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, { auto c = PClass::FindClass("MessageBoxMenu"); auto p = c->CreateNew(); - const FString msg = '$' == message[0] ? GStrings(message + 1) : message; - VMValue params[] = { p, parent, msg, messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; + VMValue params[] = { p, parent, FString(message), messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); From 03ac816e83dded357d9f72be969b1cee64e97dfe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 14:04:30 +0100 Subject: [PATCH 112/207] - added a gme_stereodepth CVAR. --- src/sound/i_music.cpp | 4 ++++ src/sound/i_music.h | 1 + src/sound/music_gme.cpp | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 1cbca0863d..a896aeee73 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -279,6 +279,10 @@ void MusInfo::TimidityVolumeChanged() { } +void MusInfo::GMEDepthChanged(float val) +{ +} + void MusInfo::FluidSettingInt(const char *, int) { } diff --git a/src/sound/i_music.h b/src/sound/i_music.h index aaa00b020a..069d2f1427 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -84,6 +84,7 @@ public: virtual void FluidSettingNum(const char *setting, double value); // " virtual void FluidSettingStr(const char *setting, const char *value); // " virtual void WildMidiSetOption(int opt, int set); + virtual void GMEDepthChanged(float val); void Start(bool loop, float rel_vol = -1.f, int subsong = 0); diff --git a/src/sound/music_gme.cpp b/src/sound/music_gme.cpp index 6038f23496..d00728ec69 100644 --- a/src/sound/music_gme.cpp +++ b/src/sound/music_gme.cpp @@ -43,6 +43,7 @@ #include #include "v_text.h" #include "files.h" +#include "templates.h" // MACROS ------------------------------------------------------------------ @@ -67,6 +68,7 @@ protected: bool StartTrack(int track, bool getcritsec=true); bool GetTrackInfo(); int CalcSongLength(); + void GMEDepthChanged(float val); static bool Read(SoundStream *stream, void *buff, int len, void *userdata); }; @@ -84,6 +86,12 @@ protected: // Currently not used. CVAR (Float, spc_amp, 1.875f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, gme_stereodepth, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (currSong != nullptr) + currSong->GMEDepthChanged(self); +} + // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- @@ -146,6 +154,7 @@ MusInfo *GME_OpenSong(FileReader &reader, const char *fmt) reader.Seek(fpos, SEEK_SET); return NULL; } + gme_set_stereo_depth(emu, clamp(*gme_stereodepth, 0.f, 1.f)); return new GMESong(emu, sample_rate); } @@ -189,6 +198,19 @@ GMESong::~GMESong() } +//========================================================================== +// +// GMESong :: GMEDepthChanged +// +//========================================================================== + +void GMESong::GMEDepthChanged(float val) +{ + if (Emu != nullptr) + gme_set_stereo_depth(Emu, clamp(val, 0.f, 1.f)); +} + + //========================================================================== // // GMESong :: Play From bb7e19120826837c65c3b6b37bffa940967bbefe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 14:50:02 +0100 Subject: [PATCH 113/207] - allow specification of intermission music based on the destination map. --- src/g_level.h | 1 + src/g_mapinfo.cpp | 12 ++++++++++++ src/wi_stuff.cpp | 5 ++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/g_level.h b/src/g_level.h index d59a4fc09e..c356476a44 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -324,6 +324,7 @@ struct level_info_t FString ExitPic; FString InterMusic; int intermusicorder; + TMap > MapInterMusic; FString SoundInfo; FString SndSeq; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index f83e18ece4..89fe27ddf6 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -915,6 +915,18 @@ DEFINE_MAP_OPTION(intermusic, true) parse.ParseMusic(info->InterMusic, info->intermusicorder); } +DEFINE_MAP_OPTION(mapintermusic, true) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + FString mapname = parse.sc.String; + FString music; + int order; + parse.ParseComma(); + parse.ParseMusic(music, order); + info->MapInterMusic[FName(mapname)] = std::make_pair(music, order); +} + DEFINE_MAP_OPTION(fadetable, true) { parse.ParseAssign(); diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index d5c5554dab..736384e62b 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -2020,7 +2020,10 @@ public: if (bcnt == 1) { // intermission music - use the defaults if none specified - if (level.info->InterMusic.IsNotEmpty()) + auto mus = level.info->MapInterMusic.CheckKey(wbs->next); + if (mus != nullptr) + S_ChangeMusic(mus->first, mus->second); + else if (level.info->InterMusic.IsNotEmpty()) S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder); else S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); From a6761463af1b1cce85cc598652270150785f2f4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:01:55 +0100 Subject: [PATCH 114/207] - added a new showtriggerlines mode that doesn't exclude doors. - use lambdas for the AM checker functions. --- src/am_map.cpp | 85 ++++++++++++++++++-------------------- wadsrc/static/language.eng | 1 + wadsrc/static/menudef.txt | 9 +++- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 9968f4ac43..8df0741828 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -90,7 +90,7 @@ CVAR (Bool, am_customcolors, true, CVAR_ARCHIVE); CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE); CVAR (Int, am_drawmapback, 1, CVAR_ARCHIVE); CVAR (Bool, am_showkeys, true, CVAR_ARCHIVE); -CVAR (Bool, am_showtriggerlines, false, CVAR_ARCHIVE); +CVAR (Int, am_showtriggerlines, 0, CVAR_ARCHIVE); CVAR (Int, am_showthingsprites, 0, CVAR_ARCHIVE); //============================================================================= @@ -2281,58 +2281,47 @@ bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int *), int *s return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false)); } -bool AM_isTeleportSpecial (int special, int *) -{ - return (special == Teleport || - special == Teleport_NoFog || - special == Teleport_ZombieChanger || - special == Teleport_Line); -} - bool AM_isTeleportBoundary (line_t &line) { - return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial); -} - -bool AM_isExitSpecial (int special, int *) -{ - return (special == Teleport_NewMap || - special == Teleport_EndGame || - special == Exit_Normal || - special == Exit_Secret); + return AM_checkSpecialBoundary(line, [](int special, int *) + { + return (special == Teleport || + special == Teleport_NoFog || + special == Teleport_ZombieChanger || + special == Teleport_Line); + }); } bool AM_isExitBoundary (line_t& line) { - return AM_checkSpecialBoundary(line, &AM_isExitSpecial); -} - -bool AM_isTriggerSpecial (int special, int *) -{ - FLineSpecial *spec = P_GetLineSpecialInfo(special); - return spec != NULL - && spec->max_args >= 0 - && special != Door_Open - && special != Door_Close - && special != Door_CloseWaitOpen - && special != Door_Raise - && special != Door_Animated - && special != Generic_Door; + return AM_checkSpecialBoundary(line, [](int special, int *) + { + return (special == Teleport_NewMap || + special == Teleport_EndGame || + special == Exit_Normal || + special == Exit_Secret); + }); } bool AM_isTriggerBoundary (line_t &line) { - return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial); -} - -bool AM_isLockSpecial (int special, int* args) -{ - return special == Door_LockedRaise - || special == ACS_LockedExecute - || special == ACS_LockedExecuteDoor - || (special == Door_Animated && args[3] != 0) - || (special == Generic_Door && args[4] != 0) - || (special == FS_Execute && args[2] != 0); + return am_showtriggerlines == 1? AM_checkSpecialBoundary(line, [](int special, int *) + { + FLineSpecial *spec = P_GetLineSpecialInfo(special); + return spec != NULL + && spec->max_args >= 0 + && special != Door_Open + && special != Door_Close + && special != Door_CloseWaitOpen + && special != Door_Raise + && special != Door_Animated + && special != Generic_Door; + }) : AM_checkSpecialBoundary(line, [](int special, int *) + { + FLineSpecial *spec = P_GetLineSpecialInfo(special); + return spec != NULL + && spec->max_args >= 0; + }); } bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) @@ -2351,7 +2340,15 @@ bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) int special; int *args; - bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args); + bool result = AM_checkSpecialBoundary(line, [](int special, int* args) + { + return special == Door_LockedRaise + || special == ACS_LockedExecute + || special == ACS_LockedExecuteDoor + || (special == Door_Animated && args[3] != 0) + || (special == Generic_Door && args[4] != 0) + || (special == FS_Execute && args[2] != 0); + }, &special, &args); if (result) { diff --git a/wadsrc/static/language.eng b/wadsrc/static/language.eng index bf0a0a91d6..66757cee70 100644 --- a/wadsrc/static/language.eng +++ b/wadsrc/static/language.eng @@ -106,6 +106,7 @@ CMPTMNU_RENDERINGBEHAVIOR = "Rendering Behaviour"; CMPTMNU_SOUNDBEHAVIOR = "Sound Behaviour"; CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only"; +OPTVAL_NODOORS = "All except doors"; C_GRAY = "\ccgrey"; C_DARKGRAY = "\cudark grey"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index d90d1851c9..db2adcdfd5 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1008,6 +1008,13 @@ OptionValue MapBackTypes 2, "$OPTVAL_MAPDEFINEDCOLORSONLY" } +OptionValue MapTriggers +{ + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_NO_DOORS" + 2, "$OPTVAL_ON" +} + OptionMenu AutomapOptions { Title "$AUTOMAPMNU_TITLE" @@ -1031,7 +1038,7 @@ OptionMenu AutomapOptions Option "$AUTOMAPMNU_SHOWMAPLABEL", "am_showmaplabel", "MaplabelTypes" Option "$AUTOMAPMNU_DRAWMAPBACK", "am_drawmapback", "MapBackTypes" Option "$AUTOMAPMNU_SHOWKEYS", "am_showkeys", "OnOff" - Option "$AUTOMAPMNU_SHOWTRIGGERLINES", "am_showtriggerlines", "OnOff" + Option "$AUTOMAPMNU_SHOWTRIGGERLINES", "am_showtriggerlines", "MapTriggers" Option "$AUTOMAPMNU_SHOWTHINGSPRITES", "am_showthingsprites", "STSTypes" } From a0b830c1989b035b89373eeaf0fcda8c50d7d62b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:20:43 +0100 Subject: [PATCH 115/207] - allow all actor list CCMDs to filter by tid. --- src/c_cmds.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index ff83d8342d..7e0a66c4b1 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -937,14 +937,20 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha AActor *mo; const PClass *FilterClass = NULL; int counter = 0; + int tid = 0; if (FilterName != NULL) { FilterClass = PClass::FindActor(FilterName); if (FilterClass == NULL) { - Printf("%s is not an actor class.\n", FilterName); - return; + char *endp; + tid = (int)strtol(FilterName, &endp, 10); + if (*endp != 0) + { + Printf("%s is not an actor class.\n", FilterName); + return; + } } } TThinkerIterator it; @@ -953,10 +959,13 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha { if ((FilterClass == NULL || mo->IsA(FilterClass)) && IsActorType(mo)) { - counter++; - if (!countOnly) - Printf ("%s at (%f,%f,%f)\n", - mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); + if (tid == 0 || tid == mo->tid) + { + counter++; + if (!countOnly) + Printf("%s at (%f,%f,%f)\n", + mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); + } } } Printf("%i match(s) found.\n", counter); From 8b2a5c75a1cc6a6e85b0e2da5dcce0a33d6a450b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:47:37 +0100 Subject: [PATCH 116/207] - added an old submission for PowerReflection, although it had to be seriously reworked and improved. --- src/namedef.h | 2 ++ src/p_interaction.cpp | 22 ++++++++++++++++++++ wadsrc/static/zscript/inventory/powerups.txt | 15 +++++++++++++ 3 files changed, 39 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index 13e9096bc3..5aa7e82dbc 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -197,6 +197,8 @@ xx(PowerWeaponLevel2) xx(PowerFlight) xx(PowerSpeed) xx(PowerTorch) +xx(PowerReflection) +xx(Reflection) xx(CustomInventory) xx(Inventory) xx(CallTryPickup) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index e940c259f8..2e2dd5682d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1162,6 +1162,28 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain. return 0; } + + + AInventory *reflect; + //[RC] Backported from the Zandronum source.. Mostly. + if( target->player && + damage > 0 && + source && + (reflect = target->FindInventory(NAME_PowerReflection)) && + mod != NAME_Reflection) + { + if ( target != source ) + { + // use the reflect item's damage factors to get the final value here. + int reflectdamage = reflect->ApplyDamageFactor(mod, damage); + P_DamageMobj(source, nullptr, target, reflectdamage, NAME_Reflection ); + + // Reset means of death flag. + MeansOfDeath = mod; + } + } + + // Push the target unless the source's weapon's kickback is 0. // (i.e. Gauntlets/Chainsaw) if (!plrDontThrust && inflictor && inflictor != target // [RH] Not if hurting own self diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 346f3d1a76..897fe80e30 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1939,6 +1939,21 @@ class PowerInfiniteAmmo : Powerup } } + +//=========================================================================== +// +// InfiniteAmmo +// +//=========================================================================== + +class PowerReflection : Powerup +{ + Default + { + Powerup.Duration -30; + } +} + //=========================================================================== // // PowerMorph From c7668952d9c0b5e7af6b124b5b24d172474172e1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:50:03 +0100 Subject: [PATCH 117/207] - set sensible defaults for PowerReflection. --- wadsrc/static/zscript/inventory/powerups.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 897fe80e30..1fc63cfbe8 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1950,7 +1950,8 @@ class PowerReflection : Powerup { Default { - Powerup.Duration -30; + Powerup.Duration -60; + DamageFactor 0.5; } } From e6b31dde27b47f484c4d1073cc3760cab5b4b2a3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 16:23:22 +0100 Subject: [PATCH 118/207] - added some flexibility to some Skulltag powerups. - handle these powerups by actual item checks instead of cheat flags. (The same should also be done for the Frightener and Buddha but those are a bit more complex because they are also real cheats.) --- src/d_player.h | 6 -- src/namedef.h | 2 + src/p_interaction.cpp | 37 ++++++-- src/p_mobj.cpp | 3 +- src/p_user.cpp | 12 ++- wadsrc/static/zscript/constants.txt | 16 ++-- wadsrc/static/zscript/inventory/powerups.txt | 92 ++------------------ 7 files changed, 58 insertions(+), 110 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index b16af36116..2d7d439c57 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -209,13 +209,7 @@ typedef enum CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame - CF_DRAIN = 1 << 16, // Player owns a drain powerup - CF_HIGHJUMP = 1 << 18, // more Skulltag flags. Implementation not guaranteed though. ;) - CF_REFLECTION = 1 << 19, - CF_PROSPERITY = 1 << 20, - CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. - CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either. CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either. CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die diff --git a/src/namedef.h b/src/namedef.h index 5aa7e82dbc..dd4a4f5e32 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -197,7 +197,9 @@ xx(PowerWeaponLevel2) xx(PowerFlight) xx(PowerSpeed) xx(PowerTorch) +xx(PowerHighJump) xx(PowerReflection) +xx(PowerDrain) xx(Reflection) xx(CustomInventory) xx(Inventory) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 2e2dd5682d..33605e4e39 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1164,18 +1164,28 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da } - AInventory *reflect; //[RC] Backported from the Zandronum source.. Mostly. if( target->player && damage > 0 && source && - (reflect = target->FindInventory(NAME_PowerReflection)) && - mod != NAME_Reflection) + mod != NAME_Reflection && + target != source) + { - if ( target != source ) + int reflectdamage = 0; + for (auto p = target->player->mo->Inventory; p != nullptr; p = p->Inventory) + { + // This picks the reflection item with the maximum efficiency for the given damage type. + if (p->IsKindOf(NAME_PowerReflection)) + { + int mydamage = p->ApplyDamageFactor(mod, damage); + if (mydamage > reflectdamage) reflectdamage = mydamage; + } + } + + if (reflectdamage > 0) { // use the reflect item's damage factors to get the final value here. - int reflectdamage = reflect->ApplyDamageFactor(mod, damage); P_DamageMobj(source, nullptr, target, reflectdamage, NAME_Reflection ); // Reset means of death flag. @@ -1439,13 +1449,24 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // If the damaging player has the power of drain, give the player 50% of the damage // done in health. - if ( source && source->player && source->player->cheats & CF_DRAIN && !(target->flags5 & MF5_DONTDRAIN)) + if ( source && source->player && !(target->flags5 & MF5_DONTDRAIN)) { if (!target->player || target->player != source->player) { - if ( P_GiveBody( source, damage / 2 )) + double draindamage = 0; + for (auto p = source->player->mo->Inventory; p != nullptr; p = p->Inventory) { - S_Sound( source, CHAN_ITEM, "*drainhealth", 1, ATTN_NORM ); + // This picks the item with the maximum efficiency. + if (p->IsKindOf(NAME_PowerDrain)) + { + double mydamage = p->FloatVar(NAME_Strength); + if (mydamage > draindamage) draindamage = mydamage; + } + } + + if ( P_GiveBody( source, int(draindamage * damage))) + { + S_Sound(source, CHAN_ITEM, "*drainhealth", 1, ATTN_NORM ); } } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a908e115e8..d14c69aadf 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -902,8 +902,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set // and infinite ammo is on if (notakeinfinite && - ((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && - item->IsKindOf(NAME_Ammo)) + ((dmflags & DF_INFINITE_AMMO) || (player && FindInventory(NAME_PowerInfiniteAmmo))) && item->IsKindOf(NAME_Ammo)) { // Nothing to do here, except maybe res = false;? Would it make sense? result = false; diff --git a/src/p_user.cpp b/src/p_user.cpp index 53e27c0f54..5bb0e2127e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2689,9 +2689,19 @@ void P_PlayerThink (player_t *player) else if (level.IsJumpingAllowed() && player->onground && player->jumpTics == 0) { double jumpvelz = player->mo->JumpZ * 35 / TICRATE; + double jumpfac = 0; // [BC] If the player has the high jump power, double his jump velocity. - if ( player->cheats & CF_HIGHJUMP ) jumpvelz *= 2; + // (actually, pick the best factors from all active items.) + for (auto p = player->mo->Inventory; p != nullptr; p = p->Inventory) + { + if (p->IsKindOf(NAME_PowerHighJump)) + { + double f = p->FloatVar(NAME_Strength); + if (f > jumpfac) jumpfac = f; + } + } + if (jumpfac > 0) jumpvelz *= jumpfac; player->mo->Vel.Z += jumpvelz; player->mo->flags2 &= ~MF2_ONMOBJ; diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index e2390cfd1f..422853ea69 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1088,17 +1088,21 @@ enum EPlayerCheats CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame - CF_DRAIN = 1 << 16, // Player owns a drain powerup - CF_HIGHJUMP = 1 << 18, // more Skulltag flags. Implementation not guaranteed though. ;) - CF_REFLECTION = 1 << 19, - CF_PROSPERITY = 1 << 20, - CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact + CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. - CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact + CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either. CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either. CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip + + // These flags no longer exist, but keep the names for some stray mod that might have used them. + CF_DRAIN = 0, + CF_HIGHJUMP = 0, + CF_REFLECTION = 0, + CF_PROSPERITY = 0, + CF_DOUBLEFIRINGSPEED= 0, + CF_INFINITEAMMO = 0, }; const TEXTCOLOR_BRICK = "\034A"; diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 1fc63cfbe8..3b01c97b3d 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1783,32 +1783,9 @@ class PowerDrain : Powerup { Default { + Powerup.Strength 0.5; Powerup.Duration -60; } - - override void InitEffect() - { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player the power to drain life from opponents when he damages them. - Owner.player.cheats |= CF_DRAIN; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the drain power. - Owner.player.cheats &= ~CF_DRAIN; - } - } - } //=========================================================================== @@ -1846,27 +1823,9 @@ class PowerRegeneration : Powerup class PowerHighJump : Powerup { - override void InitEffect() + Default { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player the power to jump much higher. - Owner.player.cheats |= CF_HIGHJUMP; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the high jump power. - Owner.player.cheats &= ~CF_HIGHJUMP; - } + Powerup.Strength 2; } } @@ -1878,27 +1837,9 @@ class PowerHighJump : Powerup class PowerDoubleFiringSpeed : Powerup { - override void InitEffect() + Default { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player the power to shoot twice as fast. - Owner.player.cheats |= CF_DOUBLEFIRINGSPEED; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the shooting twice as fast power. - Owner.player.cheats &= ~CF_DOUBLEFIRINGSPEED; - } + Powerup.Duration -40; } } @@ -1914,29 +1855,6 @@ class PowerInfiniteAmmo : Powerup { Powerup.Duration -30; } - - override void InitEffect() - { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player infinite ammo - Owner.player.cheats |= CF_INFINITEAMMO; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the limitless ammo - Owner.player.cheats &= ~CF_INFINITEAMMO; - } - } } From d80dc098bd1a37aa70234f20e62a10a7b8206e22 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 16:48:24 +0100 Subject: [PATCH 119/207] - added a RESETITEMS MAPINFO flag. --- src/g_game.cpp | 12 ++++++++++++ src/g_level.h | 1 + src/g_mapinfo.cpp | 1 + 3 files changed, 14 insertions(+) diff --git a/src/g_game.cpp b/src/g_game.cpp index b4e4973116..b39ee52a8d 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1343,12 +1343,24 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags) if (mode == FINISH_NoHub && !(level.flags2 & LEVEL2_KEEPFULLINVENTORY)) { // Reduce all owned (visible) inventory to defined maximum interhub amount + TArray todelete; for (item = p->mo->Inventory; item != NULL; item = item->Inventory) { // If the player is carrying more samples of an item than allowed, reduce amount accordingly if (item->ItemFlags & IF_INVBAR && item->Amount > item->InterHubAmount) { item->Amount = item->InterHubAmount; + if ((level.flags3 & LEVEL3_RESETINVENTORY) && !(item->ItemFlags & IF_UNDROPPABLE)) + { + todelete.Push(item); + } + } + } + for (auto it : todelete) + { + if (!(it->ObjectFlags & OF_EuthanizeMe)) + { + it->DepleteOrDestroy(); } } } diff --git a/src/g_level.h b/src/g_level.h index c356476a44..cf5d1865dd 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -223,6 +223,7 @@ enum ELevelFlags : unsigned int // More flags! LEVEL3_FORCEFAKECONTRAST = 0x00000001, // forces fake contrast even with fog enabled + LEVEL3_RESETINVENTORY = 0x00000002, // kills all INVBAR items on map change. }; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 89fe27ddf6..7a7960115e 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1277,6 +1277,7 @@ MapFlagHandlers[] = { "laxmonsteractivation", MITYPE_SETFLAG2, LEVEL2_LAXMONSTERACTIVATION, LEVEL2_LAXACTIVATIONMAPINFO }, { "additive_scrollers", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL, 0 }, { "keepfullinventory", MITYPE_SETFLAG2, LEVEL2_KEEPFULLINVENTORY, 0 }, + { "resetitems", MITYPE_SETFLAG3, LEVEL2_RESETINVENTORY, 0 }, { "monsterfallingdamage", MITYPE_SETFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 }, { "nomonsterfallingdamage", MITYPE_CLRFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 }, { "clipmidtextures", MITYPE_SETFLAG2, LEVEL2_CLIPMIDTEX, 0 }, From ee6e427e78dabdcfb6a2ed9de1febf352e7f8e0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 16:54:09 +0100 Subject: [PATCH 120/207] - fixed: USDF did not allow specials > 255. --- src/p_udmf.cpp | 2 +- src/p_usdf.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index fc71160ae9..0ba75fc4c7 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1393,7 +1393,7 @@ public: if (isTranslated) sec->special = P_TranslateSectorSpecial(sec->special); else if (namespc == NAME_Hexen) { - if (sec->special < 0 || sec->special > 255 || !HexenSectorSpecialOk[sec->special]) + if (sec->special < 0 || sec->special > 140 || !HexenSectorSpecialOk[sec->special]) sec->special = 0; // NULL all unknown specials } continue; diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 5a5f3c8269..8c8a0c6e34 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -192,7 +192,7 @@ class USDFParser : public UDMFParserBase case NAME_Special: reply->ActionSpecial = CheckInt(key); - if (reply->ActionSpecial < 0 || reply->ActionSpecial > 255) + if (reply->ActionSpecial < 0) reply->ActionSpecial = 0; break; From f31ddbc57cbbb5ac373a916dc759a16b87dcebde Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 17:05:04 +0100 Subject: [PATCH 121/207] - allow specifying specials in ZSDF by name. - allow specifying a decal ID by name in UDMF. --- specs/usdf_zdoom.txt | 2 ++ src/g_shared/a_decals.cpp | 15 ++++++++++++--- src/namedef.h | 1 + src/p_usdf.cpp | 5 +++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index cd4393351d..2025b06ba6 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -92,6 +92,8 @@ conversation // Starts a dialog. choice { + specialname = ; // Allows specifying a special by name. + // The amount of an item needed for this option to become available. // You can have as many as needed. All require blocks must be satisfied // to show this option. diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index dfa66795ca..3ad19741ad 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -751,14 +751,23 @@ IMPLEMENT_CLASS(ADecal, false, false) void ADecal::BeginPlay () { - const FDecalTemplate *tpl; + const FDecalTemplate *tpl = nullptr; Super::BeginPlay (); - int decalid = args[0] + (args[1] << 8); // [KS] High byte for decals. + if (args[0] < 0) + { + FName name = ENamedName(-args[0]); + tpl = DecalLibrary.GetDecalByName(name.GetChars()); + } + else + { + int decalid = args[0] + (args[1] << 8); // [KS] High byte for decals. + tpl = DecalLibrary.GetDecalByNum(decalid); + } // If no decal is specified, don't try to create one. - if (decalid != 0 && (tpl = DecalLibrary.GetDecalByNum (decalid)) != 0) + if (tpl != nullptr) { if (!tpl->PicNum.Exists()) { diff --git a/src/namedef.h b/src/namedef.h index dd4a4f5e32..9cd0a19ecb 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -360,6 +360,7 @@ xx(CeilingZ) xx(FloorZ) xx(Health) xx(Pitch) +xx(SpecialName) xx(Special) xx(TID) xx(TIDtoHate) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 8c8a0c6e34..3d2c2e010f 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -196,6 +196,11 @@ class USDFParser : public UDMFParserBase reply->ActionSpecial = 0; break; + case NAME_SpecialName: + if (namespace_bits == Zd) + reply->ActionSpecial = P_FindLineSpecial(CheckString(key)); + break; + case NAME_Arg0: case NAME_Arg1: case NAME_Arg2: From 3f5ef48dacc08bf85741fafbeaee05242d0a1594 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 17:22:02 +0100 Subject: [PATCH 122/207] - allow setting a global dialogue lump through gameinfo. --- src/gi.cpp | 1 + src/gi.h | 1 + src/p_conversation.cpp | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/src/gi.cpp b/src/gi.cpp index fa8afb5459..672ca3263a 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -374,6 +374,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_PATCH(mStatscreenEnteringFont, "statscreen_enteringpatch") GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass") GAMEINFOKEY_BOOL(forcekillscripts, "forcekillscripts") // [JM] Force kill scripts on thing death. (MF7_NOKILLSCRIPTS overrides.) + GAMEINFOKEY_STRING(Dialogue, "dialogue") else { diff --git a/src/gi.h b/src/gi.h index 24053b0029..2c614e3c70 100644 --- a/src/gi.h +++ b/src/gi.h @@ -176,6 +176,7 @@ struct gameinfo_t FName DefaultEndSequence; FString mMapArrow, mCheatMapArrow; FString mEasyKey, mCheatKey; + FString Dialogue; FGIFont mStatscreenMapNameFont; FGIFont mStatscreenFinishedFont; FGIFont mStatscreenEnteringFont; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 90271333c2..f43313682a 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -205,6 +205,11 @@ void P_LoadStrifeConversations (MapData *map, const char *mapname) { if (!LoadScriptFile (scriptname_b, false, 1)) { + if (gameinfo.Dialogue.IsNotEmpty()) + { + if (LoadScriptFile(gameinfo.Dialogue, false, 0)) return; + } + LoadScriptFile ("SCRIPT00", false, 1); } } From c4b546404ace0d20fa5315bba158426abcabaf90 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 17:50:48 +0100 Subject: [PATCH 123/207] - added a 'nocheck' parameter to A_Raise* and Thing_Raise. --- src/actionspecials.h | 2 +- src/p_actionfunctions.cpp | 22 ++++++++++++++++------ src/p_lnspec.cpp | 6 +++--- src/p_local.h | 2 +- src/p_things.cpp | 4 ++-- wadsrc/static/zscript/actor.txt | 6 +++--- wadsrc/static/zscript/constants.txt | 6 ++++++ 7 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 42861b702c..aac1b7161a 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -15,7 +15,7 @@ DEFINE_SPECIAL(Door_LockedRaise, 13, 4, 5, 5) DEFINE_SPECIAL(Door_Animated, 14, 4, 4, 4) DEFINE_SPECIAL(Autosave, 15, 0, 0, 0) // [RH] Save the game *now* DEFINE_SPECIAL(Transfer_WallLight, 16, -1, -1, 2) -DEFINE_SPECIAL(Thing_Raise, 17, 1, 1, 1) +DEFINE_SPECIAL(Thing_Raise, 17, 1, 2, 2) DEFINE_SPECIAL(StartConversation, 18, 1, 2, 2) DEFINE_SPECIAL(Thing_Stop, 19, 1, 1, 1) DEFINE_SPECIAL(Floor_LowerByValue, 20, 3, 4, 4) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 16c8c3267a..51e71cb3f5 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -4602,6 +4602,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags) return 0; } + +enum ERaise +{ + RF_TRANSFERFRIENDLINESS = 1, + RF_NOCHECKPOSITION = 2 +}; + //=========================================================================== // // A_RaiseMaster @@ -4610,11 +4617,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags) DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) { PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL_DEF(copy); + PARAM_INT_DEF(flags); + bool copy = !!(flags & RF_TRANSFERFRIENDLINESS); if (self->master != NULL) { - P_Thing_Raise(self->master, copy ? self : NULL); + P_Thing_Raise(self->master, copy ? self : NULL, (flags & RF_NOCHECKPOSITION)); } return 0; } @@ -4627,16 +4635,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL_DEF(copy); + PARAM_INT_DEF(flags); TThinkerIterator it; AActor *mo; + bool copy = !!(flags & RF_TRANSFERFRIENDLINESS); while ((mo = it.Next()) != NULL) { if (mo->master == self) { - P_Thing_Raise(mo, copy ? self : NULL); + P_Thing_Raise(mo, copy ? self : NULL, (flags & RF_NOCHECKPOSITION)); } } return 0; @@ -4650,18 +4659,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL_DEF(copy); + PARAM_INT_DEF(flags); TThinkerIterator it; AActor *mo; + bool copy = !!(flags & RF_TRANSFERFRIENDLINESS); if (self->master != NULL) { while ((mo = it.Next()) != NULL) { if (mo->master == self->master && mo != self) { - P_Thing_Raise(mo, copy ? self : NULL); + P_Thing_Raise(mo, copy ? self : NULL, (flags & RF_NOCHECKPOSITION)); } } } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 9cbb4aec1d..394203c75b 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1737,14 +1737,14 @@ FUNC(LS_Thing_SpawnFacing) } FUNC(LS_Thing_Raise) -// Thing_Raise(tid) +// Thing_Raise(tid, nocheck) { AActor * target; bool ok = false; if (arg0==0) { - ok = P_Thing_Raise (it,NULL); + ok = P_Thing_Raise (it,NULL, arg1); } else { @@ -1752,7 +1752,7 @@ FUNC(LS_Thing_Raise) while ( (target = iterator.Next ()) ) { - ok |= P_Thing_Raise(target,NULL); + ok |= P_Thing_Raise(target,NULL, arg1); } } return ok; diff --git a/src/p_local.h b/src/p_local.h index 677de09fcd..9ce290be76 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -151,7 +151,7 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog); int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); void P_Thing_SetVelocity(AActor *actor, const DVector3 &vec, bool add, bool setbob); void P_RemoveThing(AActor * actor); -bool P_Thing_Raise(AActor *thing, AActor *raiser); +bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck = false); bool P_Thing_CanRaise(AActor *thing); PClassActor *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); diff --git a/src/p_things.cpp b/src/p_things.cpp index f6c06a1e5e..d4298f934b 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -406,7 +406,7 @@ void P_RemoveThing(AActor * actor) } -bool P_Thing_Raise(AActor *thing, AActor *raiser) +bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck) { FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) @@ -426,7 +426,7 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser) thing->flags |= MF_SOLID; thing->Height = info->Height; // [RH] Use real height thing->radius = info->radius; // [RH] Use real radius - if (!P_CheckPosition (thing, thing->Pos())) + if (!nocheck && !P_CheckPosition (thing, thing->Pos())) { thing->flags = oldflags; thing->radius = oldradius; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2e9752b977..926b03804e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -790,9 +790,9 @@ class Actor : Thinker native native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0); deprecated native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); - native void A_RaiseMaster(bool copy = 0); - native void A_RaiseChildren(bool copy = 0); - native void A_RaiseSiblings(bool copy = 0); + native void A_RaiseMaster(int flags = 0); + native void A_RaiseChildren(int flags = 0); + native void A_RaiseSiblings(int flags = 0); deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, double missileheight); action native bool, Actor A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); native void A_Weave(int xspeed, int yspeed, double xdist, double ydist); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 422853ea69..9e9d4dae83 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -996,6 +996,12 @@ enum EFindFloorCeiling FFCF_NODROPOFF = 256, // Caller does not need a dropoff (saves some time when checking portals) }; +enum ERaise +{ + RF_TRANSFERFRIENDLINESS = 1, + RF_NOCHECKPOSITION = 2 +} + enum ETeleport { TELF_DESTFOG = 1, From 5fe04dfd2022e0f235d647ae3d804814191675d7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 18:37:12 +0100 Subject: [PATCH 124/207] - added A_SprayDecal function. --- src/d_net.cpp | 21 ++------------------- src/g_shared/a_decals.cpp | 18 ++++++++++++++++++ src/g_shared/a_sharedglobal.h | 1 + src/p_actionfunctions.cpp | 8 ++++++++ wadsrc/static/zscript/actor.txt | 1 + 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 7163cdd55d..fb7cac3166 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2376,25 +2376,8 @@ void Net_DoCommand (int type, BYTE **stream, int player) break; case DEM_SPRAY: - { - FTraceResults trace; - - DAngle ang = players[player].mo->Angles.Yaw; - DAngle pitch = players[player].mo->Angles.Pitch; - double c = pitch.Cos(); - DVector3 vec(c * ang.Cos(), c * ang.Sin(), -pitch.Sin()); - - s = ReadString (stream); - - if (Trace (players[player].mo->PosPlusZ(players[player].mo->Height/2), players[player].mo->Sector, - vec, 172., 0, ML_BLOCKEVERYTHING, players[player].mo, trace, TRACE_NoSky)) - { - if (trace.HitType == TRACE_HitWall) - { - DImpactDecal::StaticCreate (s, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); - } - } - } + s = ReadString(stream); + SprayDecal(players[player].mo, s); break; case DEM_PAUSE: diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 3ad19741ad..21f116b072 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -704,6 +704,24 @@ CCMD (spray) Net_WriteString (argv[1]); } +void SprayDecal(AActor *shooter, const char *name) +{ + FTraceResults trace; + + DAngle ang = shooter->Angles.Yaw; + DAngle pitch = shooter->Angles.Pitch; + double c = pitch.Cos(); + DVector3 vec(c * ang.Cos(), c * ang.Sin(), -pitch.Sin()); + + if (Trace(shooter->PosPlusZ(shooter->Height / 2), shooter->Sector, vec, 172., 0, ML_BLOCKEVERYTHING, shooter, trace, TRACE_NoSky)) + { + if (trace.HitType == TRACE_HitWall) + { + DImpactDecal::StaticCreate(name, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); + } + } +} + DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent) { if (tpl == NULL || (tpl = tpl->GetDecal()) == NULL) diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index c9d0d86cef..ea367dd3a4 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -11,6 +11,7 @@ struct F3DFloor; class DBaseDecal; class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent); +void SprayDecal(AActor *shooter, const char *name); class DBaseDecal : public DThinker { diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 51e71cb3f5..53fe2b6a09 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -6932,3 +6932,11 @@ DEFINE_ACTION_FUNCTION(AActor, SetCamera) } return 0; } + +DEFINE_ACTION_FUNCTION(AActor, A_SprayDecal) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(name); + SprayDecal(self, name); + return 0; +} diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 926b03804e..fdc9ddadec 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -868,6 +868,7 @@ class Actor : Thinker native native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetTranslation(name transname); native bool A_SetSize(double newradius, double newheight = -1, bool testpos = false); + native void A_SprayDecal(String name); 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); From fb3d4bd42a7b46d0652c87a0cde7b0c641d095bd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 18:46:06 +0100 Subject: [PATCH 125/207] - added A_SetMugshotState. --- src/p_actionfunctions.cpp | 10 ++++++++++ wadsrc/static/zscript/actor.txt | 1 + 2 files changed, 11 insertions(+) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 53fe2b6a09..54a577e5b9 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -80,6 +80,7 @@ #include "math/cmath.h" #include "g_levellocals.h" #include "r_utility.h" +#include "sbar.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -6940,3 +6941,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SprayDecal) SprayDecal(self, name); return 0; } + +DEFINE_ACTION_FUNCTION(AActor, A_SetMugshotState) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(name); + if (self->CheckLocalView(consoleplayer)) + StatusBar->SetMugShotState(name); + return 0; +} \ No newline at end of file diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index fdc9ddadec..9b52e7271c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -869,6 +869,7 @@ class Actor : Thinker native native void A_SetTranslation(name transname); native bool A_SetSize(double newradius, double newheight = -1, bool testpos = false); native void A_SprayDecal(String name); + native void A_SetMugshotState(String name); 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); From 92b916fd5de907103f906117d915796ad92ef76f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 18:49:40 +0100 Subject: [PATCH 126/207] - fixed: ACS's SetMugshotState function was essentially broken in multiplayer because it contained no checks if the script's activator is connected to the current console player. Ideally this should also be fixed for singleplayer but that would probably break half the mods using this function... --- src/p_acs.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 463868d88a..ad66627f53 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -9423,7 +9423,10 @@ scriptwait: } case PCD_SETMUGSHOTSTATE: - StatusBar->SetMugShotState(FBehavior::StaticLookupString(STACK(1))); + if (!multiplayer || (activator != nullptr && activator->CheckLocalView(consoleplayer))) + { + StatusBar->SetMugShotState(FBehavior::StaticLookupString(STACK(1))); + } sp--; break; From 0cc46a2aafa7e5290f13bec4fb62e8161e7729b4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:05:20 +0100 Subject: [PATCH 127/207] - added a FORCEINFIGHTING flag. --- src/actor.h | 1 + src/p_interaction.cpp | 3 ++- src/p_map.cpp | 1 + src/scripting/thingdef_data.cpp | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index c8c7cbc5ff..b52cb65713 100644 --- a/src/actor.h +++ b/src/actor.h @@ -389,6 +389,7 @@ enum ActorFlag7 MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields. MF7_FORCEZERORADIUSDMG = 0x10000000, // passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. MF7_NOINFIGHTSPECIES = 0x20000000, // don't start infights with one's own species. + MF7_FORCEINFIGHTING = 0x40000000, // overrides a map setting of 'no infighting'. }; // --- mobj.renderflags --- diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 33605e4e39..c13024fcf8 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1772,7 +1772,8 @@ bool AActor::OkayToSwitchTarget (AActor *other) } int infight; - if (flags5 & MF5_NOINFIGHTING) infight=-1; + if (flags7 & MF7_FORCEINFIGHTING) infight = 1; + else if (flags5 & MF5_NOINFIGHTING) infight = -1; else infight = G_SkillProperty(SKILLP_Infight); if (infight < 0 && other->player == NULL && !IsHostile (other)) diff --git a/src/p_map.cpp b/src/p_map.cpp index 13f566b1f4..58aaefc17c 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1177,6 +1177,7 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) if (!victim->player && !shooter->player) { int infight = G_SkillProperty(SKILLP_Infight); + if (infight < 0 && (victim->flags7 & MF7_FORCEINFIGHTING)) infight = 0; // This must override the 'no infight' setting to take effect. if (infight < 0) { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f68667bbbe..3a76002faa 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -318,6 +318,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7), DEFINE_FLAG(MF7, FORCEZERORADIUSDMG, AActor, flags7), DEFINE_FLAG(MF7, NOINFIGHTSPECIES, AActor, flags7), + DEFINE_FLAG(MF7, FORCEINFIGHTING, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), From b0eb19bbc8b80f3ab6f20a3ff57e9ca739fa5252 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:29:27 +0100 Subject: [PATCH 128/207] - added an option to define untranslated fonts through FONTDEFS. Note that due to how the fonts work they cannot be colorized AT ALL! --- src/v_font.cpp | 41 ++++++++++++++++++++++++++++------------- src/v_font.h | 4 +++- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/v_font.cpp b/src/v_font.cpp index a82bd16c17..d668de94ca 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -163,7 +163,7 @@ protected: class FSpecialFont : public FFont { public: - FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump); + FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); void LoadTranslations(); @@ -357,7 +357,7 @@ DEFINE_ACTION_FUNCTION(FFont, GetFont) // //========================================================================== -FFont::FFont (const char *name, const char *nametemplate, int first, int count, int start, int fdlump, int spacewidth) +FFont::FFont (const char *name, const char *nametemplate, int first, int count, int start, int fdlump, int spacewidth, bool notranslate) { int i; FTextureID lump; @@ -367,6 +367,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false; bool stcfn121 = false; + noTranslate = notranslate; Lump = fdlump; Chars = new CharData[count]; charlumps = new FTexture *[count]; @@ -430,7 +431,8 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, if (charlumps[i] != NULL) { - Chars[i].Pic = new FFontChar1 (charlumps[i]); + if (!noTranslate) Chars[i].Pic = new FFontChar1 (charlumps[i]); + else Chars[i].Pic = charlumps[i]; Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); } else @@ -455,7 +457,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, FixXMoves(); - LoadTranslations(); + if (!noTranslate) LoadTranslations(); delete[] charlumps; } @@ -472,11 +474,15 @@ FFont::~FFont () { int count = LastChar - FirstChar + 1; - for (int i = 0; i < count; ++i) + // A noTranslate font directly references the original textures. + if (!noTranslate) { - if (Chars[i].Pic != NULL && Chars[i].Pic->Name[0] == 0) + for (int i = 0; i < count; ++i) { - delete Chars[i].Pic; + if (Chars[i].Pic != NULL && Chars[i].Pic->Name[0] == 0) + { + delete Chars[i].Pic; + } } } delete[] Chars; @@ -752,7 +758,7 @@ void FFont::BuildTranslations (const double *luminosity, const BYTE *identity, FRemapTable *FFont::GetColorTranslation (EColorRange range) const { - if (ActiveColors == 0) + if (ActiveColors == 0 || noTranslate) return NULL; else if (range >= NumTextColors) range = CR_UNTRANSLATED; @@ -1005,6 +1011,7 @@ FFont::FFont (int lump) PatchRemap = NULL; FontName = NAME_None; Cursor = '_'; + noTranslate = false; } //========================================================================== @@ -1962,7 +1969,7 @@ void FFontChar2::MakeTexture () // //========================================================================== -FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump) : FFont(lump) +FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) : FFont(lump) { int i; FTexture **charlumps; @@ -1971,6 +1978,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l memcpy(this->notranslate, notranslate, 256*sizeof(bool)); + noTranslate = donttranslate; FontName = name; Chars = new CharData[count]; charlumps = new FTexture*[count]; @@ -2005,7 +2013,8 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l if (charlumps[i] != NULL) { - Chars[i].Pic = new FFontChar1 (charlumps[i]); + if (!noTranslate) Chars[i].Pic = new FFontChar1 (charlumps[i]); + else Chars[i].Pic = charlumps[i]; Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); } else @@ -2027,7 +2036,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l FixXMoves(); - LoadTranslations(); + if (!noTranslate) LoadTranslations(); delete[] charlumps; } @@ -2158,6 +2167,7 @@ void V_InitCustomFonts() FScanner sc; FTexture *lumplist[256]; bool notranslate[256]; + bool donttranslate; FString namebuffer, templatebuf; int i; int llump,lastlump=0; @@ -2175,6 +2185,7 @@ void V_InitCustomFonts() { memset (lumplist, 0, sizeof(lumplist)); memset (notranslate, 0, sizeof(notranslate)); + donttranslate = false; namebuffer = sc.String; format = 0; start = 33; @@ -2226,6 +2237,10 @@ void V_InitCustomFonts() spacewidth = sc.Number; format = 1; } + else if (sc.Compare("DONTTRANSLATE")) + { + donttranslate = true; + } else if (sc.Compare ("NOTRANSLATION")) { if (format == 1) goto wrong; @@ -2256,7 +2271,7 @@ void V_InitCustomFonts() } if (format == 1) { - FFont *fnt = new FFont (namebuffer, templatebuf, first, count, start, llump, spacewidth); + FFont *fnt = new FFont (namebuffer, templatebuf, first, count, start, llump, spacewidth, donttranslate); fnt->SetCursor(cursor); } else if (format == 2) @@ -2279,7 +2294,7 @@ void V_InitCustomFonts() } if (count > 0) { - FFont *fnt = new FSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump); + FFont *fnt = new FSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump, donttranslate); fnt->SetCursor(cursor); } } diff --git a/src/v_font.h b/src/v_font.h index 21d773d9d4..ec85f76221 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -75,7 +75,7 @@ extern int NumTextColors; class FFont { public: - FFont (const char *fontname, const char *nametemplate, int first, int count, int base, int fdlump, int spacewidth=-1); + FFont (const char *fontname, const char *nametemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false); virtual ~FFont (); virtual FTexture *GetChar (int code, int *const width) const; @@ -100,6 +100,7 @@ public: int GetCharCode(int code, bool needpic) const; char GetCursor() const { return Cursor; } void SetCursor(char c) { Cursor = c; } + bool NoTranslate() const { return noTranslate; } protected: FFont (int lump); @@ -116,6 +117,7 @@ protected: int FontHeight; int GlobalKerning; char Cursor; + bool noTranslate; struct CharData { FTexture *Pic; From 7267e608cf2cf7936b5057490d1dbc783be6604f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:37:25 +0100 Subject: [PATCH 129/207] - added kickback factor skill property. --- src/g_level.h | 2 ++ src/g_skill.cpp | 10 ++++++++++ src/p_interaction.cpp | 1 + 3 files changed, 13 insertions(+) diff --git a/src/g_level.h b/src/g_level.h index cf5d1865dd..03fa70dcdd 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -497,6 +497,7 @@ enum EFSkillProperty // floating point properties SKILLP_Aggressiveness, SKILLP_MonsterHealth, SKILLP_FriendlyHealth, + SKILLP_KickbackFactor, }; int G_SkillProperty(ESkillProperty prop); @@ -514,6 +515,7 @@ struct FSkillInfo double DamageFactor; double ArmorFactor; double HealthFactor; + double KickbackFactor; bool FastMonsters; bool SlowMonsters; diff --git a/src/g_skill.cpp b/src/g_skill.cpp index d158fa4cdd..1bf80bb42d 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -66,6 +66,7 @@ void FMapInfoParser::ParseSkill () skill.DamageFactor = 1.; skill.ArmorFactor = 1.; skill.HealthFactor = 1.; + skill.KickbackFactor = 1.; skill.FastMonsters = false; skill.SlowMonsters = false; skill.DisableCheats = false; @@ -118,6 +119,12 @@ void FMapInfoParser::ParseSkill () sc.MustGetFloat (); skill.DamageFactor = sc.Float; } + else if (sc.Compare("kickbackfactor")) + { + ParseAssign(); + sc.MustGetFloat(); + skill.KickbackFactor = sc.Float; + } else if (sc.Compare ("fastmonsters")) { skill.FastMonsters = true; @@ -436,6 +443,9 @@ double G_SkillProperty(EFSkillProperty prop) case SKILLP_FriendlyHealth: return AllSkills[gameskill].FriendlyHealth; + case SKILLP_KickbackFactor: + return AllSkills[gameskill].KickbackFactor; + } } return 0; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index c13024fcf8..7699fe376d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1212,6 +1212,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da else kickback = source->player->ReadyWeapon->Kickback; + kickback = int(kickback * G_SkillProperty(SKILLP_KickbackFactor)); if (kickback) { AActor *origin = (source && (flags & DMG_INFLICTOR_IS_PUFF))? source : inflictor; From 4d043f086e494bf249a3122affd4ec1681401798 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:41:39 +0100 Subject: [PATCH 130/207] - missed a spot. --- src/g_skill.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 1bf80bb42d..dd772a7451 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -511,6 +511,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) DoubleAmmoFactor = other.DoubleAmmoFactor; DropAmmoFactor = other.DropAmmoFactor; DamageFactor = other.DamageFactor; + KickbackFactor = other.KickbackFactor; FastMonsters = other.FastMonsters; SlowMonsters = other.SlowMonsters; DisableCheats = other.DisableCheats; From 7a1f36bfb00f4f243886874f0a2e0d412f35242a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:01:39 +0100 Subject: [PATCH 131/207] - added RF_DONTINTERPOLATE flag. --- src/actor.h | 4 +++- src/scripting/thingdef_data.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index b52cb65713..d767c6cb2a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -430,6 +430,7 @@ enum ActorRenderFlag RF_ABSMASKPITCH = 0x00800000, // [MC] The mask rotation does not offset by the actor's pitch. RF_INTERPOLATEANGLES = 0x01000000, // [MC] Allow interpolation of the actor's angle, pitch and roll. RF_MAYBEINVISIBLE = 0x02000000, + RF_DONTINTERPOLATE = 0x04000000, // no render interpolation ever! }; // This translucency value produces the closest match to Heretic's TINTTAB. @@ -1321,7 +1322,8 @@ public: } DVector3 InterpolatedPosition(double ticFrac) const { - return Prev + (ticFrac * (Pos() - Prev)); + if (renderflags & RF_DONTINTERPOLATE) return Pos(); + else return Prev + (ticFrac * (Pos() - Prev)); } DRotator InterpolatedAngles(double ticFrac) const { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 3a76002faa..656b754029 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -339,6 +339,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF, XFLIP, AActor, renderflags), DEFINE_FLAG(RF, YFLIP, AActor, renderflags), DEFINE_FLAG(RF, INTERPOLATEANGLES, AActor, renderflags), + DEFINE_FLAG(RF, DONTINTERPOLATE, AActor, renderflags), // Bounce flags DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags), From 0eebaf9f6b65561b9cfdecdebe822bfaa2d32a0c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:06:16 +0100 Subject: [PATCH 132/207] - allow nightmare respawn if the current state has the 'canraise' flag. --- src/p_mobj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d14c69aadf..23e83425f0 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4437,7 +4437,8 @@ void AActor::Tick () return; // freed itself } } - else + + if (tics == -1 || state->GetCanRaise()) { int respawn_monsters = G_SkillProperty(SKILLP_Respawn); // check for nightmare respawn From 9aff224891bf2948c59b97a5105a988c75fc320e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:11:24 +0100 Subject: [PATCH 133/207] - allow a link between the same sector's floor and ceiling. --- src/p_linkedsectors.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/p_linkedsectors.cpp b/src/p_linkedsectors.cpp index 0dd29c10e2..7ac614f2ef 100644 --- a/src/p_linkedsectors.cpp +++ b/src/p_linkedsectors.cpp @@ -329,11 +329,13 @@ bool P_AddSectorLinks(sector_t *control, int tag, INTBOOL ceiling, int movetype) FSectorTagIterator itr(tag); while ((sec = itr.Next()) >= 0) { - // Don't attach to self! - if (control != &level.sectors[sec]) + // Don't attach to self (but allow attaching to this sector's oposite plane. + if (control == &level.sectors[sec]) { - AddSingleSector(scrollplane, &level.sectors[sec], movetype); + if (ceiling == sector_t::floor && movetype & LINK_FLOOR) continue; + if (ceiling == sector_t::ceiling && movetype & LINK_CEILING) continue; } + AddSingleSector(scrollplane, &level.sectors[sec], movetype); } } else From 8cac2d8c849cb7333d54d2c41ecd53e4ffaf9eb1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:27:02 +0100 Subject: [PATCH 134/207] - added a NOATTACK sector flag which prevents monsters from going to their attack states if present. --- specs/udmf_zdoom.txt | 1 + src/namedef.h | 1 + src/p_enemy.cpp | 6 ++++-- src/p_udmf.cpp | 4 ++++ src/r_defs.h | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 797d092efa..f4af55f2df 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -197,6 +197,7 @@ Note: All fields default to false unless mentioned otherwise. desaturation = ; // Color desaturation factor. 0 = none, 1 = full, default = 0. silent = ; // Actors in this sector make no sound, nofallingdamage = ; // Falling damage is disabled in this sector + noattack = ; // Blocks monster attacks in this sector. dropactors = ; // Actors drop with instantly moving floors (*) norespawn = ; // Players can not respawn in this sector soundsequence = ; // The sound sequence to play when this sector moves. Placing a diff --git a/src/namedef.h b/src/namedef.h index 9cd0a19ecb..bb42fc76df 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -773,6 +773,7 @@ xx(BuiltinGetDefault) xx(BuiltinClassCast) xx(BuiltinFormat) xx(Damage) +xx(Noattack) // basic type names xx(Default) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 2fb040a933..5841e6b994 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -349,7 +349,7 @@ bool AActor::CheckMeleeRange () double dist; - if (!pl) + if (!pl || (Sector->Flags & SECF_NOATTACK)) return false; dist = Distance2D (pl); @@ -398,7 +398,7 @@ bool P_CheckMeleeRange2 (AActor *actor) double dist; - if (!actor->target) + if (!actor->target || (actor->Sector->Flags & SECF_NOATTACK)) { return false; } @@ -445,6 +445,8 @@ bool P_CheckMissileRange (AActor *actor) { double dist; + if ((actor->Sector->Flags & SECF_NOATTACK)) return false; + if (!P_CheckSight (actor, actor->target, SF_SEEPASTBLOCKEVERYTHING)) return false; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 0ba75fc4c7..27293b9188 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1658,6 +1658,10 @@ public: sec->planes[sector_t::ceiling].GlowHeight = (float)CheckFloat(key); break; + case NAME_Noattack: + Flag(sec->Flags, SECF_NOATTACK, key); + break; + case NAME_MoreIds: // delay parsing of the tag string until parsing of the sector is complete // This ensures that the ID is always the first tag in the list. diff --git a/src/r_defs.h b/src/r_defs.h index 08c27bfd39..abf43fdf15 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -494,6 +494,7 @@ enum SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode SECF_ENDLEVEL = 512, // ends level when health goes below 10 SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. + SECF_NOATTACK = 2048, // monsters cannot start attacks in this sector. SECF_WASSECRET = 1 << 30, // a secret that was discovered SECF_SECRET = 1 << 31, // a secret sector From 346ada76bce824815dab6fbfb09af0fca66c83d7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:59:24 +0100 Subject: [PATCH 135/207] - allow blocking controller input in the menu. --- src/intermission/intermission.cpp | 3 ++- src/menu/menu.cpp | 4 ++++ wadsrc/static/language.enu | 3 ++- wadsrc/static/menudef.txt | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 27532e7e98..5dddef1051 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -68,6 +68,7 @@ IMPLEMENT_POINTERS_END extern int NoWipe; +CVAR(Bool, nointerscrollabort, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); //========================================================================== // // @@ -647,7 +648,7 @@ void DIntermissionScreenScroller::Init(FIntermissionAction *desc, bool first) int DIntermissionScreenScroller::Responder (event_t *ev) { int res = Super::Responder(ev); - if (res == -1) + if (res == -1 && !nointerscrollabort) { mBackground = mSecondPic; mTicker = mScrollDelay + mScrollTime; diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 71c0ff6453..8b0bf35e97 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -64,6 +64,7 @@ CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE) CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, m_blockcontrollers, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE) @@ -582,6 +583,9 @@ bool M_Responder (event_t *ev) } else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp)) { + // eat blocked controller events without dispatching them. + if (ev->data1 >= KEY_FIRSTJOYBUTTON && m_blockcontrollers) return true; + keyup = ev->type == EV_KeyUp; ch = ev->data1; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 224aa24f0f..64cf4034bf 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1776,6 +1776,7 @@ MOUSEMNU_LOOKSTRAFE = "Lookstrafe"; JOYMNU_CONFIG = "CONFIGURE CONTROLLER"; JOYMNU_OPTIONS = "CONTROLLER OPTIONS"; +JOYMNU_NOMENU = "Block controller input in menu"; // Player Setup Menu MNU_PLAYERSETUP = "PLAYER SETUP"; @@ -1895,7 +1896,7 @@ MISCMNU_DEHLOAD = "Load *.deh/*.bex lumps"; MISCMNU_CACHENODES = "Cache nodes"; MISCMNU_CACHETIME = "Time threshold for node caching"; MISCMNU_CLEARNODECACHE = "Clear node cache"; - +MISCMNU_INTERSCROLL = "Allow skipping of intermission scrollers"; // Automap Options AUTOMAPMNU_TITLE = "AUTOMAP OPTIONS"; AUTOMAPMNU_COLORSET = "Map color set"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index db2adcdfd5..954567d0f4 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -562,6 +562,7 @@ OptionMenu "JoystickOptionsDefaults" { Title "$JOYMNU_OPTIONS" Option "$JOYMNU_ENABLE", "use_joystick", "YesNo" + Option "$JOYMNU_NOMENU", "m_blockcontrollers", "YesNo" IfOption(Windows) { Option "$JOYMNU_DINPUT", "joy_dinput", "YesNo" @@ -945,6 +946,7 @@ OptionMenu "MiscOptions" Option "$MISCMNU_SAVELOADCONFIRMATION", "saveloadconfirmation", "OnOff" Slider "$MISCMNU_AUTOSAVECOUNT", "autosavecount", 1, 20, 1, 0 Option "$MISCMNU_DEHLOAD", "dehload", "dehopt" + Option "$MISCMNU_INTERSCROLL", "nointerscrollabort", "OffOn" StaticText " " Option "$MISCMNU_CACHENODES", "gl_cachenodes", "OnOff" Slider "$MISCMNU_CACHETIME", "gl_cachetime", 0.0, 2.0, 0.1 From 24a505ed3688e13f5695edff55f239a71c5d9c24 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 21:10:53 +0100 Subject: [PATCH 136/207] - fixed: The internal and scripted morph flags did not match. --- wadsrc/static/zscript/constants.txt | 31 ++++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 9e9d4dae83..a74b61d16e 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -214,20 +214,23 @@ enum ESelectWeaponFlags // Morph constants enum EMorphFlags { - MRF_ADDSTAMINA = 1, - MRF_FULLHEALTH = 2, - MRF_UNDOBYTOMEOFPOWER = 4, - MRF_UNDOBYCHAOSDEVICE = 8, - MRF_FAILNOTELEFRAG = 16, - MRF_FAILNOLAUGH = 32, - MRF_WHENINVULNERABLE = 64, - MRF_LOSEACTUALWEAPON = 128, - MRF_NEWTIDBEHAVIOUR = 256, - MRF_UNDOBYDEATH = 512, - MRF_UNDOBYDEATHFORCED = 1024, - MRF_UNDOBYDEATHSAVES = 2048, - MRF_UNDOALWAYS = 4096, - MRF_TRANSFERTRANSLATION = 8192, + MRF_OLDEFFECTS = 0x00000000, + MRF_ADDSTAMINA = 0x00000001, + MRF_FULLHEALTH = 0x00000002, + MRF_UNDOBYTOMEOFPOWER = 0x00000004, + MRF_UNDOBYCHAOSDEVICE = 0x00000008, + MRF_FAILNOTELEFRAG = 0x00000010, + MRF_FAILNOLAUGH = 0x00000020, + MRF_WHENINVULNERABLE = 0x00000040, + MRF_LOSEACTUALWEAPON = 0x00000080, + MRF_NEWTIDBEHAVIOUR = 0x00000100, + MRF_UNDOBYDEATH = 0x00000200, + MRF_UNDOBYDEATHFORCED = 0x00000400, + MRF_UNDOBYDEATHSAVES = 0x00000800, + MRF_UNDOBYTIMEOUT = 0x00001000, + MRF_UNDOALWAYS = 0x00002000, + MRF_TRANSFERTRANSLATION = 0x00004000, + MRF_STANDARDUNDOING = MORPH_UNDOBYTOMEOFPOWER | MORPH_UNDOBYCHAOSDEVICE | MORPH_UNDOBYTIMEOUT, }; // Flags for A_RailAttack and A_CustomRailgun From f6dd99d3aab6a3167abe07553c164a7a1d2b2635 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 21:20:47 +0100 Subject: [PATCH 137/207] - added A_Morph function. --- src/g_shared/a_morph.cpp | 27 +++++++++++++++++++++++++++ wadsrc/static/zscript/actor.txt | 1 + 2 files changed, 28 insertions(+) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 1ae3c4b5ef..9259561b09 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -701,3 +701,30 @@ void AMorphedMonster::Tick () Super::Tick (); } } + + +DEFINE_ACTION_FUNCTION(AActor, A_Morph) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AActor); + PARAM_INT_DEF(duration); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(enter_flash, AActor); + PARAM_CLASS_DEF(exit_flash, AActor); + bool res = false; + if (self->player) + { + if (type->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + { + res = P_MorphPlayer(self->player, self->player, type, duration, flags, enter_flash, exit_flash); + } + } + else + { + if (type->IsKindOf(RUNTIME_CLASS(AMorphedMonster))) + { + res = P_MorphMonster(self, type, duration, flags, enter_flash, exit_flash); + } + } + ACTION_RETURN_BOOL(res); +} diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9b52e7271c..99c23c7bfe 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -796,6 +796,7 @@ class Actor : Thinker native deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, double missileheight); action native bool, Actor A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); native void A_Weave(int xspeed, int yspeed, double xdist, double ydist); + native bool A_Morph(class type, int duration = 0, int flags = 0, class enter_flash = null, class exit_flash = null); action native state, bool A_Teleport(statelabel teleportstate = null, class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, double mindist = 128, double maxdist = 0, int ptr = AAPTR_DEFAULT); From 3d500f049594a4559d28998421d7adc19d5ec014 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 21:36:06 +0100 Subject: [PATCH 138/207] - added default obituaries for damage types. Note that this is only implemented for the new official way of doing this in MAPINFO, but not in DECORATE! --- src/info.cpp | 13 +++++++++++++ src/info.h | 3 +++ src/p_interaction.cpp | 21 +++++++++++++-------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index 90d847fcc8..81912150b5 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -767,6 +767,13 @@ DEFINE_ACTION_FUNCTION(_DamageTypeDefinition, IgnoreArmor) ACTION_RETURN_BOOL(DamageTypeDefinition::IgnoreArmor(type)); } +FString DamageTypeDefinition::GetObituary(FName type) +{ + DamageTypeDefinition *dtd = Get(type); + if (dtd) return dtd->Obituary; + return ""; +} + //========================================================================== // @@ -859,6 +866,12 @@ void FMapInfoParser::ParseDamageDefinition() dtd.DefaultFactor = sc.Float; if (dtd.DefaultFactor == 0) dtd.ReplaceFactor = true; } + if (sc.Compare("OBITUARY")) + { + sc.MustGetStringName("="); + sc.MustGetString(); + dtd.Obituary = sc.String; + } else if (sc.Compare("REPLACEFACTOR")) { dtd.ReplaceFactor = true; diff --git a/src/info.h b/src/info.h index 05785f90b6..50db1e4b63 100644 --- a/src/info.h +++ b/src/info.h @@ -214,6 +214,7 @@ struct DamageTypeDefinition public: DamageTypeDefinition() { Clear(); } + FString Obituary; double DefaultFactor; bool ReplaceFactor; bool NoArmor; @@ -221,6 +222,7 @@ public: void Apply(FName type); void Clear() { + Obituary = ""; DefaultFactor = 1.; ReplaceFactor = false; NoArmor = false; @@ -228,6 +230,7 @@ public: static bool IgnoreArmor(FName type); static int ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors); + static FString GetObituary(FName type); private: static double GetMobjDamageFactor(FName type, DmgFactors const * const factors); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 7699fe376d..38d9cd3751 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -216,15 +216,20 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf } } - switch (mod) + FString obit = DamageTypeDefinition::GetObituary(mod); + if (obit.IsNotEmpty()) messagename = obit; + else { - case NAME_Suicide: messagename = "OB_SUICIDE"; break; - case NAME_Falling: messagename = "OB_FALLING"; break; - case NAME_Crush: messagename = "OB_CRUSH"; break; - case NAME_Exit: messagename = "OB_EXIT"; break; - case NAME_Drowning: messagename = "OB_WATER"; break; - case NAME_Slime: messagename = "OB_SLIME"; break; - case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break; + switch (mod) + { + case NAME_Suicide: messagename = "OB_SUICIDE"; break; + case NAME_Falling: messagename = "OB_FALLING"; break; + case NAME_Crush: messagename = "OB_CRUSH"; break; + case NAME_Exit: messagename = "OB_EXIT"; break; + case NAME_Drowning: messagename = "OB_WATER"; break; + case NAME_Slime: messagename = "OB_SLIME"; break; + case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break; + } } // Check for being killed by a voodoo doll. From 51b5b327ef58670a2abc3be2203456be945b9a08 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 21:38:08 +0100 Subject: [PATCH 139/207] - fixed constant names. --- wadsrc/static/zscript/constants.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index a74b61d16e..c15433cd63 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -230,7 +230,7 @@ enum EMorphFlags MRF_UNDOBYTIMEOUT = 0x00001000, MRF_UNDOALWAYS = 0x00002000, MRF_TRANSFERTRANSLATION = 0x00004000, - MRF_STANDARDUNDOING = MORPH_UNDOBYTOMEOFPOWER | MORPH_UNDOBYCHAOSDEVICE | MORPH_UNDOBYTIMEOUT, + MRF_STANDARDUNDOING = MRF_UNDOBYTOMEOFPOWER | MRF_UNDOBYCHAOSDEVICE | MRF_UNDOBYTIMEOUT, }; // Flags for A_RailAttack and A_CustomRailgun From 80e9763d645ac70ccd26028bf873c0fcc0e9d368 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 22:10:35 +0100 Subject: [PATCH 140/207] - added a NOMENU option for skills. --- src/g_level.h | 1 + src/g_skill.cpp | 6 ++++ src/menu/menu.h | 1 - src/menu/menudef.cpp | 86 ++++++++++++++++++++++++++------------------ 4 files changed, 58 insertions(+), 36 deletions(-) diff --git a/src/g_level.h b/src/g_level.h index 03fa70dcdd..06a91259a5 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -524,6 +524,7 @@ struct FSkillInfo bool EasyBossBrain; bool EasyKey; + bool NoMenu; int RespawnCounter; int RespawnLimit; double Aggressiveness; diff --git a/src/g_skill.cpp b/src/g_skill.cpp index dd772a7451..25108c0dfd 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -60,6 +60,7 @@ void FMapInfoParser::ParseSkill () bool thisisdefault = false; bool acsreturnisset = false; + skill.NoMenu = false; skill.AmmoFactor = 1.; skill.DoubleAmmoFactor = 2.; skill.DropAmmoFactor = -1.; @@ -149,6 +150,10 @@ void FMapInfoParser::ParseSkill () { skill.AutoUseHealth = true; } + else if (sc.Compare("nomenu")) + { + skill.NoMenu = true; + } else if (sc.Compare("respawntime")) { ParseAssign(); @@ -508,6 +513,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) { Name = other.Name; AmmoFactor = other.AmmoFactor; + NoMenu = other.NoMenu; DoubleAmmoFactor = other.DoubleAmmoFactor; DropAmmoFactor = other.DropAmmoFactor; DamageFactor = other.DamageFactor; diff --git a/src/menu/menu.h b/src/menu/menu.h index 6d7bdc9271..0b6b55ea26 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -339,7 +339,6 @@ void M_ActivateMenu(DMenu *menu); void M_ClearMenus (); void M_ParseMenuDefs(); void M_StartupSkillMenu(FGameStartup *gs); -int M_GetDefaultSkill(); void M_StartControlPanel (bool makeSound); void M_SetMenu(FName menu, int param = -1); void M_StartMessage(const char *message, int messagemode, FName action = NAME_None); diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index bc95198f27..dc4fff1a71 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -1327,6 +1327,43 @@ void M_StartupSkillMenu(FGameStartup *gs) { static int done = -1; bool success = false; + TArray MenuSkills; + TArray SkillIndices; + if (MenuSkills.Size() == 0) + { + for (unsigned ind = 0; ind < AllSkills.Size(); ind++) + { + if (!AllSkills[ind].NoMenu) + { + MenuSkills.Push(&AllSkills[ind]); + SkillIndices.Push(ind); + } + } + } + if (MenuSkills.Size() == 0) I_Error("No valid skills for menu found. At least one must be defined."); + + int defskill = DefaultSkill; + if ((unsigned int)defskill >= MenuSkills.Size()) + { + defskill = SkillIndices[(MenuSkills.Size() - 1) / 2]; + } + if (AllSkills[defskill].NoMenu) + { + for (defskill = 0; defskill < (int)AllSkills.Size(); defskill++) + { + if (!AllSkills[defskill].NoMenu) break; + } + } + int defindex = 0; + for (unsigned i = 0; i < MenuSkills.Size(); i++) + { + if (MenuSkills[i] == &AllSkills[defskill]) + { + defindex = i; + break; + } + } + DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Skillmenu); if (desc != nullptr) { @@ -1350,12 +1387,7 @@ void M_StartupSkillMenu(FGameStartup *gs) if (done != restart) { done = restart; - int defskill = DefaultSkill; - if ((unsigned int)defskill >= AllSkills.Size()) - { - defskill = (AllSkills.Size() - 1) / 2; - } - ld->mSelectedItem = ld->mItems.Size() + defskill; + ld->mSelectedItem = ld->mItems.Size() + defindex; int posy = y; int topy = posy; @@ -1368,9 +1400,9 @@ void M_StartupSkillMenu(FGameStartup *gs) } // center the menu on the screen if the top space is larger than the bottom space - int totalheight = posy + AllSkills.Size() * ld->mLinespacing - topy; + int totalheight = posy + MenuSkills.Size() * ld->mLinespacing - topy; - if (totalheight < 190 || AllSkills.Size() == 1) + if (totalheight < 190 || MenuSkills.Size() == 1) { int newtop = (200 - totalheight + topy) / 2; int topdelta = newtop - topy; @@ -1393,9 +1425,9 @@ void M_StartupSkillMenu(FGameStartup *gs) } unsigned firstitem = ld->mItems.Size(); - for(unsigned int i = 0; i < AllSkills.Size(); i++) + for(unsigned int i = 0; i < MenuSkills.Size(); i++) { - FSkillInfo &skill = AllSkills[i]; + FSkillInfo &skill = *MenuSkills[i]; DMenuItemBase *li; // Using a different name for skills that must be confirmed makes handling this easier. FName action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ? @@ -1409,22 +1441,22 @@ void M_StartupSkillMenu(FGameStartup *gs) if (skill.PicName.Len() != 0 && pItemText == nullptr) { FTextureID tex = GetMenuTexture(skill.PicName); - li = CreateListMenuItemPatch(ld->mXpos, y, ld->mLinespacing, skill.Shortcut, tex, action, i); + li = CreateListMenuItemPatch(ld->mXpos, y, ld->mLinespacing, skill.Shortcut, tex, action, SkillIndices[i]); } else { EColorRange color = (EColorRange)skill.GetTextColor(); if (color == CR_UNTRANSLATED) color = ld->mFontColor; li = CreateListMenuItemText(x, y, ld->mLinespacing, skill.Shortcut, - pItemText? *pItemText : skill.MenuName, ld->mFont, color,ld->mFontColor2, action, i); + pItemText? *pItemText : skill.MenuName, ld->mFont, color,ld->mFontColor2, action, SkillIndices[i]); } ld->mItems.Push(li); GC::WriteBarrier(*desc, li); y += ld->mLinespacing; } - if (AllEpisodes[gs->Episode].mNoSkill || AllSkills.Size() == 1) + if (AllEpisodes[gs->Episode].mNoSkill || MenuSkills.Size() == 1) { - ld->mAutoselect = firstitem + M_GetDefaultSkill(); + ld->mAutoselect = firstitem + defindex; } else { @@ -1443,7 +1475,7 @@ fail: MenuDescriptors[NAME_Skillmenu] = od; od->mMenuName = NAME_Skillmenu; od->mTitle = "$MNU_CHOOSESKILL"; - od->mSelectedItem = 0; + od->mSelectedItem = defindex; od->mScrollPos = 0; od->mClass = nullptr; od->mPosition = -15; @@ -1457,9 +1489,9 @@ fail: od = static_cast(*desc); od->mItems.Clear(); } - for(unsigned int i = 0; i < AllSkills.Size(); i++) + for(unsigned int i = 0; i < MenuSkills.Size(); i++) { - FSkillInfo &skill = AllSkills[i]; + FSkillInfo &skill = *MenuSkills[i]; DMenuItemBase *li; // Using a different name for skills that must be confirmed makes handling this easier. const char *action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ? @@ -1470,29 +1502,13 @@ fail: { pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass); } - li = CreateOptionMenuItemSubmenu(pItemText? *pItemText : skill.MenuName, action, i); + li = CreateOptionMenuItemSubmenu(pItemText? *pItemText : skill.MenuName, action, SkillIndices[i]); od->mItems.Push(li); GC::WriteBarrier(od, li); if (!done) { done = true; - od->mSelectedItem = M_GetDefaultSkill(); + od->mSelectedItem = defindex; } } } - -//============================================================================= -// -// Returns the default skill level. -// -//============================================================================= - -int M_GetDefaultSkill() -{ - int defskill = DefaultSkill; - if ((unsigned int)defskill >= AllSkills.Size()) - { - defskill = (AllSkills.Size() - 1) / 2; - } - return defskill; -} From f918a9d9a77e8227698b4b3a812f9839f0546486 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 22:31:43 +0100 Subject: [PATCH 141/207] - added a BOUNCE_NotOnShootables flag that hopefully helps addressing the biggest glitch in the bouncing code. --- src/actor.h | 1 + src/p_map.cpp | 5 +++++ src/scripting/thingdef_data.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/src/actor.h b/src/actor.h index d767c6cb2a..2ed0047405 100644 --- a/src/actor.h +++ b/src/actor.h @@ -468,6 +468,7 @@ enum ActorBounceFlag BOUNCE_MBF = 1<<12, // This in itself is not a valid mode, but replaces MBF's MF_BOUNCE flag. BOUNCE_AutoOffFloorOnly = 1<<13, // like BOUNCE_AutoOff, but only on floors BOUNCE_UseBounceState = 1<<14, // Use Bounce[.*] states + BOUNCE_NotOnShootables = 1<<15, // do not bounce off shootable actors if we are a projectile. Explode instead. BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF, diff --git a/src/p_map.cpp b/src/p_map.cpp index 58aaefc17c..9b3a257ec8 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3537,6 +3537,11 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) if ((mo->flags & MF_MISSILE) && (mo->flags2 & MF2_RIP) && BlockingMobj->flags & MF_SHOOTABLE) return true; + if (BlockingMobj->flags & MF_SHOOTABLE && mo->BounceFlags & BOUNCE_NotOnShootables) + { + mo->bouncecount = 1; // let it explode now. + } + if (mo->bouncecount>0 && --mo->bouncecount == 0) { if (mo->flags & MF_MISSILE) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 656b754029..265dc079b4 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -356,6 +356,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG2(BOUNCE_MBF, MBFBOUNCER, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_AutoOffFloorOnly, BOUNCEAUTOOFFFLOORONLY, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_UseBounceState, USEBOUNCESTATE, AActor, BounceFlags), + DEFINE_FLAG2(BOUNCE_NotOnShootables, DONTBOUNCEONSHOOTABLES, AActor, BounceFlags), }; // These won't be accessible through bitfield variables From 8c30ca213dc82de729f99d53a1d5fd86ca54afed Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 22:55:36 +0100 Subject: [PATCH 142/207] - allow loading of zips that have one root folder with all content contained within this folder. This top level's folder name will be stripped out from all file names, unless it is a special name that maps to a known namespace. --- src/resourcefiles/file_zip.cpp | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 3ae7088230..18f690205c 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -217,12 +217,66 @@ bool FZipFile::Open(bool quiet) char *dirptr = (char*)directory; FZipLump *lump_p = Lumps; + + // Check if all files have the same prefix so that this can be stripped out. + FString name0; for (DWORD i = 0; i < NumLumps; i++) { FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; int len = LittleShort(zip_fh->NameLength); FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); + + dirptr += sizeof(FZipCentralDirectoryInfo) + + LittleShort(zip_fh->NameLength) + + LittleShort(zip_fh->ExtraLength) + + LittleShort(zip_fh->CommentLength); + + if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. + { + free(directory); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", Filename); + return false; + } + + name.ToLower(); + if (i == 0) + { + // check for special names, if one of these gets found this must be treated as a normal zip. + bool isspecial = !name.Compare("flats/") || + !name.Compare("textures/") || + !name.Compare("hires/") || + !name.Compare("sprites/") || + !name.Compare("voxels/") || + !name.Compare("colormaps/") || + !name.Compare("acs/") || + !name.Compare("voices/") || + !name.Compare("patches/") || + !name.Compare("graphics/") || + !name.Compare("sounds/") || + !name.Compare("music/"); + if (isspecial) break; + name0 = name; + } + else + { + if (name.IndexOf(name0) != 0) + { + name0 = ""; + break; + } + } + } + + dirptr = (char*)directory; + lump_p = Lumps; + for (DWORD i = 0; i < NumLumps; i++) + { + FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; + + int len = LittleShort(zip_fh->NameLength); + FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); + if (name0.IsNotEmpty()) name = name.Mid(name0.Len()); dirptr += sizeof(FZipCentralDirectoryInfo) + LittleShort(zip_fh->NameLength) + LittleShort(zip_fh->ExtraLength) + From 0514a997db2586cd7666832b582afadd122b2bac Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 23:07:16 +0100 Subject: [PATCH 143/207] - added a new argument to GlassBreak to allow it to spawn other types of debris than GlassJunk by passing a spawn ID. --- src/actionspecials.h | 2 +- src/p_lnspec.cpp | 37 +++++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index aac1b7161a..233bb8958e 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -47,7 +47,7 @@ DEFINE_SPECIAL(Ceiling_CrushRaiseAndStay, 45, 3, 4, 4) DEFINE_SPECIAL(Floor_CrushStop, 46, 1, 1, 1) DEFINE_SPECIAL(Ceiling_MoveToValue, 47, 3, 5, 5) DEFINE_SPECIAL(Sector_Attach3dMidtex, 48, -1, -1, 3) -DEFINE_SPECIAL(GlassBreak, 49, 0, 1, 1) +DEFINE_SPECIAL(GlassBreak, 49, 0, 1, 2) DEFINE_SPECIAL(ExtraFloor_LightOnly, 50, -1, -1, 2) DEFINE_SPECIAL(Sector_SetLink, 51, 4, 4, 4) DEFINE_SPECIAL(Scroll_Wall, 52, 5, 5, 5) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 394203c75b..ee70dcee5d 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -3177,7 +3177,7 @@ FUNC(LS_ClearForceField) } FUNC(LS_GlassBreak) -// GlassBreak (bNoJunk) +// GlassBreak (bNoJunk, junkID) { bool switched; bool quest1, quest2; @@ -3197,7 +3197,6 @@ FUNC(LS_GlassBreak) { if (!arg0) { // Break some glass - AActor *glass; DVector2 linemid((ln->v1->fX() + ln->v2->fX()) / 2, (ln->v1->fY() + ln->v2->fY()) / 2); @@ -3209,18 +3208,32 @@ FUNC(LS_GlassBreak) y += (ln->frontsector->centerspot.y - y) / 5; */ + auto type = SpawnableThings.CheckKey(arg1); for (int i = 0; i < 7; ++i) { - glass = Spawn("GlassJunk", DVector3(linemid, ONFLOORZ), ALLOW_REPLACE); - - glass->AddZ(24.); - glass->SetState (glass->SpawnState + (pr_glass() % glass->health)); - - glass->Angles.Yaw = pr_glass() * (360 / 256.); - glass->VelFromAngle(pr_glass() & 3); - glass->Vel.Z = (pr_glass() & 7); - // [RH] Let the shards stick around longer than they did in Strife. - glass->tics += pr_glass(); + AActor *glass = nullptr; + if (arg1 > 0) + { + if (type != nullptr) + { + glass = Spawn(*type, DVector3(linemid, ONFLOORZ), ALLOW_REPLACE); + glass->AddZ(24.); + } + } + else + { + glass = Spawn("GlassJunk", DVector3(linemid, ONFLOORZ), ALLOW_REPLACE); + glass->AddZ(24.); + glass->SetState(glass->SpawnState + (pr_glass() % glass->health)); + } + if (glass != nullptr) + { + glass->Angles.Yaw = pr_glass() * (360 / 256.); + glass->VelFromAngle(pr_glass() & 3); + glass->Vel.Z = (pr_glass() & 7); + // [RH] Let the shards stick around longer than they did in Strife. + glass->tics += pr_glass(); + } } } if (quest1 || quest2) From e4e023e59a516aa8d74b7db02b27dbe6c45fa542 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 23:21:56 +0100 Subject: [PATCH 144/207] - the UDMF health key for actors was not correctly implemented. This addresses the problem by adding a second one and documenting 'Health' as implemented. - fixed: Several ZDoom-exclusive actor keys did not check the current namespace. --- specs/udmf_zdoom.txt | 4 ++-- src/namedef.h | 1 + src/p_udmf.cpp | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index f4af55f2df..553c753603 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -263,8 +263,8 @@ Note: All fields default to false unless mentioned otherwise. gravity = ; // Set per-actor gravity. Positive values are multiplied with the class's property, // negative values are used as their absolute. Default = 1.0. - health = ; // Set per-actor health. Positive values are multiplied with the class's property, - // negative values are used as their absolute. Default = 1. + health = ; // Set per-actor health as an absolute value. Default = actor default. + healthfactor = ; // Set per-actor health as a factor to the original. Default = 1. renderstyle = ; // Set per-actor render style, overriding the class default. Possible values can be "normal", // "none", "add" or "additive", "subtract" or "subtractive", "stencil", "translucentstencil", diff --git a/src/namedef.h b/src/namedef.h index bb42fc76df..28de568183 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -46,6 +46,7 @@ xx(Shadow) xx(Subtract) xx(Subtractive) xx(FillColor) +xx(HealthFactor) // Healingradius types xx(Mana) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 27293b9188..b9300f6543 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -515,6 +515,7 @@ public: FString arg0str, arg1str; memset(th, 0, sizeof(*th)); + double healthfactor = 1; th->Gravity = 1; th->RenderStyle = STYLE_Count; th->Alpha = -1; @@ -738,38 +739,52 @@ public: break; case NAME_Alpha: + CHECK_N(Zd | Zdt) th->Alpha = CheckFloat(key); break; case NAME_FillColor: + CHECK_N(Zd | Zdt) th->fillcolor = CheckInt(key); break; case NAME_Health: + CHECK_N(Zd | Zdt) th->health = CheckInt(key); break; + case NAME_HealthFactor: + CHECK_N(Zd | Zdt) + healthfactor = CheckFloat(key); + break; + case NAME_Score: + CHECK_N(Zd | Zdt) th->score = CheckInt(key); break; case NAME_Pitch: + CHECK_N(Zd | Zdt) th->pitch = (short)CheckInt(key); break; case NAME_Roll: + CHECK_N(Zd | Zdt) th->roll = (short)CheckInt(key); break; case NAME_ScaleX: + CHECK_N(Zd | Zdt) th->Scale.X = CheckFloat(key); break; case NAME_ScaleY: + CHECK_N(Zd | Zdt) th->Scale.Y = CheckFloat(key); break; case NAME_Scale: + CHECK_N(Zd | Zdt) th->Scale.X = th->Scale.Y = CheckFloat(key); break; @@ -793,6 +808,7 @@ public: { th->args[1] = -FName(arg1str); } + th->health = int(th->health * healthfactor); // Thing specials are only valid in namespaces with Hexen-type specials // and in ZDoomTranslated - which will use the translator on them. if (namespc == NAME_ZDoomTranslated) From 1ed2a0baf9ef30f2b2c18ad3bb83fbdeea5fb76e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 23:49:53 +0100 Subject: [PATCH 145/207] - fixed: The intermission screen did not show 'entering' for cluster-less maps. --- src/wi_stuff.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 736384e62b..5542130e6c 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1155,7 +1155,8 @@ public: void WI_initShowNextLoc () { - if (wbs->next_ep == -1) + auto info = FindLevelInfo(wbs->next, false); + if (info == nullptr) { // Last map in episode - there is no next location! WI_End(); From c8445703acb85fdbef17765a41698e681e1ec1da Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 01:41:27 +0100 Subject: [PATCH 146/207] - added a workaround for the 'cannot split a seg' error in the node builder: In order to prevent all segs from ending up on the same side it will now force the bogus seg onto the other side of the node - regardless of whether this is correct or not, because the most important thing here is that the set of segs gets split to prevent the node builder from ending up in an endless recursion trying to split the same set of data and endlessly failing. Note that this is not a fix, it's merely a countermeasure to avoid the crash in ZPack's E2M6 which this seems to achieve. --- src/nodebuild.cpp | 78 ++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 6b17c9629d..30c44b69c0 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -818,41 +818,57 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou newvert.y += fixed_t(frac * double(Vertices[seg->v2].y - newvert.y)); vertnum = VertexMap->SelectVertexClose (newvert); - if (vertnum == (unsigned int)seg->v1 || vertnum == (unsigned int)seg->v2) + if (vertnum != (unsigned int)seg->v1 && vertnum != (unsigned int)seg->v2) { - Printf("SelectVertexClose selected endpoint of seg %u\n", set); + seg2 = SplitSeg(set, vertnum, sidev[0]); + + Segs[seg2].next = outset0; + outset0 = seg2; + Segs[set].next = outset1; + outset1 = set; + _count0++; + _count1++; + + // Also split the seg on the back side + if (Segs[set].partner != DWORD_MAX) + { + int partner1 = Segs[set].partner; + int partner2 = SplitSeg(partner1, vertnum, sidev[1]); + // The newly created seg stays in the same set as the + // back seg because it has not been considered for splitting + // yet. If it had been, then the front seg would have already + // been split, and we would not be in this default case. + // Moreover, the back seg may not even be in the set being + // split, so we must not move its pieces into the out sets. + Segs[partner1].next = partner2; + Segs[partner2].partner = seg2; + Segs[seg2].partner = partner2; + } + + if (GLNodes) + { + AddIntersection(node, vertnum); + } } - - seg2 = SplitSeg (set, vertnum, sidev[0]); - - Segs[seg2].next = outset0; - outset0 = seg2; - Segs[set].next = outset1; - outset1 = set; - _count0++; - _count1++; - - // Also split the seg on the back side - if (Segs[set].partner != DWORD_MAX) + else { - int partner1 = Segs[set].partner; - int partner2 = SplitSeg (partner1, vertnum, sidev[1]); - // The newly created seg stays in the same set as the - // back seg because it has not been considered for splitting - // yet. If it had been, then the front seg would have already - // been split, and we would not be in this default case. - // Moreover, the back seg may not even be in the set being - // split, so we must not move its pieces into the out sets. - Segs[partner1].next = partner2; - Segs[partner2].partner = seg2; - Segs[seg2].partner = partner2; + // all that matters here is to prevent a crash so we must make sure that we do not end up with all segs being sorted to the same side - even if this may not be correct. + // But if we do not do that this code would not be able to move on. Just discarding the seg is also not an option because it won't guarantee that we achieve an actual split. + if (_count0 == 0) + { + side = 0; + seg->next = outset0; + outset0 = set; + _count0++; + } + else + { + side = 1; + seg->next = outset1; + outset1 = set; + _count1++; + } } - - if (GLNodes) - { - AddIntersection (node, vertnum); - } - break; } if (side >= 0 && GLNodes) From 1e1194a669bd99608bed8169430277efe94db3e8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 01:53:51 +0100 Subject: [PATCH 147/207] - fixed: Dp mot strip the top level folder name in Zips if they only contain one entry or if the first entry isn't a directory. --- src/resourcefiles/file_zip.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 18f690205c..bd2990dec3 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -220,7 +220,7 @@ bool FZipFile::Open(bool quiet) // Check if all files have the same prefix so that this can be stripped out. FString name0; - for (DWORD i = 0; i < NumLumps; i++) + if (NumLumps > 1) for (DWORD i = 0; i < NumLumps; i++) { FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; @@ -244,6 +244,7 @@ bool FZipFile::Open(bool quiet) { // check for special names, if one of these gets found this must be treated as a normal zip. bool isspecial = !name.Compare("flats/") || + name.IndexOf("/") < 0 || !name.Compare("textures/") || !name.Compare("hires/") || !name.Compare("sprites/") || From c7cf619ff401d877fb7af68fb1e986762050e108 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 01:58:21 +0100 Subject: [PATCH 148/207] - Caution: Wads.GetLumpName with a char pointer is stupid because it doesn't 0-terminate its return. --- src/gl/data/gl_data.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gl/data/gl_data.cpp b/src/gl/data/gl_data.cpp index 93e4d5697a..36ae3ad8f4 100644 --- a/src/gl/data/gl_data.cpp +++ b/src/gl/data/gl_data.cpp @@ -109,6 +109,7 @@ void AdjustSpriteOffsets() { char str[9]; Wads.GetLumpName(str, i); + str[8] = 0; FTextureID texid = TexMan.CheckForTexture(str, FTexture::TEX_Sprite, 0); if (texid.isValid() && Wads.GetLumpFile(TexMan[texid]->SourceLump) > FWadCollection::IWAD_FILENUM) { From 3a5124e10eac0d24ae59d9d10aca7ecdf1569675 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 02:09:56 +0100 Subject: [PATCH 149/207] - fixed: TakeInventory needs to check for subclasses of PowerInfiniteAmmo. --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 23e83425f0..d6da38961e 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -902,7 +902,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set // and infinite ammo is on if (notakeinfinite && - ((dmflags & DF_INFINITE_AMMO) || (player && FindInventory(NAME_PowerInfiniteAmmo))) && item->IsKindOf(NAME_Ammo)) + ((dmflags & DF_INFINITE_AMMO) || (player && FindInventory(NAME_PowerInfiniteAmmo, true))) && item->IsKindOf(NAME_Ammo)) { // Nothing to do here, except maybe res = false;? Would it make sense? result = false; From 720e05d131f7d309e236240ca6b62b2ca16b03a4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 02:31:19 +0100 Subject: [PATCH 150/207] - fixed memory leak in DEM_NETEVENT. - added handling for DEM_NETEVENT to SkipCommand. - keep the data of DEM_NETEVENT at a fixed length to simplify handling. --- src/d_net.cpp | 9 +++++++-- src/events.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index fb7cac3166..10ff7d0fc4 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2666,12 +2666,13 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_NETEVENT: { - FString ename = ReadString(stream); + const char *ename = ReadString(stream); int argn = ReadByte(stream); int arg[3] = { 0, 0, 0 }; - for (int i = 0; i < argn; i++) + for (int i = 0; i < 3; i++) arg[i] = ReadLong(stream); E_Console(player, ename, arg[0], arg[1], arg[2]); + delete[] ename; } break; @@ -2721,6 +2722,10 @@ void Net_SkipCommand (int type, BYTE **stream) skip = strlen ((char *)(*stream)) + 5; break; + case DEM_NETEVENT: + skip = strlen((char *)(*stream)) + 13; + break; + case DEM_SUMMON2: case DEM_SUMMONFRIEND2: case DEM_SUMMONFOE2: diff --git a/src/events.cpp b/src/events.cpp index d714eefce4..a0780fb92b 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -1139,7 +1139,7 @@ CCMD(netevent) Net_WriteByte(DEM_NETEVENT); Net_WriteString(argv[1]); Net_WriteByte(argn); - for (int i = 0; i < argn; i++) + for (int i = 0; i < 3; i++) Net_WriteLong(arg[i]); } } From 0c660ff29ca9f2915f9aaea31edaed374c7fd7e5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 10:37:47 +0100 Subject: [PATCH 151/207] - added an option to add elements to an existing options menu. Note that for list menus this does not exist because they require complete setup to work as intended. --- src/menu/menudef.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index dc4fff1a71..239366dcfe 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -871,6 +871,25 @@ static void ParseOptionMenu(FScanner &sc) } +//============================================================================= +// +// +// +//============================================================================= + +static void ParseAddOptionMenu(FScanner &sc) +{ + sc.MustGetString(); + + DMenuDescriptor **pOld = MenuDescriptors.CheckKey(sc.String); + if (pOld == nullptr || *pOld == nullptr || !(*pOld)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor))) + { + sc.ScriptError("%s is not an option menu that can be extended", sc.String); + } + ParseOptionMenuBody(sc, (DOptionMenuDescriptor*)(*pOld)); +} + + //============================================================================= // // @@ -935,6 +954,10 @@ void M_ParseMenuDefs() { ParseOptionMenu(sc); } + else if (sc.Compare("ADDOPTIONMENU")) + { + ParseAddOptionMenu(sc); + } else if (sc.Compare("DEFAULTOPTIONMENU")) { ParseOptionMenuBody(sc, DefaultOptionMenuSettings); From 073e63ed045db1e1b3de99a1cd4368606eb8c4a4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 10:50:21 +0100 Subject: [PATCH 152/207] - Added a check for all z-movement for floor huggers so that it doesn't skip all the height checks if +NODROPOFF is also given. --- src/p_map.cpp | 4 ++-- src/p_mobj.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 9b3a257ec8..6413b392b5 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2281,7 +2281,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, } #endif } - if (!(thing->flags & MF_TELEPORT) && !(thing->flags3 & MF3_FLOORHUGGER)) + if (!(thing->flags & MF_TELEPORT) && (!(thing->flags3 & MF3_FLOORHUGGER) || thing->flags5 & MF5_NODROPOFF)) { if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > thing->Z()) { // [RH] Don't let normal missiles climb steps @@ -2772,7 +2772,7 @@ bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags) if (thing->Top() > tm.ceilingz) return false; } - if (!(thing->flags & MF_TELEPORT) && !(thing->flags3 & MF3_FLOORHUGGER)) + if (!(thing->flags & MF_TELEPORT) && (!(thing->flags3 & MF3_FLOORHUGGER) || thing->flags5 & MF5_NODROPOFF)) { if (tm.floorz - newz > thing->MaxStepHeight) { // too big a step up diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d6da38961e..dfb0c73124 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2958,7 +2958,7 @@ void P_ZMovement (AActor *mo, double oldfloorz) mo->Vel.Z = 0; return; } - else if (mo->flags3 & MF3_FLOORHUGGER) + else if ((mo->flags3 & MF3_FLOORHUGGER) && !(mo->flags5 & MF5_NODROPOFF)) { // Floor huggers can go up steps return; } From e84a2899f92e09ef87aba574b00acaedaa52779c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 10:52:29 +0100 Subject: [PATCH 153/207] - this needs one more check. --- src/p_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 6413b392b5..70b18df7fa 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2283,7 +2283,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, } if (!(thing->flags & MF_TELEPORT) && (!(thing->flags3 & MF3_FLOORHUGGER) || thing->flags5 & MF5_NODROPOFF)) { - if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > thing->Z()) + if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > thing->Z() && !(thing->flags3 & MF3_FLOORHUGGER)) { // [RH] Don't let normal missiles climb steps goto pushline; } @@ -2778,7 +2778,7 @@ bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags) { // too big a step up return false; } - else if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > newz) + else if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > newz && !(thing->flags3 & MF3_FLOORHUGGER)) { // [RH] Don't let normal missiles climb steps return false; } From f9f9f2d5fc7b7a0231519db8c78826bc61743053 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 11:22:51 +0100 Subject: [PATCH 154/207] - added selfdamagefactor actor property. --- src/info.cpp | 2 ++ src/info.h | 1 + src/p_interaction.cpp | 5 +++++ src/p_mobj.cpp | 1 + src/scripting/thingdef_properties.cpp | 10 ++++++++++ 5 files changed, 19 insertions(+) diff --git a/src/info.cpp b/src/info.cpp index 81912150b5..84d8e26be4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -257,6 +257,7 @@ PClassActor::PClassActor() WoundHealth = 6; FastSpeed = -1.; RDFactor = 1.; + SelfDamageFactor = 1.; CameraHeight = INT_MIN; DropItems = NULL; @@ -317,6 +318,7 @@ void PClassActor::DeriveData(PClass *newclass) newa->WoundHealth = WoundHealth; newa->FastSpeed = FastSpeed; newa->RDFactor = RDFactor; + newa->SelfDamageFactor = SelfDamageFactor; newa->CameraHeight = CameraHeight; newa->HowlSound = HowlSound; newa->BloodType = BloodType; diff --git a/src/info.h b/src/info.h index 50db1e4b63..a9f79182f3 100644 --- a/src/info.h +++ b/src/info.h @@ -299,6 +299,7 @@ public: int WoundHealth; // Health needed to enter wound state double FastSpeed; // speed in fast mode double RDFactor; // Radius damage factor + double SelfDamageFactor; double CameraHeight; // Height of camera when used as such FSoundID HowlSound; // Sound being played when electrocuted or poisoned FName BloodType; // Blood replacement type diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 38d9cd3751..4c23c8123c 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1020,6 +1020,11 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da } return 0; } + if (target == source && damage < TELEFRAG_DAMAGE) + { + damage = int(damage * target->GetClass()->SelfDamageFactor); + } + // [MC] Changed it to check rawdamage here for consistency, even though that doesn't actually do anything // different here. At any rate, invulnerable is being checked before type factoring, which is then being // checked by player cheats/invul/buddha followed by monster buddha. This is inconsistent. Don't let the diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index dfb0c73124..f85f2c9eb3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -321,6 +321,7 @@ DEFINE_FIELD(PClassActor, GibHealth) DEFINE_FIELD(PClassActor, WoundHealth) DEFINE_FIELD(PClassActor, FastSpeed) DEFINE_FIELD(PClassActor, RDFactor) +DEFINE_FIELD(PClassActor, SelfDamageFactor) DEFINE_FIELD(PClassActor, CameraHeight) DEFINE_FIELD(PClassActor, HowlSound) DEFINE_FIELD(PClassActor, BloodType) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 50b81310ca..6537e24820 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1430,6 +1430,16 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor) static_cast(info)->RDFactor = i; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(selfdamagefactor, F, Actor) +{ + PROP_DOUBLE_PARM(i, 0); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->SelfDamageFactor = i; +} + //========================================================================== // //========================================================================== From 78538ed9efa1dbd5efa7162f7674aa661649d6ba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 14:53:39 +0100 Subject: [PATCH 155/207] - missed an else. --- src/info.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.cpp b/src/info.cpp index 84d8e26be4..580abbf1a0 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -868,7 +868,7 @@ void FMapInfoParser::ParseDamageDefinition() dtd.DefaultFactor = sc.Float; if (dtd.DefaultFactor == 0) dtd.ReplaceFactor = true; } - if (sc.Compare("OBITUARY")) + else if (sc.Compare("OBITUARY")) { sc.MustGetStringName("="); sc.MustGetString(); From cc598dfddeb5ba507249041e95ca9d10498b8929 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 15:16:03 +0100 Subject: [PATCH 156/207] - fixed: To get the final error handling from the serializer, Close must be called before the destructor gets invoked. - added line feeds to all error messages in the serializer. --- src/g_level.cpp | 1 + src/serializer.cpp | 62 ++++++++++++++++++++++++---------------------- src/serializer.h | 1 + 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 01911f7423..b0de51b43e 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1624,6 +1624,7 @@ void G_UnSnapshotLevel (bool hubLoad) } } } + arc.Close(); } // No reason to keep the snapshot around once the level's been entered. level.info->Snapshot.Clean(); diff --git a/src/serializer.cpp b/src/serializer.cpp index a577056aff..fd9af832c0 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -486,6 +486,8 @@ bool FSerializer::OpenReader(FCompressedBuffer *input) void FSerializer::Close() { + if (w == nullptr && r == nullptr) return; // double close? This should skip the I_Error at the bottom. + if (w != nullptr) { delete w; @@ -590,7 +592,7 @@ bool FSerializer::BeginObject(const char *name) } else { - Printf(TEXTCOLOR_RED "Object expected for '%s'", name); + Printf(TEXTCOLOR_RED "Object expected for '%s'\n", name); mErrors++; return false; } @@ -656,7 +658,7 @@ bool FSerializer::BeginArray(const char *name) } else { - Printf(TEXTCOLOR_RED "Array expected for '%s'", name); + Printf(TEXTCOLOR_RED "Array expected for '%s'\n", name); mErrors++; return false; } @@ -748,7 +750,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe else { assert(false && "Integer expected"); - Printf(TEXTCOLOR_RED "Integer expected for '%s[%d]'", key, i); + Printf(TEXTCOLOR_RED "Integer expected for '%s[%d]'\n", key, i); mErrors++; } } @@ -756,7 +758,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe else { assert(false && "array expected"); - Printf(TEXTCOLOR_RED "array expected for '%s'", key); + Printf(TEXTCOLOR_RED "array expected for '%s'\n", key); mErrors++; } } @@ -800,7 +802,7 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num) else { assert(false && "Integer expected"); - Printf(TEXTCOLOR_RED "Integer expected for '%s'", key); + Printf(TEXTCOLOR_RED "Integer expected for '%s'\n", key); mErrors++; } } @@ -1005,7 +1007,7 @@ void FSerializer::ReadObjects(bool hubtravel) PClass *cls = PClass::FindClass(clsname); if (cls == nullptr) { - Printf("Unknown object class '%s' in savegame", clsname.GetChars()); + Printf(TEXTCOLOR_RED "Unknown object class '%s' in savegame\n", clsname.GetChars()); founderrors = true; r->mDObjects[i] = RUNTIME_CLASS(AActor)->CreateNew(); // make sure we got at least a valid pointer for the duration of the loading process. r->mDObjects[i]->Destroy(); // but we do not want to keep this around, so destroy it right away. @@ -1041,7 +1043,7 @@ void FSerializer::ReadObjects(bool hubtravel) catch (CRecoverableError &err) { // In case something in here throws an error, let's continue and deal with it later. - Printf(TEXTCOLOR_RED "'%s'\n while restoring %s", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object"); + Printf(TEXTCOLOR_RED "'%s'\n while restoring %s\n", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object"); mErrors++; } } @@ -1055,7 +1057,7 @@ void FSerializer::ReadObjects(bool hubtravel) assert(!founderrors); if (founderrors) { - Printf(TEXTCOLOR_RED "Failed to restore all objects in savegame"); + Printf(TEXTCOLOR_RED "Failed to restore all objects in savegame\n"); mErrors++; } } @@ -1064,7 +1066,7 @@ void FSerializer::ReadObjects(bool hubtravel) // nuke all objects we created here. for (auto obj : r->mDObjects) { - obj->Destroy(); + if (!(obj->ObjectFlags & OF_EuthanizeMe)) obj->Destroy(); } r->mDObjects.Clear(); @@ -1182,7 +1184,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *def } else { - Printf(TEXTCOLOR_RED "boolean type expected for '%s'", key); + Printf(TEXTCOLOR_RED "boolean type expected for '%s'\n", key); arc.mErrors++; } } @@ -1218,7 +1220,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_ } else { - Printf(TEXTCOLOR_RED "integer type expected for '%s'", key); + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); arc.mErrors++; } } @@ -1254,7 +1256,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint6 } else { - Printf(TEXTCOLOR_RED "integer type expected for '%s'", key); + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); arc.mErrors++; } } @@ -1291,7 +1293,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_ } else { - Printf(TEXTCOLOR_RED "integer type expected for '%s'", key); + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); arc.mErrors++; } } @@ -1327,7 +1329,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint3 } else { - Printf(TEXTCOLOR_RED "integer type expected for '%s'", key); + Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key); arc.mErrors++; } } @@ -1405,7 +1407,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double } else { - Printf(TEXTCOLOR_RED "float type expected for '%s'", key); + Printf(TEXTCOLOR_RED "float type expected for '%s'\n", key); arc.mErrors++; } } @@ -1548,7 +1550,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe } else { - Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'", key); + Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key); value.SetNull(); arc.mErrors++; } @@ -1564,7 +1566,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe else { assert(false && "not a texture"); - Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'", key); + Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key); value.SetNull(); arc.mErrors++; } @@ -1649,7 +1651,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje else { assert(false && "invalid object reference"); - Printf(TEXTCOLOR_RED "Invalid object reference for '%s'", key); + Printf(TEXTCOLOR_RED "Invalid object reference for '%s'\n", key); value = nullptr; arc.mErrors++; if (retcode) *retcode = false; @@ -1698,7 +1700,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d } else { - Printf(TEXTCOLOR_RED "String expected for '%s'", key); + Printf(TEXTCOLOR_RED "String expected for '%s'\n", key); arc.mErrors++; value = NAME_None; } @@ -1746,7 +1748,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicCol } } assert(false && "not a colormap"); - Printf(TEXTCOLOR_RED "object does not represent a colormap for '%s'", key); + Printf(TEXTCOLOR_RED "object does not represent a colormap for '%s'\n", key); cm = &NormalLight; } } @@ -1787,7 +1789,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI } else { - Printf(TEXTCOLOR_RED "string type expected for '%s'", key); + Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); sid = 0; arc.mErrors++; } @@ -1836,7 +1838,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor } else { - Printf(TEXTCOLOR_RED "string type expected for '%s'", key); + Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); clst = nullptr; arc.mErrors++; } @@ -1884,7 +1886,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&cl } else { - Printf(TEXTCOLOR_RED "string type expected for '%s'", key); + Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key); clst = nullptr; arc.mErrors++; } @@ -1960,20 +1962,20 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState { // this can actually happen by changing the DECORATE so treat it as a warning, not an error. state = nullptr; - Printf(TEXTCOLOR_ORANGE "Invalid state '%s+%d' for '%s'", cls.GetString(), ndx.GetInt(), key); + Printf(TEXTCOLOR_ORANGE "Invalid state '%s+%d' for '%s'\n", cls.GetString(), ndx.GetInt(), key); } } else { assert(false && "not a state"); - Printf(TEXTCOLOR_RED "data does not represent a state for '%s'", key); + Printf(TEXTCOLOR_RED "data does not represent a state for '%s'\n", key); arc.mErrors++; } } else if (!retcode) { assert(false && "not an array"); - Printf(TEXTCOLOR_RED "array type expected for '%s'", key); + Printf(TEXTCOLOR_RED "array type expected for '%s'\n", key); arc.mErrors++; } } @@ -2028,7 +2030,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDial } else { - Printf(TEXTCOLOR_RED "integer expected for '%s'", key); + Printf(TEXTCOLOR_RED "integer expected for '%s'\n", key); arc.mErrors++; node = nullptr; } @@ -2077,7 +2079,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&p } else { - Printf(TEXTCOLOR_RED "string expected for '%s'", key); + Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); pstr = nullptr; arc.mErrors++; } @@ -2119,7 +2121,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString } else { - Printf(TEXTCOLOR_RED "string expected for '%s'", key); + Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); pstr = ""; arc.mErrors++; } @@ -2168,7 +2170,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr } else { - Printf(TEXTCOLOR_RED "string expected for '%s'", key); + Printf(TEXTCOLOR_RED "string expected for '%s'\n", key); pstr = nullptr; arc.mErrors++; } diff --git a/src/serializer.h b/src/serializer.h index 4f0d90cecd..7527eeb3c3 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -64,6 +64,7 @@ public: ~FSerializer() { + mErrors = 0; // The destructor may not throw an exception so silence the error checker. Close(); } bool OpenWriter(bool pretty = true); From e9364fccb86f1d06df48a04050a65d5ab6fb0b4b Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Mon, 27 Feb 2017 12:02:46 -0500 Subject: [PATCH 157/207] - Fixed: voxels were not properly remapped after "restart" ccmd --- src/d_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_main.cpp b/src/d_main.cpp index b430c7f04b..77e0edda04 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2692,6 +2692,7 @@ void D_DoomMain (void) // These calls from inside V_Init2 are still necessary C_NewModeAdjust(); M_InitVideoModesMenu(); + Renderer->RemapVoxels(); D_StartTitle (); // start up intro loop setmodeneeded = false; // This may be set to true here, but isn't needed for a restart } From 4bcbd5c0117b52d0e4c767d21c3299df3621536a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 18:35:29 +0100 Subject: [PATCH 158/207] - clear WF_WEAPONBOBBING in P_FireWeapon, because otherwise the first frame of the fire animation will be drawn in the current bobbing position and not centered. --- src/p_pspr.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 8b8e93f6ad..47675699a2 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -536,6 +536,7 @@ void P_FireWeapon (player_t *player, FState *state) return; } + player->WeaponState &= ~WF_WEAPONBOBBING; player->mo->PlayAttacking (); weapon->bAltFire = false; if (state == nullptr) @@ -572,6 +573,7 @@ void P_FireWeaponAlt (player_t *player, FState *state) return; } + player->WeaponState &= ~WF_WEAPONBOBBING; player->mo->PlayAttacking (); weapon->bAltFire = true; From f82ab889b21980e0d2c1588aca92bb047f409125 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 18:44:58 +0100 Subject: [PATCH 159/207] - added ACS strarg function which can convert a string into a string argument for ACS specials. --- src/p_acs.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index ad66627f53..4a2ca3fd9b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4367,6 +4367,7 @@ enum EACSFunctions ACSF_SetTranslation, ACSF_GetActorFloorTexture, ACSF_GetActorFloorTerrain, + ACSF_StrArg, // OpenGL stuff @@ -6087,7 +6088,8 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; } - + case ACSF_StrArg: + return -FName(FBehavior::StaticLookupString(args[0])); default: break; From 321c846d0123a35c6a3374eb177b47f7e8a15e8c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 19:46:27 +0100 Subject: [PATCH 160/207] - added StealthAlpha actor property for defining a minimum visibility value of a stealth monster. --- src/info.cpp | 2 ++ src/info.h | 1 + src/p_mobj.cpp | 5 +++-- src/scripting/thingdef_properties.cpp | 10 ++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index 580abbf1a0..7cac3569d9 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -258,6 +258,7 @@ PClassActor::PClassActor() FastSpeed = -1.; RDFactor = 1.; SelfDamageFactor = 1.; + StealthAlpha = 0.; CameraHeight = INT_MIN; DropItems = NULL; @@ -319,6 +320,7 @@ void PClassActor::DeriveData(PClass *newclass) newa->FastSpeed = FastSpeed; newa->RDFactor = RDFactor; newa->SelfDamageFactor = SelfDamageFactor; + newa->StealthAlpha = StealthAlpha; newa->CameraHeight = CameraHeight; newa->HowlSound = HowlSound; newa->BloodType = BloodType; diff --git a/src/info.h b/src/info.h index a9f79182f3..6d6329f88f 100644 --- a/src/info.h +++ b/src/info.h @@ -301,6 +301,7 @@ public: double RDFactor; // Radius damage factor double SelfDamageFactor; double CameraHeight; // Height of camera when used as such + double StealthAlpha; // Minmum alpha for MF_STEALTH. FSoundID HowlSound; // Sound being played when electrocuted or poisoned FName BloodType; // Blood replacement type FName BloodType2; // Bloopsplatter replacement type diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f85f2c9eb3..d218d24dee 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -322,6 +322,7 @@ DEFINE_FIELD(PClassActor, WoundHealth) DEFINE_FIELD(PClassActor, FastSpeed) DEFINE_FIELD(PClassActor, RDFactor) DEFINE_FIELD(PClassActor, SelfDamageFactor) +DEFINE_FIELD(PClassActor, StealthAlpha) DEFINE_FIELD(PClassActor, CameraHeight) DEFINE_FIELD(PClassActor, HowlSound) DEFINE_FIELD(PClassActor, BloodType) @@ -4100,9 +4101,9 @@ void AActor::Tick () else if (visdir < 0) { Alpha -= 1.5/TICRATE; - if (Alpha < 0) + if (Alpha < GetClass()->StealthAlpha) { - Alpha = 0; + Alpha = GetClass()->StealthAlpha; visdir = 0; } } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 6537e24820..cf70b19aee 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1440,6 +1440,16 @@ DEFINE_PROPERTY(selfdamagefactor, F, Actor) static_cast(info)->SelfDamageFactor = i; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(stealthalpha, F, Actor) +{ + PROP_DOUBLE_PARM(i, 0); + assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); + static_cast(info)->StealthAlpha = i; +} + //========================================================================== // //========================================================================== From ac4074a69a685810bfba58e76c8a76effd4d2149 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 19:51:37 +0100 Subject: [PATCH 161/207] - allow sprites and particles simultaneously for puffs. --- src/p_mobj.cpp | 2 +- wadsrc/static/menudef.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d218d24dee..88bb1d40a9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6009,7 +6009,7 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 if (cl_pufftype && updown != 3 && (puff->flags4 & MF4_ALLOWPARTICLES)) { P_DrawSplash2 (32, pos, particledir, updown, 1); - puff->renderflags |= RF_INVISIBLE; + if (cl_pufftype == 1) puff->renderflags |= RF_INVISIBLE; } if ((flags & PF_HITTHING) && puff->SeeSound) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 954567d0f4..b66b381bad 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -638,6 +638,7 @@ OptionValue PuffTypes { 0.0, "$OPTVAL_SPRITES" 1.0, "$OPTVAL_PARTICLES" + 2.0, "$OPTVAL_SPRITESPARTICLES" } OptionValue Wipes From e511f7f84b96963557947e99325523ef8bf56548 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 20:07:21 +0100 Subject: [PATCH 162/207] - added a damage type parameter to MDK CCMD. --- src/d_net.cpp | 13 +++++++++---- src/d_protocol.h | 3 ++- src/m_cheat.cpp | 21 +++++++++++++++++++-- src/m_cheat.h | 1 + src/version.h | 2 +- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 10ff7d0fc4..6ba77bc2ae 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2380,6 +2380,11 @@ void Net_DoCommand (int type, BYTE **stream, int player) SprayDecal(players[player].mo, s); break; + case DEM_MDK: + s = ReadString(stream); + cht_DoMDK(&players[player], s); + break; + case DEM_PAUSE: if (gamestate == GS_LEVEL) { @@ -2666,13 +2671,12 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_NETEVENT: { - const char *ename = ReadString(stream); + s = ReadString(stream); int argn = ReadByte(stream); int arg[3] = { 0, 0, 0 }; for (int i = 0; i < 3; i++) arg[i] = ReadLong(stream); - E_Console(player, ename, arg[0], arg[1], arg[2]); - delete[] ename; + E_Console(player, s, arg[0], arg[1], arg[2]); } break; @@ -2723,7 +2727,7 @@ void Net_SkipCommand (int type, BYTE **stream) break; case DEM_NETEVENT: - skip = strlen((char *)(*stream)) + 13; + skip = strlen((char *)(*stream)) + 14; break; case DEM_SUMMON2: @@ -2747,6 +2751,7 @@ void Net_SkipCommand (int type, BYTE **stream) case DEM_SPRAY: case DEM_MORPHEX: case DEM_KILLCLASSCHEAT: + case DEM_MDK: skip = strlen ((char *)(*stream)) + 1; break; diff --git a/src/d_protocol.h b/src/d_protocol.h index 27af1dae26..f95e3fc816 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -159,7 +159,8 @@ enum EDemoCommand DEM_SETSLOTPNUM, // 67 Byte: player number, the rest is the same as DEM_SETSLOT DEM_REMOVE, // 68 DEM_FINISHGAME, // 69 - DEM_NETEVENT // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int + DEM_NETEVENT, // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int + DEM_MDK // 71 String: Damage type }; // The following are implemented by cht_DoCheat in m_cheat.cpp diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index c78ab5dde1..652385df28 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -55,6 +55,22 @@ // writes some bytes to the network data stream, and the network code // later calls us. +void cht_DoMDK(player_t *player, const char *mod) +{ + if (player->mo == NULL) + { + Printf("What do you want to kill outside of a game?\n"); + } + else if (!deathmatch) + { + // Don't allow this in deathmatch even with cheats enabled, because it's + // a very very cheap kill. + P_LineAttack(player->mo, player->mo->Angles.Yaw, PLAYERMISSILERANGE, + P_AimLineAttack(player->mo, player->mo->Angles.Yaw, PLAYERMISSILERANGE), TELEFRAG_DAMAGE, + mod, NAME_BulletPuff); + } +} + void cht_DoCheat (player_t *player, int cheat) { static const char * const BeholdPowers[9] = @@ -671,6 +687,7 @@ CCMD (mdk) if (CheckCheatmode ()) return; - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_MDK); + const char *name = argv.argc() > 1 ? argv[1] : ""; + Net_WriteByte (DEM_MDK); + Net_WriteString(name); } diff --git a/src/m_cheat.h b/src/m_cheat.h index baab5a4513..729c3bff66 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -31,6 +31,7 @@ class player_t; class PClassActor; +void cht_DoMDK(player_t *player, const char *mod); void cht_DoCheat (player_t *player, int cheat); void cht_Give (player_t *player, const char *item, int amount=1); void cht_Take (player_t *player, const char *item, int amount=1); diff --git a/src/version.h b/src/version.h index a03c6a21e8..d0910f8b40 100644 --- a/src/version.h +++ b/src/version.h @@ -57,7 +57,7 @@ const char *GetVersionString(); // Version identifier for network games. // Bump it every time you do a release unless you're certain you // didn't change anything that will affect sync. -#define NETGAMEVERSION 232 +#define NETGAMEVERSION 233 // Version stored in the ini's [LastRun] section. // Bump it if you made some configuration change that you want to From 1ff401649845990fd154007b459839b907ea4157 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 20:42:12 +0100 Subject: [PATCH 163/207] - added ACS math functions floor, ceil and round. --- src/p_acs.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 4a2ca3fd9b..baf15c1105 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4368,6 +4368,9 @@ enum EACSFunctions ACSF_GetActorFloorTexture, ACSF_GetActorFloorTerrain, ACSF_StrArg, + ACSF_Floor, + ACSF_Ceil, + ACSF_Round, // OpenGL stuff @@ -6091,6 +6094,15 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_StrArg: return -FName(FBehavior::StaticLookupString(args[0])); + case ACSF_Floor: + return args[0] & ~0xffff; + + case ACSF_Ceil: + return (args[0] & ~0xffff) + 0x10000; + + case ACSF_Round: + return (args[0] + 32768) & ~0xffff; + default: break; } From d5d383ee93326c160a3a3f0d7454b5247f936375 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 21:31:59 +0100 Subject: [PATCH 164/207] - added Floor_Stop and Ceiling_Stop action specials. --- src/actionspecials.h | 2 ++ src/p_ceiling.cpp | 15 +++++++++++++++ src/p_floor.cpp | 15 +++++++++++++++ src/p_lnspec.cpp | 16 ++++++++++++++++ src/p_spec.h | 2 ++ 5 files changed, 50 insertions(+) diff --git a/src/actionspecials.h b/src/actionspecials.h index 233bb8958e..173a07b2d3 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -260,5 +260,7 @@ DEFINE_SPECIAL(Stairs_BuildUpDoomSync, 271, 4, 4, 4) DEFINE_SPECIAL(Stairs_BuildDownDoomSync, 272, 4, 4, 4) DEFINE_SPECIAL(Stairs_BuildUpDoomCrush, 273, 5, 5, 5) DEFINE_SPECIAL(Door_AnimatedClose, 274, 4, 4, 4) +DEFINE_SPECIAL(Floor_Stop, 275, 1, 1, 1) +DEFINE_SPECIAL(Ceiling_Stop, 276, 1, 1, 1) #undef DEFINE_SPECIAL diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 7bf1f9099e..b978fd0d32 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -582,3 +582,18 @@ bool EV_CeilingCrushStop (int tag, bool remove) return rtn; } + +bool EV_StopCeiling(int tag) +{ + FSectorTagIterator it(tag); + while (int sec = it.Next()) + { + if (level.sectors[sec].ceilingdata) + { + SN_StopSequence(&level.sectors[sec], CHAN_CEILING); + level.sectors[sec].ceilingdata->Destroy(); + level.sectors[sec].ceilingdata = nullptr; + } + } + return true; +} diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 2fd205a9d3..1bd0c53fce 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -561,6 +561,21 @@ bool EV_FloorCrushStop (int tag) return true; } +// same as above but stops any floor mover that was active on the given sector. +bool EV_StopFloor(int tag) +{ + FSectorTagIterator it(tag); + while (int sec = it.Next()) + { + if (level.sectors[sec].floordata) + { + SN_StopSequence(&level.sectors[sec], CHAN_FLOOR); + level.sectors[sec].floordata->Destroy(); + level.sectors[sec].floordata = nullptr; + } + } + return true; +} //========================================================================== // // BUILD A STAIRCASE! diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index ee70dcee5d..ff72b3baa3 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -563,6 +563,13 @@ FUNC(LS_Generic_Floor) } +FUNC(LS_Floor_Stop) +// Floor_Stop (tag) +{ + return EV_StopFloor(arg0); +} + + FUNC(LS_Stairs_BuildDown) // Stair_BuildDown (tag, speed, height, delay, reset) { @@ -860,6 +867,13 @@ FUNC(LS_Ceiling_LowerByTexture) return EV_DoCeiling (DCeiling::ceilLowerByTexture, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg4)); } +FUNC(LS_Ceiling_Stop) +// Ceiling_Stop (tag) +{ + return EV_StopCeiling(arg0); +} + + FUNC(LS_Generic_Ceiling) // Generic_Ceiling (tag, speed, height, target, change/model/direct/crush) { @@ -3614,6 +3628,8 @@ static lnSpecFunc LineSpecials[] = /* 272 */ LS_Stairs_BuildDownDoomSync, /* 273 */ LS_Stairs_BuildUpDoomCrush, /* 274 */ LS_Door_AnimatedClose, + /* 275 */ LS_Floor_Stop, + /* 276 */ LS_Ceiling_Stop, }; diff --git a/src/p_spec.h b/src/p_spec.h index b00e5cacf9..930ae51434 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -451,6 +451,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom); bool EV_CeilingCrushStop (int tag, bool remove); +bool EV_StopCeiling(int tag); void P_ActivateInStasisCeiling (int tag); @@ -564,6 +565,7 @@ bool EV_DoFloor(DFloor::EFloor floortype, line_t *line, int tag, double speed, double height, int crush, int change, bool hexencrush, bool hereticlower = false); bool EV_FloorCrushStop (int tag); +bool EV_StopFloor(int tag); bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed); class DElevator : public DMover From 3700dea3361361999d6b4102a0551faa42783c53 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 22:05:20 +0100 Subject: [PATCH 165/207] Revert "- the UDMF health key for actors was not correctly implemented. This addresses the problem by adding a second one and documenting 'Health' as implemented." This reverts commit e4e023e59a516aa8d74b7db02b27dbe6c45fa542. (This was nonsense.) --- specs/udmf_zdoom.txt | 4 ++-- src/dobjtype.cpp | 14 ++++++++++++-- src/dobjtype.h | 5 ++++- src/namedef.h | 1 - src/p_udmf.cpp | 16 ---------------- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 553c753603..f4af55f2df 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -263,8 +263,8 @@ Note: All fields default to false unless mentioned otherwise. gravity = ; // Set per-actor gravity. Positive values are multiplied with the class's property, // negative values are used as their absolute. Default = 1.0. - health = ; // Set per-actor health as an absolute value. Default = actor default. - healthfactor = ; // Set per-actor health as a factor to the original. Default = 1. + health = ; // Set per-actor health. Positive values are multiplied with the class's property, + // negative values are used as their absolute. Default = 1. renderstyle = ; // Set per-actor render style, overriding the class default. Possible values can be "normal", // "none", "add" or "additive", "subtract" or "subtractive", "stencil", "translucentstencil", diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 75193b868b..97d154a3b8 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3160,7 +3160,6 @@ void PClass::InitializeDefaults() optr->ObjNext = nullptr; optr->SetClass(this); - // Copy the defaults from the parent but leave the DObject part alone because it contains important data. if (ParentClass->Defaults != nullptr) { @@ -3174,6 +3173,13 @@ void PClass::InitializeDefaults() { memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject)); } + + if (MetaSize != 0) + { + Meta = (BYTE*)ClassDataAllocator.Alloc(MetaSize); + memset(Meta, 0, MetaSize); + if (ParentClass->MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + } } if (bRuntimeClass) @@ -3183,10 +3189,14 @@ void PClass::InitializeDefaults() if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); for (const PField *field : Fields) { - if (!(field->Flags & VARF_Native)) + if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) { field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); } + if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); + } } } } diff --git a/src/dobjtype.h b/src/dobjtype.h index 0151e6c119..24951c9d89 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -560,8 +560,9 @@ class PClass : public PNativeStruct protected: // We unravel _WITH_META here just as we did for PType. TArray SpecialInits; + TArray MetaInits; void Derive(PClass *newclass, FName name); - void InitializeSpecials(void *addr, void *defaults) const; + void InitializeSpecials(void *addr, void *defaults, TArray* PClass::*Inits); void SetSuper(); public: void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; @@ -582,6 +583,8 @@ public: const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default const size_t *ArrayPointers; // dynamic arrays containing object pointers. BYTE *Defaults; + BYTE *Meta; // Per-class static script data + unsigned MetaSize; bool bRuntimeClass; // class was defined at run-time, not compile-time bool bExported; // This type has been declared in a script bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility diff --git a/src/namedef.h b/src/namedef.h index 28de568183..bb42fc76df 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -46,7 +46,6 @@ xx(Shadow) xx(Subtract) xx(Subtractive) xx(FillColor) -xx(HealthFactor) // Healingradius types xx(Mana) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index b9300f6543..27293b9188 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -515,7 +515,6 @@ public: FString arg0str, arg1str; memset(th, 0, sizeof(*th)); - double healthfactor = 1; th->Gravity = 1; th->RenderStyle = STYLE_Count; th->Alpha = -1; @@ -739,52 +738,38 @@ public: break; case NAME_Alpha: - CHECK_N(Zd | Zdt) th->Alpha = CheckFloat(key); break; case NAME_FillColor: - CHECK_N(Zd | Zdt) th->fillcolor = CheckInt(key); break; case NAME_Health: - CHECK_N(Zd | Zdt) th->health = CheckInt(key); break; - case NAME_HealthFactor: - CHECK_N(Zd | Zdt) - healthfactor = CheckFloat(key); - break; - case NAME_Score: - CHECK_N(Zd | Zdt) th->score = CheckInt(key); break; case NAME_Pitch: - CHECK_N(Zd | Zdt) th->pitch = (short)CheckInt(key); break; case NAME_Roll: - CHECK_N(Zd | Zdt) th->roll = (short)CheckInt(key); break; case NAME_ScaleX: - CHECK_N(Zd | Zdt) th->Scale.X = CheckFloat(key); break; case NAME_ScaleY: - CHECK_N(Zd | Zdt) th->Scale.Y = CheckFloat(key); break; case NAME_Scale: - CHECK_N(Zd | Zdt) th->Scale.X = th->Scale.Y = CheckFloat(key); break; @@ -808,7 +793,6 @@ public: { th->args[1] = -FName(arg1str); } - th->health = int(th->health * healthfactor); // Thing specials are only valid in namespaces with Hexen-type specials // and in ZDoomTranslated - which will use the translator on them. if (namespc == NAME_ZDoomTranslated) From f343d36ea941829b68c239eb91d0f68c4e7a3b38 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Feb 2017 23:28:19 +0100 Subject: [PATCH 166/207] - implemented the basics of a working metadata system. This will store class meta properties in a separate memory block so that it won't have to muck around with PClass - which made the implementation from the scripting branch relatively useless because extending the data wasn't particularly easy and also not well implemented. This can now be handled just like the defaults. --- src/dobjtype.cpp | 105 ++++++++++++++++++---- src/dobjtype.h | 14 +-- src/intermission/intermission.h | 6 +- src/menu/menu.cpp | 2 +- src/scripting/backend/codegen.cpp | 8 +- src/scripting/decorate/thingdef_parse.cpp | 9 +- src/scripting/vm/vmexec.h | 8 +- src/scripting/vm/vmops.h | 3 +- src/scripting/zscript/zcc_compile.cpp | 14 +-- 9 files changed, 128 insertions(+), 41 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 75193b868b..dcb93599dc 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2910,6 +2910,11 @@ PClass::~PClass() M_Free(Defaults); Defaults = nullptr; } + if (Meta != nullptr) + { + M_Free(Meta); + Meta = nullptr; + } } //========================================================================== @@ -3047,7 +3052,7 @@ PClass *PClass::FindClass (FName zaname) // //========================================================================== -DObject *PClass::CreateNew() const +DObject *PClass::CreateNew() { BYTE *mem = (BYTE *)M_Malloc (Size); assert (mem != nullptr); @@ -3064,7 +3069,7 @@ DObject *PClass::CreateNew() const } ConstructNative (mem); ((DObject *)mem)->SetClass (const_cast(this)); - InitializeSpecials(mem, Defaults); + InitializeSpecials(mem, Defaults, &PClass::SpecialInits); return (DObject *)mem; } @@ -3076,7 +3081,7 @@ DObject *PClass::CreateNew() const // //========================================================================== -void PClass::InitializeSpecials(void *addr, void *defaults) const +void PClass::InitializeSpecials(void *addr, void *defaults, TArray PClass::*Inits) { // Once we reach a native class, we can stop going up the family tree, // since native classes handle initialization natively. @@ -3085,8 +3090,8 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const return; } assert(ParentClass != nullptr); - ParentClass->InitializeSpecials(addr, defaults); - for (auto tao : SpecialInits) + ParentClass->InitializeSpecials(addr, defaults, Inits); + for (auto tao : (this->*Inits)) { tao.first->InitializeValue((char*)addr + tao.second, defaults == nullptr? nullptr : ((char*)defaults) + tao.second); } @@ -3101,7 +3106,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const // //========================================================================== -void PClass::DestroySpecials(void *addr) const +void PClass::DestroySpecials(void *addr) { // Once we reach a native class, we can stop going up the family tree, // since native classes handle deinitialization natively. @@ -3160,7 +3165,6 @@ void PClass::InitializeDefaults() optr->ObjNext = nullptr; optr->SetClass(this); - // Copy the defaults from the parent but leave the DObject part alone because it contains important data. if (ParentClass->Defaults != nullptr) { @@ -3174,19 +3178,31 @@ void PClass::InitializeDefaults() { memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject)); } + + if (MetaSize != 0) + { + Meta = (BYTE*)M_Malloc(MetaSize); + memset(Meta, 0, MetaSize); + if (ParentClass->MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + } } if (bRuntimeClass) { // Copy parent values from the parent defaults. assert(ParentClass != nullptr); - if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); + if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); + if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); for (const PField *field : Fields) { - if (!(field->Flags & VARF_Native)) + if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) { field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); } + if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); + } } } } @@ -3264,6 +3280,39 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) return type; } +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new metadata field to the end of a struct. Returns either the new field +// or nullptr if a symbol by that name already exists. +// +//========================================================================== + +PField *PClass::AddMetaField(FName name, PType *type, DWORD flags) +{ + PField *field = new PField(name, type, flags); + + // The new field is added to the end of this struct, alignment permitting. + field->Offset = (MetaSize + (type->Align - 1)) & ~(type->Align - 1); + + // Enlarge this struct to enclose the new field. + MetaSize = unsigned(field->Offset + type->Size); + + // This struct's alignment is the same as the largest alignment of any of + // its fields. + Align = MAX(Align, type->Align); + + if (Symbols.AddSymbol(field) == nullptr) + { // name is already in use + field->Destroy(); + return nullptr; + } + Fields.Push(field); + + return field; +} + //========================================================================== // // PClass :: AddField @@ -3272,18 +3321,36 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) PField *PClass::AddField(FName name, PType *type, DWORD flags) { - unsigned oldsize = Size; - PField *field = Super::AddField(name, type, flags); - - // Only initialize the defaults if they have already been created. - // For ZScript this is not the case, it will first define all fields before - // setting up any defaults for any class. - if (field != nullptr && !(flags & VARF_Native) && Defaults != nullptr) + if (!(flags & VARF_Meta)) { - Defaults = (BYTE *)M_Realloc(Defaults, Size); - memset(Defaults + oldsize, 0, Size - oldsize); + unsigned oldsize = Size; + PField *field = Super::AddField(name, type, flags); + + // Only initialize the defaults if they have already been created. + // For ZScript this is not the case, it will first define all fields before + // setting up any defaults for any class. + if (field != nullptr && !(flags & VARF_Native) && Defaults != nullptr) + { + Defaults = (BYTE *)M_Realloc(Defaults, Size); + memset(Defaults + oldsize, 0, Size - oldsize); + } + return field; + } + else + { + unsigned oldsize = MetaSize; + PField *field = AddMetaField(name, type, flags); + + // Only initialize the defaults if they have already been created. + // For ZScript this is not the case, it will first define all fields before + // setting up any defaults for any class. + if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) + { + Meta = (BYTE *)M_Realloc(Meta, MetaSize); + memset(Meta + oldsize, 0, MetaSize - oldsize); + } + return field; } - return field; } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index 0151e6c119..c88b00930b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -557,12 +557,13 @@ enum class PClass : public PNativeStruct { DECLARE_CLASS(PClass, PNativeStruct); -protected: // We unravel _WITH_META here just as we did for PType. - TArray SpecialInits; +protected: + TArray MetaInits; void Derive(PClass *newclass, FName name); - void InitializeSpecials(void *addr, void *defaults) const; + void InitializeSpecials(void *addr, void *defaults, TArray PClass::*Inits); void SetSuper(); + PField *AddMetaField(FName name, PType *type, DWORD flags); public: void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; void WriteAllFields(FSerializer &ar, const void *addr) const; @@ -577,11 +578,14 @@ public: static void StaticBootstrap(); // Per-class information ------------------------------------- + TArray SpecialInits; PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default const size_t *ArrayPointers; // dynamic arrays containing object pointers. BYTE *Defaults; + BYTE *Meta; // Per-class static script data + unsigned MetaSize; bool bRuntimeClass; // class was defined at run-time, not compile-time bool bExported; // This type has been declared in a script bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility @@ -593,13 +597,13 @@ public: PClass(); ~PClass(); void InsertIntoHash(); - DObject *CreateNew() const; + DObject *CreateNew(); PClass *CreateDerivedClass(FName name, unsigned int size); PField *AddField(FName name, PType *type, DWORD flags=0) override; void InitializeActorInfo(); void BuildFlatPointers(); void BuildArrayPointers(); - void DestroySpecials(void *addr) const; + void DestroySpecials(void *addr); const PClass *NativeClass() const; // Returns true if this type is an ancestor of (or same as) the passed type. diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index cdc100d888..f0b423150c 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -58,15 +58,15 @@ enum EScrollDir }; // actions that don't create objects -#define WIPER_ID ((const PClass*)intptr_t(-1)) -#define TITLE_ID ((const PClass*)intptr_t(-2)) +#define WIPER_ID ((PClass*)intptr_t(-1)) +#define TITLE_ID ((PClass*)intptr_t(-2)) //========================================================================== struct FIntermissionAction { int mSize; - const PClass *mClass; + PClass *mClass; FString mMusic; int mMusicOrder; int mCdTrack; diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 8b0bf35e97..1c8e0b39bb 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -472,7 +472,7 @@ void M_SetMenu(FName menu, int param) } else { - const PClass *menuclass = PClass::FindClass(menu); + PClass *menuclass = PClass::FindClass(menu); if (menuclass != nullptr) { if (menuclass->IsDescendantOf("GenericMenu")) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index cc93c22156..bd18103fca 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6371,7 +6371,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) ExpEmit ob = obj->Emit(build); ob.Free(build); ExpEmit meta(build, REGT_POINTER); - build->Emit(OP_META, meta.RegNum, ob.RegNum); + build->Emit(OP_CLSS, meta.RegNum, ob.RegNum); build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return meta; @@ -6805,7 +6805,7 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) { obj.Free(build); ExpEmit meta(build, REGT_POINTER); - build->Emit(OP_META, meta.RegNum, obj.RegNum); + build->Emit(membervar->Flags & VARF_Native? OP_CLSS : OP_META, meta.RegNum, obj.RegNum); obj = meta; } @@ -8832,7 +8832,7 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build) ExpEmit op = Self->Emit(build); op.Free(build); ExpEmit to(build, REGT_POINTER); - build->Emit(OP_META, to.RegNum, op.RegNum); + build->Emit(OP_CLSS, to.RegNum, op.RegNum); return to; } @@ -8873,7 +8873,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build) if (Self->IsObject()) { ExpEmit to(build, REGT_POINTER); - build->Emit(OP_META, to.RegNum, op.RegNum); + build->Emit(OP_CLSS, to.RegNum, op.RegNum); op = to; op.Free(build); } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index e444d30a9f..bd4d781a10 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -827,7 +827,14 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul if (i > 0) sc.MustGetStringName(","); if (f->Flags & VARF_Meta) { - addr = ((char*)bag.Info) + f->Offset; + if (f->Flags & VARF_Native) + { + addr = ((char*)bag.Info) + f->Offset; + } + else + { + addr = ((char*)bag.Info->Meta) + f->Offset; + } } else { diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 3082abf802..c37e29cbf1 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -109,12 +109,18 @@ begin: reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts. NEXTOP; - OP(META): + OP(CLSS): ASSERTA(a); ASSERTO(B); reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer... reg.atag[a] = ATAG_OBJECT; NEXTOP; + OP(META): + ASSERTA(a); ASSERTO(B); + reg.a[a] = ((DObject*)reg.a[B])->GetClass()->Meta; // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer... + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(LB): ASSERTD(a); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index b058dc94b6..3d503932aa 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -23,7 +23,8 @@ xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer -xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta class address +xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta data address +xx(CLSS, clss, RPRP, NOP, 0, 0), // load a class's descriptor address // Load from memory. rA = *(rB + rkC) xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index b28226efbb..6f902648e2 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1070,11 +1070,6 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Flags & ZCC_Meta) { varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly - if (!(field->Flags & ZCC_Native)) - { - // Non-native meta data is not implemented yet and requires some groundwork in the class copy code. - Error(field, "Metadata member %s must be native", FName(field->Names->Name).GetChars()); - } } if (field->Type->ArraySize != nullptr) @@ -1692,7 +1687,14 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop if (f->Flags & VARF_Meta) { - addr = ((char*)bag.Info) + f->Offset; + if (f->Flags & VARF_Native) + { + addr = ((char*)bag.Info) + f->Offset; + } + else + { + addr = ((char*)bag.Info->Meta) + f->Offset; + } } else { From 78a66e001aa0c67e88f3fba81bdf2ce511542a3b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 00:45:16 +0100 Subject: [PATCH 167/207] - properly handle all meta properties for inventory items. --- src/dobject.h | 1 + src/dobjtype.cpp | 40 ++++++++++++++----- src/dobjtype.h | 6 +++ src/g_inventory/a_pickups.cpp | 5 +-- src/g_inventory/a_pickups.h | 1 - src/info.cpp | 1 - src/info.h | 1 - src/namedef.h | 2 + src/scripting/decorate/olddecorations.cpp | 4 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/thingdef_properties.cpp | 19 --------- src/scripting/zscript/zcc_compile.cpp | 5 +++ wadsrc/static/zscript/inventory/ammo.txt | 2 +- wadsrc/static/zscript/inventory/health.txt | 4 +- wadsrc/static/zscript/inventory/inv_misc.txt | 4 +- wadsrc/static/zscript/inventory/inventory.txt | 7 +++- wadsrc/static/zscript/inventory/weapons.txt | 2 +- 17 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 41b5e2824d..7510a4cff3 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -486,6 +486,7 @@ public: PalEntry &ColorVar(FName field); FName &NameVar(FName field); double &FloatVar(FName field); + FString &StringVar(FName field); template T*& PointerVar(FName field); // If you need to replace one object with another and want to diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index dcb93599dc..1d5cd15122 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2892,6 +2892,7 @@ PClass::PClass() bExported = false; bDecorateClass = false; ConstructNative = nullptr; + Meta = nullptr; mDescriptiveName = "Class"; PClass::AllClasses.Push(this); @@ -3085,11 +3086,10 @@ void PClass::InitializeSpecials(void *addr, void *defaults, TArrayInitializeSpecials(addr, defaults, Inits); for (auto tao : (this->*Inits)) { @@ -3179,11 +3179,27 @@ void PClass::InitializeDefaults() memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject)); } + assert(MetaSize >= ParentClass->MetaSize); if (MetaSize != 0) { Meta = (BYTE*)M_Malloc(MetaSize); - memset(Meta, 0, MetaSize); - if (ParentClass->MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + + // Copy the defaults from the parent but leave the DObject part alone because it contains important data. + if (ParentClass->Meta != nullptr) + { + memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + if (MetaSize > ParentClass->MetaSize) + { + memset(Meta + ParentClass->MetaSize, 0, MetaSize - ParentClass->MetaSize); + } + } + else + { + memset(Meta, 0, MetaSize); + } + + if (MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); + else memset(Meta, 0, MetaSize); } } @@ -3199,10 +3215,14 @@ void PClass::InitializeDefaults() { field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); } - if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) - { - field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); - } + } + } + if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); } } } @@ -3264,6 +3284,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->bRuntimeClass = true; Derive(type, name); type->Size = size; + type->MetaSize = MetaSize; if (size != TentativeClass) { type->InitializeDefaults(); @@ -3344,7 +3365,7 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags) // Only initialize the defaults if they have already been created. // For ZScript this is not the case, it will first define all fields before // setting up any defaults for any class. - if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) + if (field != nullptr && !(flags & VARF_Native)) { Meta = (BYTE *)M_Realloc(Meta, MetaSize); memset(Meta + oldsize, 0, MetaSize - oldsize); @@ -3380,6 +3401,7 @@ PClass *PClass::FindClassTentative(FName name) PClass *type = static_cast(GetClass()->CreateNew()); DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); + assert(MetaSize == 0); Derive(type, name); type->Size = TentativeClass; TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket); diff --git a/src/dobjtype.h b/src/dobjtype.h index c88b00930b..76e17b1331 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -603,6 +603,7 @@ public: void InitializeActorInfo(); void BuildFlatPointers(); void BuildArrayPointers(); + void InitMeta(); void DestroySpecials(void *addr); const PClass *NativeClass() const; @@ -742,6 +743,11 @@ inline double &DObject::FloatVar(FName field) return *(double*)ScriptVar(field, TypeFloat64); } +inline FString &DObject::StringVar(FName field) +{ + return *(FString*)ScriptVar(field, TypeString); +} + template inline T *&DObject::PointerVar(FName field) { diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 53e7d84ed7..df6679d41a 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -50,8 +50,6 @@ DEFINE_FIELD(AInventory, DropTime) DEFINE_FIELD(AInventory, SpawnPointClass) DEFINE_FIELD(AInventory, PickupFlash) DEFINE_FIELD(AInventory, PickupSound) -DEFINE_FIELD(AInventory, GiveQuest) -DEFINE_FIELD(PClassActor, PickupMsg) //=========================================================================== // @@ -115,8 +113,7 @@ void AInventory::Serialize(FSerializer &arc) ("icon", Icon, def->Icon) ("pickupsound", PickupSound, def->PickupSound) ("spawnpointclass", SpawnPointClass, def->SpawnPointClass) - ("droptime", DropTime, def->DropTime) - ("givequest", GiveQuest, def->GiveQuest); + ("droptime", DropTime, def->DropTime); } //=========================================================================== diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 817fcf1769..9258d320a5 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -87,7 +87,6 @@ public: FTextureID Icon; // Icon to show on status bar or HUD int DropTime; // Countdown after dropping PClassActor *SpawnPointClass; // For respawning like Heretic's mace - int GiveQuest; // Optionally give one of the quest items. FTextureID AltHUDIcon; DWORD ItemFlags; diff --git a/src/info.cpp b/src/info.cpp index 7cac3569d9..2bba8afb4b 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -354,7 +354,6 @@ void PClassActor::DeriveData(PClass *newclass) } // Inventory stuff - newa->PickupMsg = PickupMsg; newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass; newa->RestrictedToPlayerClass = RestrictedToPlayerClass; diff --git a/src/info.h b/src/info.h index 6d6329f88f..f0f0f6c3c6 100644 --- a/src/info.h +++ b/src/info.h @@ -321,7 +321,6 @@ public: double MissileHeight; // These are only valid for inventory items. - FString PickupMsg; TArray RestrictedToPlayerClass; TArray ForbiddenToPlayerClass; diff --git a/src/namedef.h b/src/namedef.h index 28de568183..df2841daa1 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -398,6 +398,8 @@ xx(VisibleStartPitch) xx(VisibleEndAngle) xx(VisibleEndPitch) xx(Format) +xx(PickupMsg) +xx(Respawnable) // Various actor names which are used internally xx(MapSpot) diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 50e8f9c6a8..5c5714ba3b 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -541,11 +541,11 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - bag.Info->PickupMsg = sc.String; + inv->StringVar(NAME_PickupMsg) = sc.String; } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { - inv->BoolVar("Respawnable") = true; + inv->BoolVar(NAME_Respawnable) = true; } else if (def == DEF_BreakableDecoration && sc.Compare ("SolidOnDeath")) { diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index bd4d781a10..e70059fecb 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -874,7 +874,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul else if (f->Type->IsKindOf(RUNTIME_CLASS(PString))) { sc.MustGetString(); - *(FString*)addr = sc.String; + *(FString*)addr = strbin1(sc.String); } else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer))) { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index cf70b19aee..527782382c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1831,16 +1831,6 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) defaults->PickupFlash = FindClassTentative(str, RUNTIME_CLASS(AActor)); } -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->PickupMsg = str; -} - //========================================================================== // //========================================================================== @@ -1875,15 +1865,6 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory) defaults->UseSound = str; } -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(givequest, I, Inventory) -{ - PROP_INT_PARM(i, 0); - defaults->GiveQuest = i; -} - //========================================================================== // //========================================================================== diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6f902648e2..1a9dfbe8d1 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1007,6 +1007,11 @@ void ZCCCompiler::CompileAllFields() type->Size = Classes[i]->Type()->ParentClass->Size; } } + if (Classes[i]->Type()->ParentClass) + type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize; + else + type->MetaSize = 0; + if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) { // Remove from the list if all fields got compiled. diff --git a/wadsrc/static/zscript/inventory/ammo.txt b/wadsrc/static/zscript/inventory/ammo.txt index e742e806d9..092a93846b 100644 --- a/wadsrc/static/zscript/inventory/ammo.txt +++ b/wadsrc/static/zscript/inventory/ammo.txt @@ -37,7 +37,7 @@ class Ammo : Inventory { int BackpackAmount; int BackpackMaxAmount; - /*meta*/ int DropAmount; + meta int DropAmount; property BackpackAmount: BackpackAmount; property BackpackMaxAmount: BackpackMaxAmount; diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt index 230b3575be..e2fb8eacfd 100644 --- a/wadsrc/static/zscript/inventory/health.txt +++ b/wadsrc/static/zscript/inventory/health.txt @@ -36,8 +36,8 @@ class Health : Inventory { transient int PrevHealth; - /*meta*/ int LowHealth; - /*meta*/ String LowHealthMessage; + meta int LowHealth; + meta String LowHealthMessage; property LowMessage: LowHealth, LowHealthMessage; diff --git a/wadsrc/static/zscript/inventory/inv_misc.txt b/wadsrc/static/zscript/inventory/inv_misc.txt index 441566786c..ce4bf805b4 100644 --- a/wadsrc/static/zscript/inventory/inv_misc.txt +++ b/wadsrc/static/zscript/inventory/inv_misc.txt @@ -87,8 +87,8 @@ class MapRevealer : Inventory class PuzzleItem : Inventory { - /*meta*/ int PuzzleItemNumber; - /*meta*/ String PuzzFailMessage; + meta int PuzzleItemNumber; + meta String PuzzFailMessage; property Number: PuzzleItemNumber; property FailMessage: PuzzFailMessage; diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index 06caedad73..cac9b9b8f2 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -23,8 +23,11 @@ class Inventory : Actor native native bool bPickupGood; native bool bCreateCopyMoved; native bool bInitEffectFailed; - native meta String PickupMsg; - native /*meta*/ int GiveQuest; + meta String PickupMsg; + meta int GiveQuest; + + Property PickupMessage: PickupMsg; + Property GiveQuest: GiveQuest; Default { diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index c76aaef54c..de94647265 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -33,7 +33,7 @@ class Weapon : StateProvider native native float FOVScale; native int Crosshair; // 0 to use player's crosshair native bool GivenAsMorphWeapon; - native bool bAltFire; // Set when self weapon's alternate fire is used. + native bool bAltFire; // Set when this weapon's alternate fire is used. native readonly bool bDehAmmo; Default From 4a87a598fb0926ff36d4740879af859f78a91b56 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 00:59:09 +0100 Subject: [PATCH 168/207] - do floatification of the UDMF Health property as it should have been. --- specs/udmf_zdoom.txt | 2 +- src/dobjtype.cpp | 14 ++------------ src/dobjtype.h | 5 +---- src/doomdata.h | 2 +- src/p_mobj.cpp | 10 +++++----- src/p_setup.cpp | 4 ++-- src/p_udmf.cpp | 4 ++-- 7 files changed, 14 insertions(+), 27 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index f4af55f2df..eeb3c2a560 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -263,7 +263,7 @@ Note: All fields default to false unless mentioned otherwise. gravity = ; // Set per-actor gravity. Positive values are multiplied with the class's property, // negative values are used as their absolute. Default = 1.0. - health = ; // Set per-actor health. Positive values are multiplied with the class's property, + health = ; // Set per-actor health. Positive values are multiplied with the class's property, // negative values are used as their absolute. Default = 1. renderstyle = ; // Set per-actor render style, overriding the class default. Possible values can be "normal", diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 97d154a3b8..75193b868b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3160,6 +3160,7 @@ void PClass::InitializeDefaults() optr->ObjNext = nullptr; optr->SetClass(this); + // Copy the defaults from the parent but leave the DObject part alone because it contains important data. if (ParentClass->Defaults != nullptr) { @@ -3173,13 +3174,6 @@ void PClass::InitializeDefaults() { memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject)); } - - if (MetaSize != 0) - { - Meta = (BYTE*)ClassDataAllocator.Alloc(MetaSize); - memset(Meta, 0, MetaSize); - if (ParentClass->MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize); - } } if (bRuntimeClass) @@ -3189,14 +3183,10 @@ void PClass::InitializeDefaults() if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); for (const PField *field : Fields) { - if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) + if (!(field->Flags & VARF_Native)) { field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); } - if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) - { - field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); - } } } } diff --git a/src/dobjtype.h b/src/dobjtype.h index 24951c9d89..0151e6c119 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -560,9 +560,8 @@ class PClass : public PNativeStruct protected: // We unravel _WITH_META here just as we did for PType. TArray SpecialInits; - TArray MetaInits; void Derive(PClass *newclass, FName name); - void InitializeSpecials(void *addr, void *defaults, TArray* PClass::*Inits); + void InitializeSpecials(void *addr, void *defaults) const; void SetSuper(); public: void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; @@ -583,8 +582,6 @@ public: const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default const size_t *ArrayPointers; // dynamic arrays containing object pointers. BYTE *Defaults; - BYTE *Meta; // Per-class static script data - unsigned MetaSize; bool bRuntimeClass; // class was defined at run-time, not compile-time bool bExported; // This type has been declared in a script bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility diff --git a/src/doomdata.h b/src/doomdata.h index eca7dcd4aa..39f0d184a5 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -359,7 +359,7 @@ struct FMapThing double Alpha; DWORD fillcolor; DVector2 Scale; - int health; + double Health; int score; short pitch; short roll; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 88bb1d40a9..f38ac12bb3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5930,13 +5930,13 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mobj->LevelSpawned (); } - if (mthing->health > 0) - mobj->health *= mthing->health; + if (mthing->Health > 0) + mobj->health = int(mobj->health * mthing->Health); else - mobj->health = -mthing->health; - if (mthing->health == 0) + mobj->health = -int(mthing->Health); + if (mthing->Health == 0) mobj->CallDie(NULL, NULL); - else if (mthing->health != 1) + else if (mthing->Health != 1) mobj->StartHealth = mobj->health; return mobj; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 308054a8b3..76e8b6b340 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1741,7 +1741,7 @@ void P_LoadThings (MapData * map) mti[i].ClassFilter = 0xffff; // Doom map format doesn't have class flags so spawn for all player classes mti[i].RenderStyle = STYLE_Count; mti[i].Alpha = -1; - mti[i].health = 1; + mti[i].Health = 1; mti[i].FloatbobPhase = -1; mti[i].pos.X = LittleShort(mt->x); @@ -1837,7 +1837,7 @@ void P_LoadThings2 (MapData * map) mti[i].Gravity = 1; mti[i].RenderStyle = STYLE_Count; mti[i].Alpha = -1; - mti[i].health = 1; + mti[i].Health = 1; mti[i].FloatbobPhase = -1; } delete[] mtp; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 27293b9188..4d5e00e48a 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -518,7 +518,7 @@ public: th->Gravity = 1; th->RenderStyle = STYLE_Count; th->Alpha = -1; - th->health = 1; + th->Health = 1; th->FloatbobPhase = -1; sc.MustGetToken('{'); while (!sc.CheckToken('}')) @@ -746,7 +746,7 @@ public: break; case NAME_Health: - th->health = CheckInt(key); + th->Health = CheckFloat(key); break; case NAME_Score: From a93a7e1cac9745aa8ec731e4015a3d7b71fe1da5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 01:23:12 +0100 Subject: [PATCH 169/207] - handle player meta properties. Only two really make sense, the rest is never used from scripts and may just remain where it was. --- src/d_player.h | 2 -- src/p_user.cpp | 3 --- src/scripting/thingdef_properties.cpp | 18 ----------------- src/scripting/zscript/zcc_compile.cpp | 6 ++++-- wadsrc/static/zscript/shared/player.txt | 26 ++++++++++++++----------- 5 files changed, 19 insertions(+), 36 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 2d7d439c57..43e6e53ab2 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -159,8 +159,6 @@ public: FNameNoInit Face; // Doom status bar face (when used) FNameNoInit Portrait; FNameNoInit Slot[10]; - FNameNoInit InvulMode; - FNameNoInit HealingRadiusType; double HexenArmor[5]; BYTE ColorRangeStart; // Skin color range BYTE ColorRangeEnd; diff --git a/src/p_user.cpp b/src/p_user.cpp index 5bb0e2127e..30db0a2711 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3325,13 +3325,10 @@ DEFINE_FIELD(APlayerPawn, FlechetteType) DEFINE_FIELD(APlayerPawn, DamageFade) DEFINE_FIELD(APlayerPawn, ViewBob) DEFINE_FIELD(APlayerPawn, FullHeight) - -DEFINE_FIELD(APlayerPawn, HealingRadiusType) DEFINE_FIELD(APlayerPawn, SoundClass) DEFINE_FIELD(APlayerPawn, Face) DEFINE_FIELD(APlayerPawn, Portrait) DEFINE_FIELD(APlayerPawn, Slot) -DEFINE_FIELD(APlayerPawn, InvulMode) DEFINE_FIELD(APlayerPawn, HexenArmor) DEFINE_FIELD(APlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 527782382c..09f6dcd954 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2699,24 +2699,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) bag.DropItemList = di; } -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) -{ - PROP_STRING_PARM(str, 0); - defaults->InvulMode = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) -{ - PROP_STRING_PARM(str, 0); - defaults->HealingRadiusType = str; -} - //========================================================================== // //========================================================================== diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 1a9dfbe8d1..548424cd97 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1188,8 +1188,10 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray &Proper FString qualifiedname; // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. - if (prefix == NAME_None) qualifiedname.Format("@property@%s", FName(p->NodeName).GetChars()); - else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), FName(p->NodeName).GetChars()); + FName name = FName(p->NodeName); + if (prefix == NAME_None) qualifiedname.Format("@property@%s", name.GetChars()); + else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars()); + fields.ShrinkToFit(); if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields))) { diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 8886e6744c..9b686a5513 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -8,18 +8,14 @@ class PlayerPawn : Actor native native int PlayerFlags; native Inventory InvFirst; // first inventory item displayed on inventory bar native Inventory InvSel; // selected inventory item - native meta String DisplayName; // Display name (used in menus, etc.) + native Name SoundClass; // Sound class + native Name Face; // Doom status bar face (when used) + native Name Portrait; + native Name Slot[10]; + native double HexenArmor[5]; + native uint8 ColorRangeStart; // Skin color range + native uint8 ColorRangeEnd; - native /*meta*/ Name SoundClass; // Sound class - native /*meta*/ Name Face; // Doom status bar face (when used) - native /*meta*/ Name Portrait; - native /*meta*/ Name Slot[10]; - native /*meta*/ Name InvulMode; - native /*meta*/ Name HealingRadiusType; - native /*meta*/ double HexenArmor[5]; - native /*meta*/ uint8 ColorRangeStart; // Skin color range - native /*meta*/ uint8 ColorRangeEnd; - // [GRB] Player class properties native double JumpZ; native double GruntSpeed; @@ -37,6 +33,14 @@ class PlayerPawn : Actor native native color DamageFade; // [CW] Fades for when you are being damaged. native double ViewBob; // [SP] ViewBob Multiplier native double FullHeight; + + native meta String DisplayName; // Display name (used in menus, etc.) + meta Name HealingRadiusType; + meta Name InvulMode; + + Property prefix: Player; + Property HealRadiusType: HealingradiusType; + Property InvulnerabilityMode: InvulMode; Default { From b6a1fe7fc6ac50409cc127c026e39387a5955f94 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 10:51:32 +0100 Subject: [PATCH 170/207] - scriptified the basic attack functions, its properties and the explosion properties to test the new metadata system. --- src/dobject.cpp | 14 +++- src/info.cpp | 13 ---- src/info.h | 9 --- src/namedef.h | 3 + src/p_actionfunctions.cpp | 87 +-------------------- src/p_mobj.cpp | 7 -- src/scripting/decorate/olddecorations.cpp | 6 +- src/scripting/thingdef_properties.cpp | 69 ----------------- src/scripting/zscript/zcc_parser.cpp | 1 + wadsrc/static/zscript/actor.txt | 92 ++++++++++++++++++++--- 10 files changed, 101 insertions(+), 200 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 747c1f9bfa..b8097f5498 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -623,12 +623,20 @@ DEFINE_ACTION_FUNCTION(DObject, MSTime) void *DObject::ScriptVar(FName field, PType *type) { - auto sym = dyn_cast(GetClass()->Symbols.FindSymbol(field, true)); + auto cls = GetClass(); + auto sym = dyn_cast(cls->Symbols.FindSymbol(field, true)); if (sym && (sym->Type == type || type == nullptr)) { - return (((char*)this) + sym->Offset); + if (!(sym->Flags & VARF_Meta)) + { + return (((char*)this) + sym->Offset); + } + else + { + return (cls->Meta + sym->Offset); + } } // This is only for internal use so I_Error is fine. - I_Error("Variable %s not found in %s\n", field.GetChars(), GetClass()->TypeName.GetChars()); + I_Error("Variable %s not found in %s\n", field.GetChars(), cls->TypeName.GetChars()); return nullptr; } diff --git a/src/info.cpp b/src/info.cpp index 2bba8afb4b..0db6c7fbc5 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -262,11 +262,6 @@ PClassActor::PClassActor() CameraHeight = INT_MIN; DropItems = NULL; - - DontHurtShooter = false; - ExplosionRadius = -1; - MeleeDamage = 0; - // Record this in the master list. AllActorClasses.Push(this); } @@ -330,14 +325,6 @@ void PClassActor::DeriveData(PClass *newclass) newa->DropItems = DropItems; - newa->DontHurtShooter = DontHurtShooter; - newa->ExplosionRadius = ExplosionRadius; - newa->ExplosionDamage = ExplosionDamage; - newa->MeleeDamage = MeleeDamage; - newa->MeleeSound = MeleeSound; - newa->MissileName = MissileName; - newa->MissileHeight = MissileHeight; - newa->VisibleToPlayerClass = VisibleToPlayerClass; if (DamageFactors != NULL) diff --git a/src/info.h b/src/info.h index f0f0f6c3c6..9e684f462b 100644 --- a/src/info.h +++ b/src/info.h @@ -311,15 +311,6 @@ public: FString SourceLumpName; FIntCVar *distancecheck; - // Old Decorate compatibility stuff - bool DontHurtShooter; - int ExplosionRadius; - int ExplosionDamage; - int MeleeDamage; - FSoundID MeleeSound; - FName MissileName; - double MissileHeight; - // These are only valid for inventory items. TArray RestrictedToPlayerClass; TArray ForbiddenToPlayerClass; diff --git a/src/namedef.h b/src/namedef.h index df2841daa1..196c41fd05 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -400,6 +400,9 @@ xx(VisibleEndPitch) xx(Format) xx(PickupMsg) xx(Respawnable) +xx(ExplosionDamage) +xx(ExplosionRadius) +xx(DontHurtShooter) // Various actor names which are used internally xx(MapSpot) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 54a577e5b9..1f6e6df7f8 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -86,7 +86,6 @@ AActor *SingleActorFromTID(int tid, AActor *defactor); static FRandom pr_camissile ("CustomActorfire"); -static FRandom pr_camelee ("CustomMelee"); static FRandom pr_cabullet ("CustomBullet"); static FRandom pr_cajump ("CustomJump"); static FRandom pr_cwbullet ("CustomWpBullet"); @@ -924,86 +923,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_CopyFriendliness) return 0; } -//========================================================================== -// -// Customizable attack functions which use actor parameters. -// -//========================================================================== -static void DoAttack (AActor *self, bool domelee, bool domissile, - int MeleeDamage, FSoundID MeleeSound, PClassActor *MissileType,double MissileHeight) -{ - if (self->target == NULL) return; - - A_FaceTarget (self); - if (domelee && MeleeDamage>0 && self->CheckMeleeRange ()) - { - int damage = pr_camelee.HitDice(MeleeDamage); - if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - } - else if (domissile && MissileType != NULL) - { - // This seemingly senseless code is needed for proper aiming. - double add = MissileHeight + self->GetBobOffset() - 32; - self->AddZ(add); - AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32.), self, self->target, MissileType, false); - self->AddZ(-add); - - if (missile) - { - // automatic handling of seeker missiles - if (missile->flags2&MF2_SEEKERMISSILE) - { - missile->tracer=self->target; - } - P_CheckMissileSpawn(missile, self->radius); - } - } -} - -DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - int MeleeDamage = self->GetClass()->MeleeDamage; - FSoundID MeleeSound = self->GetClass()->MeleeSound; - DoAttack(self, true, false, MeleeDamage, MeleeSound, NULL, 0); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); - DoAttack(self, false, true, 0, 0, MissileType, self->GetClass()->MissileHeight); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - int MeleeDamage = self->GetClass()->MeleeDamage; - FSoundID MeleeSound = self->GetClass()->MeleeSound; - PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); - DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, self->GetClass()->MissileHeight); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_BasicAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (melee_damage); - PARAM_SOUND (melee_sound); - PARAM_CLASS (missile_type, AActor); - PARAM_FLOAT (missile_height); - - if (missile_type != NULL) - { - DoAttack(self, true, true, melee_damage, melee_sound, missile_type, missile_height); - } - return 0; -} - //========================================================================== // // Custom sound functions. @@ -1261,9 +1180,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode) if (damage < 0) // get parameters from metadata { - damage = self->GetClass()->ExplosionDamage; - distance = self->GetClass()->ExplosionRadius; - flags = !self->GetClass()->DontHurtShooter; + damage = self->IntVar(NAME_ExplosionDamage); + distance = self->IntVar(NAME_ExplosionRadius); + flags = !self->BoolVar(NAME_DontHurtShooter); alert = false; } if (distance <= 0) distance = damage; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 88bb1d40a9..40fa7e0c95 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -328,13 +328,6 @@ DEFINE_FIELD(PClassActor, HowlSound) DEFINE_FIELD(PClassActor, BloodType) DEFINE_FIELD(PClassActor, BloodType2) DEFINE_FIELD(PClassActor, BloodType3) -DEFINE_FIELD(PClassActor, DontHurtShooter) -DEFINE_FIELD(PClassActor, ExplosionRadius) -DEFINE_FIELD(PClassActor, ExplosionDamage) -DEFINE_FIELD(PClassActor, MeleeDamage) -DEFINE_FIELD(PClassActor, MeleeSound) -DEFINE_FIELD(PClassActor, MissileName) -DEFINE_FIELD(PClassActor, MissileHeight) //========================================================================== // diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 5c5714ba3b..8d220ec707 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -445,18 +445,18 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius")) { sc.MustGetNumber (); - bag.Info->ExplosionRadius = sc.Number; + defaults->IntVar(NAME_ExplosionRadius) = sc.Number; extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage")) { sc.MustGetNumber (); - bag.Info->ExplosionDamage = sc.Number; + defaults->IntVar(NAME_ExplosionDamage) = sc.Number; extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter")) { - bag.Info->DontHurtShooter = true; + defaults->BoolVar(NAME_DontHurtShooter) = true; } else if (def == DEF_Projectile && sc.Compare ("Damage")) { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 09f6dcd954..0e34e2da48 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1001,35 +1001,6 @@ DEFINE_PROPERTY(hitobituary, S, Actor) static_cast(info)->HitObituary = str; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(donthurtshooter, 0, Actor) -{ - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->DontHurtShooter = true; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(explosionradius, I, Actor) -{ - PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->ExplosionRadius = id; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(explosiondamage, I, Actor) -{ - PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->ExplosionDamage = id; -} - //========================================================================== // //========================================================================== @@ -1068,16 +1039,6 @@ DEFINE_PROPERTY(meleethreshold, F, Actor) defaults->meleethreshold = id; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(meleedamage, I, Actor) -{ - PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->MeleeDamage = id; -} - //========================================================================== // //========================================================================== @@ -1087,36 +1048,6 @@ DEFINE_PROPERTY(meleerange, F, Actor) defaults->meleerange = id; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(meleesound, S, Actor) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->MeleeSound = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(missiletype, S, Actor) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->MissileName = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(missileheight, F, Actor) -{ - PROP_DOUBLE_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->MissileHeight = id; -} - //========================================================================== // //========================================================================== diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 501a7b2ea8..439b495b4c 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -281,6 +281,7 @@ static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCPar tokentype = ZCC_FLOATCONST; break; + case TK_None: // 'NONE' is a token for SBARINFO but not here. case TK_Identifier: value.Int = FName(sc.String); tokentype = ZCC_IDENTIFIER; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 99c23c7bfe..6a12e00f8f 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -189,7 +189,7 @@ class Actor : Thinker native native State MissileState; native voidptr /*DecalBase*/ DecalGenerator; native uint8 fountaincolor; - + native meta String Obituary; // Player was killed by this actor native meta String HitObituary; // Player was killed by this actor in melee native meta double DeathHeight; // Height on normal death @@ -204,15 +204,24 @@ class Actor : Thinker native native meta Name BloodType; // Blood replacement type native meta Name BloodType2; // Bloopsplatter replacement type native meta Name BloodType3; // AxeBlood replacement type - native meta bool DontHurtShooter; - native meta int ExplosionRadius; - native meta int ExplosionDamage; - native meta int MeleeDamage; - native meta Sound MeleeSound; - native meta Name MissileName; - native meta double MissileHeight; + meta bool DontHurtShooter; + meta int ExplosionRadius; + meta int ExplosionDamage; + meta int MeleeDamage; + meta Sound MeleeSound; + meta double MissileHeight; + meta Name MissileName; + Property prefix: none; + Property MeleeDamage: MeleeDamage; + Property MeleeSound: MeleeSound; + Property MissileHeight: MissileHeight; + Property MissileType: MissileName; + Property DontHurtShooter: DontHurtShooter; + Property ExplosionRadius: ExplosionRadius; + Property ExplosionDamage: ExplosionDamage; + // need some definition work first //FRenderStyle RenderStyle; //int ConversationRoot; // THe root of the current dialogue @@ -271,6 +280,7 @@ class Actor : Thinker native DefThreshold 100; BloodType "Blood", "BloodSplatter", "AxeBlood"; ExplosionDamage 128; + ExplosionRadius -1; // i.e. use ExplosionDamage value MissileHeight 32; SpriteAngle 0; SpriteRotation 0; @@ -724,6 +734,68 @@ class Actor : Thinker native // Meh, MBF redundant functions. Only for DeHackEd support. native bool A_LineEffect(int boomspecial = 0, int tag = 0); // End of MBF redundant functions. + + + //========================================================================== + // + // old customizable attack functions which use actor parameters. + // + //========================================================================== + + private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class MissileType,double MissileHeight) + { + if (target == NULL) return; + + A_FaceTarget (); + if (domelee && MeleeDamage>0 && CheckMeleeRange ()) + { + int damage = random[CustomMelee](1, 8) * MeleeDamage; + if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON); + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + else if (domissile && MissileType != NULL) + { + // This seemingly senseless code is needed for proper aiming. + double add = MissileHeight + GetBobOffset() - 32; + AddZ(add); + Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), target, MissileType, false); + AddZ(-add); + + if (missile) + { + // automatic handling of seeker missiles + if (missile.bSeekerMissile) + { + missile.tracer = target; + } + missile.CheckMissileSpawn(radius); + } + } + } + + deprecated void A_MeleeAttack() + { + DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0); + } + + deprecated void A_MissileAttack() + { + Class MissileType = MissileName; + DoAttack(false, true, 0, 0, MissileType, MissileHeight); + } + + deprecated void A_ComboAttack() + { + Class MissileType = MissileName; + DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight); + } + + void A_BasicAttack(int melee_damage, sound melee_sound, class missile_type, double missile_height) + { + DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height); + } + native void A_MonsterRail(); native void A_Pain(); @@ -753,9 +825,6 @@ class Actor : Thinker native native void A_Wander(int flags = 0); native void A_Look2(); - deprecated native void A_MissileAttack(); - deprecated native void A_MeleeAttack(); - deprecated native void A_ComboAttack(); deprecated native void A_BulletAttack(); native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class pufftype = "BulletPuff"); native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false); @@ -793,7 +862,6 @@ class Actor : Thinker native native void A_RaiseMaster(int flags = 0); native void A_RaiseChildren(int flags = 0); native void A_RaiseSiblings(int flags = 0); - deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, double missileheight); action native bool, Actor A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); native void A_Weave(int xspeed, int yspeed, double xdist, double ydist); native bool A_Morph(class type, int duration = 0, int flags = 0, class enter_flash = null, class exit_flash = null); From 1311f08f4714138fb1bfa837a91672760f77d944 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 12:11:25 +0100 Subject: [PATCH 171/207] - scriptified Actor.GetBloodType as a virtual function to allow mods more flexibility here. - made CameraHeight a modifiable actor property - it was readonly before. - allow accessing the type constants from ZScript, this required quite a bit of explicit coding because the type system has no capabilities to search for basic types by name. --- src/actor.h | 30 +--------- src/dobjtype.cpp | 4 -- src/info.cpp | 5 -- src/info.h | 4 -- src/p_mobj.cpp | 21 +++++-- src/scripting/backend/codegen.cpp | 80 ++++++++++++++++++++++++--- src/scripting/thingdef_properties.cpp | 34 +----------- wadsrc/static/zscript/actor.txt | 43 +++++++++++--- 8 files changed, 129 insertions(+), 92 deletions(-) diff --git a/src/actor.h b/src/actor.h index 2ed0047405..6e64b6033e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -817,32 +817,7 @@ public: void SetAngle(DAngle ang, bool interpolate); void SetRoll(DAngle roll, bool interpolate); - PClassActor *GetBloodType(int type = 0) const - { - PClassActor *bloodcls; - if (type == 0) - { - bloodcls = PClass::FindActor(GetClass()->BloodType); - } - else if (type == 1) - { - bloodcls = PClass::FindActor(GetClass()->BloodType2); - } - else if (type == 2) - { - bloodcls = PClass::FindActor(GetClass()->BloodType3); - } - else - { - return NULL; - } - - if (bloodcls != NULL) - { - bloodcls = bloodcls->GetReplacement(); - } - return bloodcls; - } + PClassActor *GetBloodType(int type = 0) const; double Distance2DSquared(AActor *other, bool absolute = false) { @@ -1048,7 +1023,8 @@ public: double renderradius; double projectilepassheight; // height for clipping projectile movement against this actor - + double CameraHeight; // Height of camera when used as such + SDWORD tics; // state tic counter FState *state; //VMFunction *Damage; // For missiles and monster railgun diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 1d5cd15122..f86797dfd2 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -722,10 +722,6 @@ PBool::PBool() { mDescriptiveName = "Bool"; MemberOnly = false; - // Override the default max set by PInt's constructor - PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); - assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); - maxsym->Value = 1; } /* PFloat *****************************************************************/ diff --git a/src/info.cpp b/src/info.cpp index 0db6c7fbc5..6f9b95f36d 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -259,7 +259,6 @@ PClassActor::PClassActor() RDFactor = 1.; SelfDamageFactor = 1.; StealthAlpha = 0.; - CameraHeight = INT_MIN; DropItems = NULL; // Record this in the master list. @@ -316,11 +315,7 @@ void PClassActor::DeriveData(PClass *newclass) newa->RDFactor = RDFactor; newa->SelfDamageFactor = SelfDamageFactor; newa->StealthAlpha = StealthAlpha; - newa->CameraHeight = CameraHeight; newa->HowlSound = HowlSound; - newa->BloodType = BloodType; - newa->BloodType2 = BloodType2; - newa->BloodType3 = BloodType3; newa->distancecheck = distancecheck; newa->DropItems = DropItems; diff --git a/src/info.h b/src/info.h index 9e684f462b..fd89145465 100644 --- a/src/info.h +++ b/src/info.h @@ -300,12 +300,8 @@ public: double FastSpeed; // speed in fast mode double RDFactor; // Radius damage factor double SelfDamageFactor; - double CameraHeight; // Height of camera when used as such double StealthAlpha; // Minmum alpha for MF_STEALTH. FSoundID HowlSound; // Sound being played when electrocuted or poisoned - FName BloodType; // Blood replacement type - FName BloodType2; // Bloopsplatter replacement type - FName BloodType3; // AxeBlood replacement type FDropItem *DropItems; FString SourceLumpName; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 40fa7e0c95..d95bae5b2f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -311,6 +311,7 @@ DEFINE_FIELD(AActor, ConversationRoot) DEFINE_FIELD(AActor, Conversation) DEFINE_FIELD(AActor, DecalGenerator) DEFINE_FIELD(AActor, fountaincolor) +DEFINE_FIELD(AActor, CameraHeight) DEFINE_FIELD(PClassActor, Obituary) DEFINE_FIELD(PClassActor, HitObituary) @@ -323,11 +324,7 @@ DEFINE_FIELD(PClassActor, FastSpeed) DEFINE_FIELD(PClassActor, RDFactor) DEFINE_FIELD(PClassActor, SelfDamageFactor) DEFINE_FIELD(PClassActor, StealthAlpha) -DEFINE_FIELD(PClassActor, CameraHeight) DEFINE_FIELD(PClassActor, HowlSound) -DEFINE_FIELD(PClassActor, BloodType) -DEFINE_FIELD(PClassActor, BloodType2) -DEFINE_FIELD(PClassActor, BloodType3) //========================================================================== // @@ -488,6 +485,7 @@ void AActor::Serialize(FSerializer &arc) A("spriteangle", SpriteAngle) A("spriterotation", SpriteRotation) ("alternative", alternative) + A("cameraheight", CameraHeight) A("tag", Tag) A("visiblestartangle",VisibleStartAngle) A("visibleendangle",VisibleEndAngle) @@ -3816,6 +3814,19 @@ void AActor::SetRoll(DAngle r, bool interpolate) } } +PClassActor *AActor::GetBloodType(int type) const +{ + IFVIRTUAL(AActor, GetBloodType) + { + VMValue params[] = { (DObject*)this, type }; + PClassActor *res; + VMReturn ret((void**)&res); + GlobalVMStack.Call(func, params, countof(params), &ret, 1); + return res; + } + return nullptr; +} + DVector3 AActor::GetPortalTransition(double byoffset, sector_t **pSec) { @@ -7593,7 +7604,7 @@ int AActor::GetGibHealth() const double AActor::GetCameraHeight() const { - return GetClass()->CameraHeight == INT_MIN ? Height / 2 : GetClass()->CameraHeight; + return CameraHeight == INT_MIN ? Height / 2 : CameraHeight; } DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index bd18103fca..893a50eed9 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6088,19 +6088,85 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) if (Object->ExprType == EFX_Identifier) { + auto id = static_cast(Object)->Identifier; // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - ccls = FindStructType(static_cast(Object)->Identifier, ctx); - if (ccls != nullptr) static_cast(Object)->noglobal = true; + ccls = FindStructType(id, ctx); + if (ccls != nullptr) + { + static_cast(Object)->noglobal = true; + } + else + { + PType *type; + // Another special case to deal with here is constants assigned to non-struct types. The code below cannot deal with them so it needs to be done here explicitly. + // Thanks to the messed up search logic of the type system, which doesn't allow any search by type name for the basic types at all, + // we have to do this manually, though and check for all types that may have values attached explicitly. + // (What's the point of attached fields to types if you cannot even search for the types...???) + switch (id) + { + default: + type = nullptr; + break; + + case NAME_Byte: + case NAME_uint8: + type = TypeUInt8; + break; + + case NAME_sByte: + case NAME_int8: + type = TypeSInt8; + break; + + case NAME_uShort: + case NAME_uint16: + type = TypeUInt16; + break; + + case NAME_Short: + case NAME_int16: + type = TypeSInt16; + break; + + case NAME_Int: + type = TypeSInt32; + break; + + case NAME_uInt: + type = TypeUInt32; + break; + + case NAME_Float: + type = TypeFloat32; + break; + + case NAME_Double: + type = TypeFloat64; + break; + } + if (type != nullptr) + { + auto sym = type->Symbols.FindSymbol(Identifier, true); + if (sym != nullptr) + { + // non-struct symbols must be constant numbers and can only be defined internally. + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + auto sn = static_cast(sym); + + VMValue vmv; + if (sn->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) vmv = sn->Value; + else vmv = sn->Float; + auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + } + } } SAFE_RESOLVE(Object, ctx); - if (Identifier == FName("allmap")) - { - int a = 2; - } - // check for class or struct constants if the left side is a type name. if (Object->ValueType == TypeError) { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 0e34e2da48..3838c3a89a 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1121,37 +1121,6 @@ DEFINE_PROPERTY(bloodcolor, C, Actor) } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(bloodtype, Sss, Actor) -{ - PROP_STRING_PARM(str, 0) - PROP_STRING_PARM(str1, 1) - PROP_STRING_PARM(str2, 2) - - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - PClassActor *ainfo = static_cast(info); - - FName blood = str; - // normal blood - ainfo->BloodType = blood; - - if (PROP_PARM_COUNT > 1) - { - blood = str1; - } - // blood splatter - ainfo->BloodType2 = blood; - - if (PROP_PARM_COUNT > 2) - { - blood = str2; - } - // axe blood - ainfo->BloodType3 = blood; -} - //========================================================================== // //========================================================================== @@ -1387,8 +1356,7 @@ DEFINE_PROPERTY(stealthalpha, F, Actor) DEFINE_PROPERTY(cameraheight, F, Actor) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->CameraHeight = i; + defaults->CameraHeight = i; } //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 6a12e00f8f..9796c3e8df 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -189,6 +189,7 @@ class Actor : Thinker native native State MissileState; native voidptr /*DecalBase*/ DecalGenerator; native uint8 fountaincolor; + native double CameraHeight; // Height of camera when used as such native meta String Obituary; // Player was killed by this actor native meta String HitObituary; // Player was killed by this actor in melee @@ -199,12 +200,11 @@ class Actor : Thinker native native meta int WoundHealth; // Health needed to enter wound state native meta double FastSpeed; // speed in fast mode native meta double RDFactor; // Radius damage factor - native meta double CameraHeight; // Height of camera when used as such native meta Sound HowlSound; // Sound being played when electrocuted or poisoned - native meta Name BloodType; // Blood replacement type - native meta Name BloodType2; // Bloopsplatter replacement type - native meta Name BloodType3; // AxeBlood replacement type - + + meta Name BloodType; // Blood replacement type + meta Name BloodType2; // Bloopsplatter replacement type + meta Name BloodType3; // AxeBlood replacement type meta bool DontHurtShooter; meta int ExplosionRadius; meta int ExplosionDamage; @@ -221,6 +221,7 @@ class Actor : Thinker native Property DontHurtShooter: DontHurtShooter; Property ExplosionRadius: ExplosionRadius; Property ExplosionDamage: ExplosionDamage; + Property BloodType: BloodType, BloodType2, BloodType3; // need some definition work first //FRenderStyle RenderStyle; @@ -248,7 +249,7 @@ class Actor : Thinker native Health DEFAULT_HEALTH; Reactiontime 8; Radius 20; - RenderRadius 0; + RenderRadius 0; Height 16; Mass 100; RenderStyle 'Normal'; @@ -288,6 +289,7 @@ class Actor : Thinker native VisibleAngles 0, 0; VisiblePitch 0, 0; DefaultStateUsage SUF_ACTOR|SUF_OVERLAY; + CameraHeight int.min; } // Functions @@ -320,7 +322,7 @@ class Actor : Thinker native virtual native void Touch(Actor toucher); virtual native void MarkPrecacheSounds(); - // Called by PIT_CheckThing to check if two actos actually can collide. + // Called by PIT_CheckThing to check if two actors actually can collide. virtual bool CanCollideWith(Actor other, bool passive) { return true; @@ -344,6 +346,33 @@ class Actor : Thinker native { return false; } + + virtual class GetBloodType(int type) + { + Class bloodcls; + if (type == 0) + { + bloodcls = BloodType; + } + else if (type == 1) + { + bloodcls = BloodType2; + } + else if (type == 2) + { + bloodcls = BloodType3; + } + else + { + return NULL; + } + + if (bloodcls != NULL) + { + bloodcls = GetReplacement(bloodcls); + } + return bloodcls; + } native static class GetReplacement(class cls); native static class GetReplacee(class cls); From 2a4a5e7a7064c615b5d9a68e4805e999e047fba4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 12:47:44 +0100 Subject: [PATCH 172/207] - refactored a few more native meta properties. --- src/actor.h | 4 +++ src/info.cpp | 8 ------ src/info.h | 4 --- src/namedef.h | 1 + src/p_interaction.cpp | 2 +- src/p_map.cpp | 4 +-- src/p_mobj.cpp | 36 +++++++++++++++++---------- src/scripting/thingdef_properties.cpp | 19 +++----------- wadsrc/static/zscript/actor.txt | 12 +++++++-- 9 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/actor.h b/src/actor.h index 6e64b6033e..e7d84f09d5 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1025,6 +1025,10 @@ public: double projectilepassheight; // height for clipping projectile movement against this actor double CameraHeight; // Height of camera when used as such + double RadiusDamageFactor; // Radius damage factor + double SelfDamageFactor; + double StealthAlpha; // Minmum alpha for MF_STEALTH. + SDWORD tics; // state tic counter FState *state; //VMFunction *Damage; // For missiles and monster railgun diff --git a/src/info.cpp b/src/info.cpp index 6f9b95f36d..b8abba9760 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -255,10 +255,6 @@ PClassActor::PClassActor() BurnHeight = -1; GibHealth = INT_MIN; WoundHealth = 6; - FastSpeed = -1.; - RDFactor = 1.; - SelfDamageFactor = 1.; - StealthAlpha = 0.; DropItems = NULL; // Record this in the master list. @@ -311,10 +307,6 @@ void PClassActor::DeriveData(PClass *newclass) newa->BloodColor = BloodColor; newa->GibHealth = GibHealth; newa->WoundHealth = WoundHealth; - newa->FastSpeed = FastSpeed; - newa->RDFactor = RDFactor; - newa->SelfDamageFactor = SelfDamageFactor; - newa->StealthAlpha = StealthAlpha; newa->HowlSound = HowlSound; newa->distancecheck = distancecheck; diff --git a/src/info.h b/src/info.h index fd89145465..f2a6101e9b 100644 --- a/src/info.h +++ b/src/info.h @@ -297,10 +297,6 @@ public: PalEntry BloodColor; // Colorized blood int GibHealth; // Negative health below which this monster dies an extreme death int WoundHealth; // Health needed to enter wound state - double FastSpeed; // speed in fast mode - double RDFactor; // Radius damage factor - double SelfDamageFactor; - double StealthAlpha; // Minmum alpha for MF_STEALTH. FSoundID HowlSound; // Sound being played when electrocuted or poisoned FDropItem *DropItems; diff --git a/src/namedef.h b/src/namedef.h index 196c41fd05..7c63eb7859 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -392,6 +392,7 @@ xx(Radius) xx(ReactionTime) xx(MeleeRange) xx(Speed) +xx(FastSpeed) xx(Clamp) xx(VisibleStartAngle) xx(VisibleStartPitch) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 4c23c8123c..2af2a3da13 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1022,7 +1022,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da } if (target == source && damage < TELEFRAG_DAMAGE) { - damage = int(damage * target->GetClass()->SelfDamageFactor); + damage = int(damage * target->SelfDamageFactor); } // [MC] Changed it to check rawdamage here for consistency, even though that doesn't actually do anything diff --git a/src/p_map.cpp b/src/p_map.cpp index 70b18df7fa..7e110dcbf4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5680,7 +5680,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom { points = points * splashfactor; } - points *= thing->GetClass()->RDFactor; + points *= thing->RadiusDamageFactor; double check = int(points) * bombdamage; // points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.) @@ -5759,7 +5759,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom dist = clamp(dist - fulldamagedistance, 0, dist); int damage = Scale(bombdamage, bombdistance - int(dist), bombdistance); - double factor = splashfactor * thing->GetClass()->RDFactor; + double factor = splashfactor * thing->RadiusDamageFactor; damage = int(damage * factor); if (damage > 0 || (bombspot->flags7 & MF7_FORCEZERORADIUSDMG)) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d95bae5b2f..9ccdde24e3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -312,6 +312,9 @@ DEFINE_FIELD(AActor, Conversation) DEFINE_FIELD(AActor, DecalGenerator) DEFINE_FIELD(AActor, fountaincolor) DEFINE_FIELD(AActor, CameraHeight) +DEFINE_FIELD(AActor, RadiusDamageFactor) +DEFINE_FIELD(AActor, SelfDamageFactor) +DEFINE_FIELD(AActor, StealthAlpha) DEFINE_FIELD(PClassActor, Obituary) DEFINE_FIELD(PClassActor, HitObituary) @@ -320,10 +323,6 @@ DEFINE_FIELD(PClassActor, BurnHeight) DEFINE_FIELD(PClassActor, BloodColor) DEFINE_FIELD(PClassActor, GibHealth) DEFINE_FIELD(PClassActor, WoundHealth) -DEFINE_FIELD(PClassActor, FastSpeed) -DEFINE_FIELD(PClassActor, RDFactor) -DEFINE_FIELD(PClassActor, SelfDamageFactor) -DEFINE_FIELD(PClassActor, StealthAlpha) DEFINE_FIELD(PClassActor, HowlSound) //========================================================================== @@ -490,7 +489,11 @@ void AActor::Serialize(FSerializer &arc) A("visiblestartangle",VisibleStartAngle) A("visibleendangle",VisibleEndAngle) A("visiblestartpitch",VisibleStartPitch) - A("visibleendpitch",VisibleEndPitch); + A("visibleendpitch",VisibleEndPitch) + A("rdfactor", RadiusDamageFactor) + A("selfdamagefactor", SelfDamageFactor) + A("stealthalpha", StealthAlpha); + } #undef A @@ -4105,9 +4108,9 @@ void AActor::Tick () else if (visdir < 0) { Alpha -= 1.5/TICRATE; - if (Alpha < GetClass()->StealthAlpha) + if (Alpha < StealthAlpha) { - Alpha = GetClass()->StealthAlpha; + Alpha = StealthAlpha; visdir = 0; } } @@ -4828,8 +4831,11 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a actor->renderflags = (actor->renderflags & ~RF_FULLBRIGHT) | ActorRenderFlags::FromInt (st->GetFullbright()); actor->touching_sectorlist = nullptr; // NULL head of sector list // phares 3/13/98 actor->touching_rendersectors = nullptr; - if (G_SkillProperty(SKILLP_FastMonsters) && actor->GetClass()->FastSpeed >= 0) - actor->Speed = actor->GetClass()->FastSpeed; + if (G_SkillProperty(SKILLP_FastMonsters)) + { + double f = actor->FloatVar(NAME_FastSpeed); + if (f >= 0) actor->Speed = f; + } // set subsector and/or block links actor->LinkToWorld (nullptr, SpawningMapThing); @@ -6701,10 +6707,14 @@ static double GetDefaultSpeed(PClassActor *type) { if (type == NULL) return 0; - else if (G_SkillProperty(SKILLP_FastMonsters) && type->FastSpeed >= 0) - return type->FastSpeed; - else - return GetDefaultByType(type)->Speed; + + auto def = GetDefaultByType(type); + if (G_SkillProperty(SKILLP_FastMonsters)) + { + double f = def->FloatVar(NAME_FastSpeed); + if (f >= 0) return f; + } + return def->Speed; } DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 3838c3a89a..a6657ce972 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1310,24 +1310,13 @@ DEFINE_PROPERTY(poisondamagetype, S, Actor) defaults->PoisonDamageType = poisondamagetype; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(fastspeed, F, Actor) -{ - PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->FastSpeed = i; -} - //========================================================================== // //========================================================================== DEFINE_PROPERTY(radiusdamagefactor, F, Actor) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->RDFactor = i; + defaults->RadiusDamageFactor = i; } //========================================================================== @@ -1336,8 +1325,7 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor) DEFINE_PROPERTY(selfdamagefactor, F, Actor) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->SelfDamageFactor = i; + defaults->SelfDamageFactor = i; } //========================================================================== @@ -1346,8 +1334,7 @@ DEFINE_PROPERTY(selfdamagefactor, F, Actor) DEFINE_PROPERTY(stealthalpha, F, Actor) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->StealthAlpha = i; + defaults->StealthAlpha = i; } //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 9796c3e8df..2fc0d6d3bd 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -190,6 +190,9 @@ class Actor : Thinker native native voidptr /*DecalBase*/ DecalGenerator; native uint8 fountaincolor; native double CameraHeight; // Height of camera when used as such + native double RadiusDamageFactor; // Radius damage factor + native double SelfDamageFactor; + native double StealthAlpha; native meta String Obituary; // Player was killed by this actor native meta String HitObituary; // Player was killed by this actor in melee @@ -198,8 +201,6 @@ class Actor : Thinker native native meta color BloodColor; // Colorized blood native meta int GibHealth; // Negative health below which this monster dies an extreme death native meta int WoundHealth; // Health needed to enter wound state - native meta double FastSpeed; // speed in fast mode - native meta double RDFactor; // Radius damage factor native meta Sound HowlSound; // Sound being played when electrocuted or poisoned meta Name BloodType; // Blood replacement type @@ -212,6 +213,7 @@ class Actor : Thinker native meta Sound MeleeSound; meta double MissileHeight; meta Name MissileName; + meta double FastSpeed; // speed in fast mode Property prefix: none; Property MeleeDamage: MeleeDamage; @@ -222,6 +224,7 @@ class Actor : Thinker native Property ExplosionRadius: ExplosionRadius; Property ExplosionDamage: ExplosionDamage; Property BloodType: BloodType, BloodType2, BloodType3; + Property FastSpeed: FastSpeed; // need some definition work first //FRenderStyle RenderStyle; @@ -290,6 +293,11 @@ class Actor : Thinker native VisiblePitch 0, 0; DefaultStateUsage SUF_ACTOR|SUF_OVERLAY; CameraHeight int.min; + FastSpeed -1; + RadiusDamageFactor 1; + SelfDamageFactor 1; + StealthAlpha 0; + } // Functions From d5250d6b9f87af047214926e4c8f7ac14cb65032 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 12:56:35 +0100 Subject: [PATCH 173/207] - made WoundHealth modifiable to allow more control over the wound state. --- src/actor.h | 1 + src/info.cpp | 2 -- src/info.h | 1 - src/p_interaction.cpp | 2 +- src/p_mobj.cpp | 3 ++- src/scripting/thingdef_properties.cpp | 3 +-- wadsrc/static/zscript/actor.txt | 2 ++ 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/actor.h b/src/actor.h index e7d84f09d5..739f08f4ab 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1028,6 +1028,7 @@ public: double RadiusDamageFactor; // Radius damage factor double SelfDamageFactor; double StealthAlpha; // Minmum alpha for MF_STEALTH. + int WoundHealth; // Health needed to enter wound state SDWORD tics; // state tic counter FState *state; diff --git a/src/info.cpp b/src/info.cpp index b8abba9760..d81d4d8743 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -254,7 +254,6 @@ PClassActor::PClassActor() DeathHeight = -1; BurnHeight = -1; GibHealth = INT_MIN; - WoundHealth = 6; DropItems = NULL; // Record this in the master list. @@ -306,7 +305,6 @@ void PClassActor::DeriveData(PClass *newclass) newa->BurnHeight = BurnHeight; newa->BloodColor = BloodColor; newa->GibHealth = GibHealth; - newa->WoundHealth = WoundHealth; newa->HowlSound = HowlSound; newa->distancecheck = distancecheck; diff --git a/src/info.h b/src/info.h index f2a6101e9b..28a684281b 100644 --- a/src/info.h +++ b/src/info.h @@ -296,7 +296,6 @@ public: double BurnHeight; // Height on burning death PalEntry BloodColor; // Colorized blood int GibHealth; // Negative health below which this monster dies an extreme death - int WoundHealth; // Health needed to enter wound state FSoundID HowlSound; // Sound being played when electrocuted or poisoned FDropItem *DropItems; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 2af2a3da13..da60af8ad9 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1536,7 +1536,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da woundstate = target->FindState(NAME_Wound, mod); if (woundstate != NULL) { - int woundhealth = target->GetClass()->WoundHealth; + int woundhealth = target->WoundHealth; if (target->health <= woundhealth) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9ccdde24e3..22cbe1e3fa 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -315,6 +315,7 @@ DEFINE_FIELD(AActor, CameraHeight) DEFINE_FIELD(AActor, RadiusDamageFactor) DEFINE_FIELD(AActor, SelfDamageFactor) DEFINE_FIELD(AActor, StealthAlpha) +DEFINE_FIELD(AActor, WoundHealth) DEFINE_FIELD(PClassActor, Obituary) DEFINE_FIELD(PClassActor, HitObituary) @@ -322,7 +323,6 @@ DEFINE_FIELD(PClassActor, DeathHeight) DEFINE_FIELD(PClassActor, BurnHeight) DEFINE_FIELD(PClassActor, BloodColor) DEFINE_FIELD(PClassActor, GibHealth) -DEFINE_FIELD(PClassActor, WoundHealth) DEFINE_FIELD(PClassActor, HowlSound) //========================================================================== @@ -490,6 +490,7 @@ void AActor::Serialize(FSerializer &arc) A("visibleendangle",VisibleEndAngle) A("visiblestartpitch",VisibleStartPitch) A("visibleendpitch",VisibleEndPitch) + A("woundhealth", WoundHealth) A("rdfactor", RadiusDamageFactor) A("selfdamagefactor", SelfDamageFactor) A("stealthalpha", StealthAlpha); diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index a6657ce972..a70fa0c9e1 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -608,8 +608,7 @@ DEFINE_PROPERTY(gibhealth, I, Actor) DEFINE_PROPERTY(woundhealth, I, Actor) { PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->WoundHealth = id; + defaults->WoundHealth = id; } //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2fc0d6d3bd..4fa2323b00 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -297,6 +297,8 @@ class Actor : Thinker native RadiusDamageFactor 1; SelfDamageFactor 1; StealthAlpha 0; + WoundHealth 6; + } From 851984efe0649bda9583ecc834d948c1c241a9f0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 13:40:46 +0100 Subject: [PATCH 174/207] - made GetDeathHeight a virtual scripted function. - made GetGibHealth a virtual scripted function. - removed a few more native meta properties. --- src/dobject.h | 2 + src/dobjtype.h | 5 ++ src/gi.cpp | 1 + src/info.cpp | 8 ---- src/info.h | 4 -- src/namedef.h | 1 + src/p_acs.cpp | 4 +- src/p_actionfunctions.cpp | 16 ------- src/p_interaction.cpp | 20 ++------ src/p_mobj.cpp | 32 ++++++------- src/scripting/decorate/olddecorations.cpp | 4 +- src/scripting/thingdef_properties.cpp | 40 ---------------- wadsrc/static/zscript/actor.txt | 57 +++++++++++++++++++---- wadsrc/static/zscript/base.txt | 1 + 14 files changed, 80 insertions(+), 115 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 7510a4cff3..d99fbee2b8 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -41,6 +41,7 @@ class PClass; class PType; class FSerializer; +class FSoundID; class DObject; /* @@ -483,6 +484,7 @@ public: // Add other types as needed. bool &BoolVar(FName field); int &IntVar(FName field); + FSoundID &SoundVar(FName field); PalEntry &ColorVar(FName field); FName &NameVar(FName field); double &FloatVar(FName field); diff --git a/src/dobjtype.h b/src/dobjtype.h index 76e17b1331..f589b4e489 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -728,6 +728,11 @@ inline int &DObject::IntVar(FName field) return *(int*)ScriptVar(field, TypeSInt32); } +inline FSoundID &DObject::SoundVar(FName field) +{ + return *(FSoundID*)ScriptVar(field, TypeSound); +} + inline PalEntry &DObject::ColorVar(FName field) { return *(PalEntry*)ScriptVar(field, TypeColor); diff --git a/src/gi.cpp b/src/gi.cpp index 672ca3263a..ad5c5a0eea 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -56,6 +56,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenMapNameFont) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenEnteringFont) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenFinishedFont) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gibfactor) const char *GameNames[17] = diff --git a/src/info.cpp b/src/info.cpp index d81d4d8743..76ba0fbcbe 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -251,10 +251,6 @@ PClassActor::PClassActor() DamageFactors = NULL; PainChances = NULL; - DeathHeight = -1; - BurnHeight = -1; - GibHealth = INT_MIN; - DropItems = NULL; // Record this in the master list. AllActorClasses.Push(this); @@ -301,11 +297,7 @@ void PClassActor::DeriveData(PClass *newclass) newa->DefaultStateUsage = DefaultStateUsage; newa->Obituary = Obituary; newa->HitObituary = HitObituary; - newa->DeathHeight = DeathHeight; - newa->BurnHeight = BurnHeight; newa->BloodColor = BloodColor; - newa->GibHealth = GibHealth; - newa->HowlSound = HowlSound; newa->distancecheck = distancecheck; newa->DropItems = DropItems; diff --git a/src/info.h b/src/info.h index 28a684281b..cd21deac44 100644 --- a/src/info.h +++ b/src/info.h @@ -292,11 +292,7 @@ public: FString Obituary; // Player was killed by this actor FString HitObituary; // Player was killed by this actor in melee - double DeathHeight; // Height on normal death - double BurnHeight; // Height on burning death PalEntry BloodColor; // Colorized blood - int GibHealth; // Negative health below which this monster dies an extreme death - FSoundID HowlSound; // Sound being played when electrocuted or poisoned FDropItem *DropItems; FString SourceLumpName; diff --git a/src/namedef.h b/src/namedef.h index 7c63eb7859..50bde739f2 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -393,6 +393,7 @@ xx(ReactionTime) xx(MeleeRange) xx(Speed) xx(FastSpeed) +xx(HowlSound) xx(Clamp) xx(VisibleStartAngle) xx(VisibleStartPitch) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index baf15c1105..6053ce85ab 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4232,7 +4232,7 @@ enum SOUND_Howl, }; -static FSoundID GetActorSound(const AActor *actor, int soundtype) +static FSoundID GetActorSound(AActor *actor, int soundtype) { switch (soundtype) { @@ -4245,7 +4245,7 @@ static FSoundID GetActorSound(const AActor *actor, int soundtype) case SOUND_Bounce: return actor->BounceSound; case SOUND_WallBounce: return actor->WallBounceSound; case SOUND_CrushPain: return actor->CrushPainSound; - case SOUND_Howl: return actor->GetClass()->HowlSound; + case SOUND_Howl: return actor->SoundVar(NAME_HowlSound); default: return 0; } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 1f6e6df7f8..b75949f01b 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -438,22 +438,6 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpawnHealth) return 0; } -//========================================================================== -// -// GetGibHealth -// -//========================================================================== -DEFINE_ACTION_FUNCTION(AActor, GetGibHealth) -{ - if (numret > 0) - { - PARAM_SELF_PROLOGUE(AActor); - ret->SetInt(self->GetGibHealth()); - return 1; - } - return 0; -} - //========================================================================== // // GetSpriteAngle diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index da60af8ad9..9d8d63de0a 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -411,23 +411,11 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) } flags6 |= MF6_KILLED; - // [RH] Allow the death height to be overridden using metadata. - double metaheight = -1; - if (DamageType == NAME_Fire) + IFVIRTUAL(AActor, GetDeathHeight) { - metaheight = GetClass()->BurnHeight; - } - if (metaheight < 0) - { - metaheight = GetClass()->DeathHeight; - } - if (metaheight < 0) - { - Height *= 0.25; - } - else - { - Height = MAX (metaheight, 0); + VMValue params[] = { (DObject*)this }; + VMReturn ret(&Height); + GlobalVMStack.Call(func, params, 1, &ret, 1); } // [RH] If the thing has a special, execute and remove it diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 22cbe1e3fa..bc432434c3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -319,11 +319,7 @@ DEFINE_FIELD(AActor, WoundHealth) DEFINE_FIELD(PClassActor, Obituary) DEFINE_FIELD(PClassActor, HitObituary) -DEFINE_FIELD(PClassActor, DeathHeight) -DEFINE_FIELD(PClassActor, BurnHeight) -DEFINE_FIELD(PClassActor, BloodColor) -DEFINE_FIELD(PClassActor, GibHealth) -DEFINE_FIELD(PClassActor, HowlSound) +//DEFINE_FIELD(PClassActor, BloodColor) //========================================================================== // @@ -3516,7 +3512,7 @@ int AActor::GetMissileDamage (int mask, int add) void AActor::Howl () { - FSoundID howl = GetClass()->HowlSound; + FSoundID howl = IntVar(NAME_HowlSound); if (!S_IsActorPlayingSomething(this, CHAN_BODY, howl)) { S_Sound (this, CHAN_BODY, howl, 1, ATTN_NORM); @@ -7481,9 +7477,10 @@ void AActor::Crash() { FState *crashstate = NULL; + int gibh = GetGibHealth(); if (DamageType != NAME_None) { - if (health < GetGibHealth()) + if (health < gibh) { // Extreme death FName labels[] = { NAME_Crash, NAME_Extreme, DamageType }; crashstate = FindState (3, labels, true); @@ -7495,7 +7492,7 @@ void AActor::Crash() } if (crashstate == NULL) { - if (health < GetGibHealth()) + if (health < gibh) { // Extreme death crashstate = FindState(NAME_Crash, NAME_Extreme); } @@ -7601,16 +7598,15 @@ void AActor::Revive() int AActor::GetGibHealth() const { - int gibhealth = GetClass()->GibHealth; - - if (gibhealth != INT_MIN) + IFVIRTUAL(AActor, GetGibHealth) { - return -abs(gibhealth); - } - else - { - return -int(SpawnHealth() * gameinfo.gibfactor); + VMValue params[] = { (DObject*)this }; + int h; + VMReturn ret(&h); + GlobalVMStack.Call(func, params, 1, &ret, 1); + return h; } + return -SpawnHealth(); } double AActor::GetCameraHeight() const @@ -8294,9 +8290,9 @@ void PrintMiscActorInfo(AActor *query) query->args[0], query->args[1], query->args[2], query->args[3], query->args[4], query->special1, query->special2); Printf("\nTID: %d", query->tid); - Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f.", + Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f, height= %f", query->X(), query->Y(), query->Z(), - query->floorz, query->ceilingz); + query->floorz, query->ceilingz, query->Height); Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n", query->Speed, query->Vel.X, query->Vel.Y, query->Vel.Z, query->Vel.Length()); Printf("Scale: x:%f, y:%f\n", query->Scale.X, query->Scale.Y); diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 8d220ec707..7370ddb54f 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -223,7 +223,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) { extra.DeathHeight = ((AActor*)(type->Defaults))->Height; } - type->DeathHeight = extra.DeathHeight; + ((AActor*)(type->Defaults))->FloatVar("DeathHeight") = extra.DeathHeight; } bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]); } @@ -262,7 +262,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) } if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->Height; - type->BurnHeight = extra.BurnHeight; + ((AActor*)(type->Defaults))->FloatVar("BurnHeight") = extra.BurnHeight; bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]); } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index a70fa0c9e1..e588b452ca 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -592,16 +592,6 @@ DEFINE_PROPERTY(health, I, Actor) defaults->health=id; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(gibhealth, I, Actor) -{ - PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->GibHealth = id; -} - //========================================================================== // //========================================================================== @@ -887,16 +877,6 @@ DEFINE_PROPERTY(activesound, S, Actor) defaults->ActiveSound = str; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(howlsound, S, Actor) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->HowlSound = str; -} - //========================================================================== // //========================================================================== @@ -1000,26 +980,6 @@ DEFINE_PROPERTY(hitobituary, S, Actor) static_cast(info)->HitObituary = str; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(deathheight, F, Actor) -{ - PROP_DOUBLE_PARM(h, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->DeathHeight = MAX(0., h); -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(burnheight, F, Actor) -{ - PROP_DOUBLE_PARM(h, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->BurnHeight = MAX(0., h); -} - //========================================================================== // //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 4fa2323b00..fcb250563a 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -193,16 +193,16 @@ class Actor : Thinker native native double RadiusDamageFactor; // Radius damage factor native double SelfDamageFactor; native double StealthAlpha; + native int WoundHealth; // Health needed to enter wound state + //native color BloodColor; // won't be accessible for now because it needs refactoring to remove the 255-translations limit. native meta String Obituary; // Player was killed by this actor native meta String HitObituary; // Player was killed by this actor in melee - native meta double DeathHeight; // Height on normal death - native meta double BurnHeight; // Height on burning death - native meta color BloodColor; // Colorized blood - native meta int GibHealth; // Negative health below which this monster dies an extreme death - native meta int WoundHealth; // Health needed to enter wound state - native meta Sound HowlSound; // Sound being played when electrocuted or poisoned + meta double DeathHeight; // Height on normal death + meta double BurnHeight; // Height on burning death + meta int GibHealth; // Negative health below which this monster dies an extreme death + meta Sound HowlSound; // Sound being played when electrocuted or poisoned meta Name BloodType; // Blood replacement type meta Name BloodType2; // Bloopsplatter replacement type meta Name BloodType3; // AxeBlood replacement type @@ -225,6 +225,10 @@ class Actor : Thinker native Property ExplosionDamage: ExplosionDamage; Property BloodType: BloodType, BloodType2, BloodType3; Property FastSpeed: FastSpeed; + Property HowlSound: HowlSound; + Property GibHealth: GibHealth; + Property DeathHeight: DeathHeight; + Property BurnHeight: BurnHeight; // need some definition work first //FRenderStyle RenderStyle; @@ -298,8 +302,9 @@ class Actor : Thinker native SelfDamageFactor 1; StealthAlpha 0; WoundHealth 6; - - + GibHealth int.min; + DeathHeight -1; + BurnHeight -1; } // Functions @@ -383,6 +388,41 @@ class Actor : Thinker native } return bloodcls; } + + virtual int GetGibHealth() + { + if (GibHealth != int.min) + { + return -abs(GibHealth); + } + else + { + return -int(GetSpawnHealth() * gameinfo.gibfactor); + } + } + + virtual double GetDeathHeight() + { + // [RH] Allow the death height to be overridden using metadata. + double metaheight = -1; + if (DamageType == 'Fire') + { + metaheight = BurnHeight; + } + if (metaheight < 0) + { + metaheight = DeathHeight; + } + if (metaheight < 0) + { + return Height * 0.25; + } + else + { + return MAX(metaheight, 0); + } + } + native static class GetReplacement(class cls); native static class GetReplacee(class cls); @@ -559,7 +599,6 @@ class Actor : Thinker native native double GetAngle(int flags, int ptr = AAPTR_TARGET); native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT); native int GetSpawnHealth(); - native int GetGibHealth(); native double GetCrouchFactor(int ptr = AAPTR_PLAYER1); native double GetCVar(string cvar); native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index d8fed2f28a..f5eda90227 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -310,6 +310,7 @@ struct GameInfoStruct native native GIFont mStatscreenMapNameFont; native GIFont mStatscreenEnteringFont; native GIFont mStatscreenFinishedFont; + native double gibfactor; } class Object native From fc125f7eafcac65805f3b62f9ae13eca774f0c47 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 14:30:14 +0100 Subject: [PATCH 175/207] - reworked the obituary system to use scripted virtual overrides. Let's hope this solves the problems with the original code, now that any actor needing special treatment can override it. --- src/info.cpp | 2 - src/info.h | 2 - src/p_interaction.cpp | 90 +++++---------------- src/p_mobj.cpp | 2 - src/scripting/thingdef_properties.cpp | 20 ----- wadsrc/static/zscript/actor.txt | 20 ++++- wadsrc/static/zscript/inventory/weapons.txt | 6 ++ wadsrc/static/zscript/shared/player.txt | 30 +++++++ 8 files changed, 73 insertions(+), 99 deletions(-) diff --git a/src/info.cpp b/src/info.cpp index 76ba0fbcbe..d51cad1155 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -295,8 +295,6 @@ void PClassActor::DeriveData(PClass *newclass) PClassActor *newa = static_cast(newclass); newa->DefaultStateUsage = DefaultStateUsage; - newa->Obituary = Obituary; - newa->HitObituary = HitObituary; newa->BloodColor = BloodColor; newa->distancecheck = distancecheck; diff --git a/src/info.h b/src/info.h index cd21deac44..d5e3eff481 100644 --- a/src/info.h +++ b/src/info.h @@ -290,8 +290,6 @@ public: TArray VisibleToPlayerClass; - FString Obituary; // Player was killed by this actor - FString HitObituary; // Player was killed by this actor in melee PalEntry BloodColor; // Colorized blood FDropItem *DropItems; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 9d8d63de0a..b4cb5d16f5 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -62,7 +62,6 @@ #include "g_levellocals.h" #include "events.h" -static FRandom pr_obituary ("Obituary"); static FRandom pr_botrespawn ("BotRespawn"); static FRandom pr_killmobj ("ActorDie"); FRandom pr_damagemobj ("ActorTakeDamage"); @@ -186,14 +185,11 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf const char *message; const char *messagename; char gendermessage[1024]; - int gender; // No obituaries for non-players, voodoo dolls or when not wanted if (self->player == NULL || self->player->mo != self || !show_obituaries) return; - gender = self->player->userinfo.GetGender(); - // Treat voodoo dolls as unknown deaths if (inflictor && inflictor->player && inflictor->player->mo != inflictor) MeansOfDeath = NAME_None; @@ -217,93 +213,47 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf } FString obit = DamageTypeDefinition::GetObituary(mod); - if (obit.IsNotEmpty()) messagename = obit; + if (attacker == nullptr) messagename = obit; else { switch (mod) { - case NAME_Suicide: messagename = "OB_SUICIDE"; break; - case NAME_Falling: messagename = "OB_FALLING"; break; - case NAME_Crush: messagename = "OB_CRUSH"; break; - case NAME_Exit: messagename = "OB_EXIT"; break; - case NAME_Drowning: messagename = "OB_WATER"; break; - case NAME_Slime: messagename = "OB_SLIME"; break; - case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break; + case NAME_Suicide: message = "$OB_SUICIDE"; break; + case NAME_Falling: message = "$OB_FALLING"; break; + case NAME_Crush: message = "$OB_CRUSH"; break; + case NAME_Exit: message = "$OB_EXIT"; break; + case NAME_Drowning: message = "$OB_WATER"; break; + case NAME_Slime: message = "$OB_SLIME"; break; + case NAME_Fire: messagename = "$OB_LAVA"; break; } } // Check for being killed by a voodoo doll. if (inflictor && inflictor->player && inflictor->player->mo != inflictor) { - messagename = "OB_VOODOO"; + messagename = "$OB_VOODOO"; } - if (messagename != NULL) - message = GStrings(messagename); - if (attacker != NULL && message == NULL) { if (attacker == self) { - message = GStrings("OB_KILLEDSELF"); + message = "$OB_KILLEDSELF"; } - else if (attacker->player == NULL) + else { - if (mod == NAME_Telefrag) + IFVIRTUALPTR(attacker, AActor, GetObituary) { - message = GStrings("OB_MONTELEFRAG"); - } - else if (mod == NAME_Melee && attacker->GetClass()->HitObituary.IsNotEmpty()) - { - message = attacker->GetClass()->HitObituary; - } - else if (attacker->GetClass()->Obituary.IsNotEmpty()) - { - message = attacker->GetClass()->Obituary; + VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) }; + FString ret; + VMReturn rett(&ret); + GlobalVMStack.Call(func, params, countof(params), &rett, 1); + if (ret.IsNotEmpty()) message = ret; } } } - - if (message == NULL && attacker != NULL && attacker->player != NULL) - { - if (self->player != attacker->player && self->IsTeammate(attacker)) - { - self = attacker; - gender = self->player->userinfo.GetGender(); - mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3)); - message = GStrings(gendermessage); - } - else - { - if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG"); - if (message == NULL) - { - if (inflictor != NULL && inflictor->GetClass()->Obituary.IsNotEmpty()) - { - message = inflictor->GetClass()->Obituary; - } - if (message == NULL && (dmgflags & DMG_PLAYERATTACK) && attacker->player->ReadyWeapon != NULL) - { - message = attacker->player->ReadyWeapon->GetClass()->Obituary; - } - if (message == NULL) - { - switch (mod) - { - case NAME_BFGSplash: messagename = "OB_MPBFG_SPLASH"; break; - case NAME_Railgun: messagename = "OB_RAILGUN"; break; - } - if (messagename != NULL) - message = GStrings(messagename); - } - if (message == NULL) - { - message = attacker->GetClass()->Obituary; - } - } - } - } - else attacker = self; // for the message creation + if (message == nullptr) message = messagename; // fallback to defaults if possible. + if (attacker->player == nullptr) attacker = self; // for the message creation if (message != NULL && message[0] == '$') { @@ -319,7 +269,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (message == NULL || strlen(message) <= 0) return; - SexMessage (message, gendermessage, gender, + SexMessage (message, gendermessage, self->player->userinfo.GetGender(), self->player->userinfo.GetName(), attacker->player->userinfo.GetName()); Printf (PRINT_MEDIUM, "%s\n", gendermessage); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index bc432434c3..4446393d71 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -317,8 +317,6 @@ DEFINE_FIELD(AActor, SelfDamageFactor) DEFINE_FIELD(AActor, StealthAlpha) DEFINE_FIELD(AActor, WoundHealth) -DEFINE_FIELD(PClassActor, Obituary) -DEFINE_FIELD(PClassActor, HitObituary) //DEFINE_FIELD(PClassActor, BloodColor) //========================================================================== diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index e588b452ca..e41523b8cf 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -960,26 +960,6 @@ DEFINE_PROPERTY(alpha, F, Actor) defaults->Alpha = id; } -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(obituary, S, Actor) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->Obituary = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(hitobituary, S, Actor) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->HitObituary = str; -} - //========================================================================== // //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index fcb250563a..97e2bf6bb8 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -196,9 +196,8 @@ class Actor : Thinker native native int WoundHealth; // Health needed to enter wound state //native color BloodColor; // won't be accessible for now because it needs refactoring to remove the 255-translations limit. - native meta String Obituary; // Player was killed by this actor - native meta String HitObituary; // Player was killed by this actor in melee - + meta String Obituary; // Player was killed by this actor + meta String HitObituary; // Player was killed by this actor in melee meta double DeathHeight; // Height on normal death meta double BurnHeight; // Height on burning death meta int GibHealth; // Negative health below which this monster dies an extreme death @@ -216,6 +215,8 @@ class Actor : Thinker native meta double FastSpeed; // speed in fast mode Property prefix: none; + Property Obituary: Obituary; + Property HitObituary: HitObituary; Property MeleeDamage: MeleeDamage; Property MeleeSound: MeleeSound; Property MissileHeight: MissileHeight; @@ -423,6 +424,19 @@ class Actor : Thinker native } } + virtual String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack) + { + if (mod == 'Telefrag') + { + return "$OB_MONTELEFRAG"; + } + else if (mod == 'Melee' && HitObituary.Length() > 0) + { + return HitObituary; + } + return Obituary; + } + native static class GetReplacement(class cls); native static class GetReplacee(class cls); diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index de94647265..860d387e27 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -89,6 +89,12 @@ class Weapon : StateProvider native return s; } + override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack) + { + // Weapons may never return HitObituary by default. Override this if it is needed. + return Obituary; + } + action void A_GunFlash(statelabel flashlabel = null, int flags = 0) { let player = player; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 9b686a5513..14347a41c9 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -119,6 +119,36 @@ class PlayerPawn : Actor native } } + override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack) + { + if (victim.player != player && victim.IsTeammate(self)) + { + victim = self; + return String.Format("$OB_FRIENDLY%c", random[Obituary](49, 53)); + } + else + { + if (mod == 'Telefrag') return "$OB_MPTELEFRAG"; + + String message; + if (inflictor != NULL) + { + message = inflictor.GetObituary(victim, inflictor, mod, playerattack); + } + if (message.Length() == 0 && playerattack && player.ReadyWeapon != NULL) + { + message = player.ReadyWeapon.GetObituary(victim, inflictor, mod, playerattack); + } + if (message.Length() == 0) + { + if (mod == 'BFGSplash') return "$OB_MPBFG_SPLASH"; + if (mod == 'Railgun') return "$OB_RAILGUN"; + message = Obituary; + } + return message; + } + } + // This is for SBARINFO. int, int GetEffectTicsForItem(class item) { From bc0ffc4185d4c5c42e10b488b925cf2aec2be230 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 14:33:46 +0100 Subject: [PATCH 176/207] - removed access to the PlayerPawn's DisplayName variable. This one has implicit semantics, so wherever a displayable name is needed GetPrintableDisplayName should be called instead to allow later refactoring of the internal handling. --- src/p_user.cpp | 2 -- wadsrc/static/zscript/shared/player.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/src/p_user.cpp b/src/p_user.cpp index 30db0a2711..0f8954e56e 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3333,8 +3333,6 @@ DEFINE_FIELD(APlayerPawn, HexenArmor) DEFINE_FIELD(APlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd) -DEFINE_FIELD(PClassActor, DisplayName) - DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) DEFINE_FIELD_X(PlayerInfo, player_t, original_oldbuttons) diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 14347a41c9..2e7bda8f65 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -34,7 +34,6 @@ class PlayerPawn : Actor native native double ViewBob; // [SP] ViewBob Multiplier native double FullHeight; - native meta String DisplayName; // Display name (used in menus, etc.) meta Name HealingRadiusType; meta Name InvulMode; From 168627f549a353794d74aa83452b9139c5366f71 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 14:38:50 +0100 Subject: [PATCH 177/207] - native meta variables are not needed anymore. They were only a temporary aid to properly handle this, but now all have been redone. --- src/scripting/backend/codegen.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 9 +----- src/scripting/zscript/zcc_compile.cpp | 39 +++++++++++------------ 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 893a50eed9..8e41f44ab4 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6871,7 +6871,7 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) { obj.Free(build); ExpEmit meta(build, REGT_POINTER); - build->Emit(membervar->Flags & VARF_Native? OP_CLSS : OP_META, meta.RegNum, obj.RegNum); + build->Emit(OP_META, meta.RegNum, obj.RegNum); obj = meta; } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index e70059fecb..72cac7cde7 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -827,14 +827,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul if (i > 0) sc.MustGetStringName(","); if (f->Flags & VARF_Meta) { - if (f->Flags & VARF_Native) - { - addr = ((char*)bag.Info) + f->Offset; - } - else - { - addr = ((char*)bag.Info->Meta) + f->Offset; - } + addr = ((char*)bag.Info->Meta) + f->Offset; } else { diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 548424cd97..5574fcc187 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1095,22 +1095,28 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (varflags & VARF_Native) { - auto querytype = (varflags & VARF_Meta) ? type->GetClass() : type; - fd = FindField(querytype, FName(name->Name).GetChars()); - if (fd == nullptr) + if (varflags & VARF_Meta) { - Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); + Error(field, "Native meta variable %s not allowed", FName(name->Name).GetChars()); } - else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0) - { - Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); - } - // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. else { - // for bit fields the type must point to the source variable. - if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; - type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + fd = FindField(type, FName(name->Name).GetChars()); + if (fd == nullptr) + { + Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); + } + else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0) + { + Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); + } + // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. + else + { + // for bit fields the type must point to the source variable. + if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; + type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + } } } else if (hasnativechildren) @@ -1694,14 +1700,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop if (f->Flags & VARF_Meta) { - if (f->Flags & VARF_Native) - { - addr = ((char*)bag.Info) + f->Offset; - } - else - { - addr = ((char*)bag.Info->Meta) + f->Offset; - } + addr = ((char*)bag.Info->Meta) + f->Offset; } else { From 5f6da0d2223569ea9f5c346f791ac7e913236d0b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 14:44:18 +0100 Subject: [PATCH 178/207] fixed double allocation of metadata. --- src/dobjtype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f86797dfd2..cd128b6560 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3361,7 +3361,7 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags) // Only initialize the defaults if they have already been created. // For ZScript this is not the case, it will first define all fields before // setting up any defaults for any class. - if (field != nullptr && !(flags & VARF_Native)) + if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) { Meta = (BYTE *)M_Realloc(Meta, MetaSize); memset(Meta + oldsize, 0, MetaSize - oldsize); From bb1709228cb0e9b66150094d9d836e50468772b4 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Tue, 28 Feb 2017 18:23:40 +0800 Subject: [PATCH 179/207] Changed FOV from a CCMD to a CVar, allowing players' FOV settings to persist. Also exported SetFOV to PlayerInfo for ZScript. --- src/c_cmds.cpp | 28 ----------------- src/d_player.h | 3 ++ src/p_mobj.cpp | 3 +- src/p_user.cpp | 41 +++++++++++++++++++++++++ wadsrc/static/zscript/shared/player.txt | 1 + 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 7e0a66c4b1..4bdca624a2 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -732,34 +732,6 @@ CCMD (dir) chdir (curdir); } -CCMD (fov) -{ - player_t *player = who ? who->player : &players[consoleplayer]; - - if (argv.argc() != 2) - { - Printf ("fov is %g\n", player->DesiredFOV); - return; - } - else if (dmflags & DF_NO_FOV) - { - if (consoleplayer == Net_Arbitrator) - { - Net_WriteByte (DEM_FOV); - } - else - { - Printf ("A setting controller has disabled FOV changes.\n"); - return; - } - } - else - { - Net_WriteByte (DEM_MYFOV); - } - Net_WriteByte (clamp (atoi (argv[1]), 5, 179)); -} - //========================================================================== // // CCMD warp diff --git a/src/d_player.h b/src/d_player.h index 2d7d439c57..35daa57a2c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -529,6 +529,9 @@ public: DPSprite *GetPSprite(PSPLayers layer); bool GetPainFlash(FName type, PalEntry *color) const; + + // [Nash] set player FOV + void SetFOV(float fov); }; // Bookkeeping on players - state. diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f38ac12bb3..d5c1332652 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5305,6 +5305,7 @@ DEFINE_ACTION_FUNCTION(AActor, AdjustFloorClip) // EXTERN_CVAR (Bool, chasedemo) EXTERN_CVAR(Bool, sv_singleplayerrespawn) +EXTERN_CVAR(Float, fov) extern bool demonew; @@ -5442,7 +5443,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) mobj->sprite = Skins[p->userinfo.GetSkin()].sprite; } - p->DesiredFOV = p->FOV = 90.f; + p->DesiredFOV = p->FOV = fov; p->camera = p->mo; p->playerstate = PST_LIVE; p->refire = 0; diff --git a/src/p_user.cpp b/src/p_user.cpp index 5bb0e2127e..62d44c74ed 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -88,6 +88,13 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO ColorSetList ColorSets; PainFlashList PainFlashes; +// [Nash] FOV cvar setting +CUSTOM_CVAR(Float, fov, 90.f, CVAR_ARCHIVE | CVAR_USERINFO | CVAR_NOINITCALL) +{ + player_t *p = &players[consoleplayer]; + p->SetFOV(fov); +} + struct PredictPos { int gametic; @@ -550,6 +557,40 @@ int player_t::GetSpawnClass() return static_cast(GetDefaultByType(type))->SpawnMask; } +// [Nash] Set FOV +void player_t::SetFOV(float fov) +{ + player_t *p = &players[consoleplayer]; + if (p != nullptr && p->mo != nullptr) + { + if (dmflags & DF_NO_FOV) + { + if (consoleplayer == Net_Arbitrator) + { + Net_WriteByte(DEM_MYFOV); + } + else + { + Printf("A setting controller has disabled FOV changes.\n"); + return; + } + } + else + { + Net_WriteByte(DEM_MYFOV); + } + Net_WriteByte((BYTE)clamp(fov, 5.f, 179.f)); + } +} + +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetFOV) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_FLOAT(fov); + self->SetFOV((float)fov); + return 0; +} + //=========================================================================== // // EnumColorsets diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 8886e6744c..d2bd2d0120 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -320,6 +320,7 @@ usercmd_t original_cmd; native int GetGender(); native int GetTeam(); native float GetAutoaim(); + native void SetFOV(float fov); } struct PlayerClass native From dc6c91042bb1c34330774a4677fcb33cd785b124 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 18:47:18 +0100 Subject: [PATCH 180/207] - fixed misordered ACS functions. --- src/p_acs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 6053ce85ab..5ea7dfa075 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4369,8 +4369,8 @@ enum EACSFunctions ACSF_GetActorFloorTerrain, ACSF_StrArg, ACSF_Floor, - ACSF_Ceil, ACSF_Round, + ACSF_Ceil, // OpenGL stuff From 12915b5f6e27e36e2eb69356114f287347df2134 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Feb 2017 21:45:47 +0100 Subject: [PATCH 181/207] - use an inventory flag to decide what items are slipped by DF_NO_HEALTH and DF_NO_ARMOR. With all the changes over the last 10 years this had become too spotty. - use an enum type for ItemFlags, just like it was done for actor flags. Since the flag word is almost full it may soon be necessary to add a second one and then this kind of security check may become necessary. --- src/g_inventory/a_pickups.h | 10 ++++-- src/p_enemy.cpp | 4 +-- src/p_mobj.cpp | 36 +++++++++----------- src/scripting/thingdef_data.cpp | 2 ++ wadsrc/static/zscript/doom/doomartifacts.txt | 3 ++ wadsrc/static/zscript/inventory/armor.txt | 1 + wadsrc/static/zscript/inventory/health.txt | 2 ++ 7 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 9258d320a5..9b2fc1cc1a 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -17,7 +17,7 @@ struct visstyle_t; // A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc) -enum +enum ItemFlag { IF_ACTIVATABLE = 1<<0, // can be activated IF_ACTIVATED = 1<<1, // is currently activated @@ -46,8 +46,14 @@ enum IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting. IF_NOSCREENBLINK = 1<<26, // Does not blink the screen overlay when expiring. + IF_ISHEALTH = 1<<27, // for the DM flag so that it can recognize items that are not obviously health givers. + IF_ISARMOR = 1<<28, // for the DM flag so that it can recognize items that are not obviously armor givers. }; +typedef TFlags InvFlags; +//typedef TFlags ItemFlags2; +DEFINE_TFLAGS_OPERATORS(InvFlags) +//DEFINE_TFLAGS_OPERATORS(ItemFlags2) class AInventory : public AActor { @@ -89,7 +95,7 @@ public: PClassActor *SpawnPointClass; // For respawning like Heretic's mace FTextureID AltHUDIcon; - DWORD ItemFlags; + InvFlags ItemFlags; PClassActor *PickupFlash; // actor to spawn as pickup flash FSoundIDNoInit PickupSound; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 5841e6b994..dde4fce29c 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3217,13 +3217,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound) //--------------------------------------------------------------------------- void ModifyDropAmount(AInventory *inv, int dropamount) { - int flagmask = IF_IGNORESKILL; + auto flagmask = IF_IGNORESKILL; double dropammofactor = G_SkillProperty(SKILLP_DropAmmoFactor); // Default drop amount is half of regular amount * regular ammo multiplication if (dropammofactor == -1) { dropammofactor = 0.5; - flagmask = 0; + flagmask = ItemFlag(0); } if (dropamount > 0) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index fc40982f51..104a424711 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5821,27 +5821,23 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // [RH] Other things that shouldn't be spawned depending on dmflags if (deathmatch || alwaysapplydmflags) { - // Fixme: This needs to be done differently, it's quite broken. - if (dmflags & DF_NO_HEALTH) + if (i->IsDescendantOf(RUNTIME_CLASS(AInventory))) { - if (i->IsDescendantOf (PClass::FindActor(NAME_Health))) - return NULL; - if (i->TypeName == NAME_Berserk) - return NULL; - if (i->TypeName == NAME_Megasphere) - return NULL; - } - if (dmflags & DF_NO_ITEMS) - { -// if (i->IsDescendantOf (RUNTIME_CLASS(AArtifact))) -// return; - } - if (dmflags & DF_NO_ARMOR) - { - if (i->IsDescendantOf (PClass::FindActor(NAME_Armor))) - return NULL; - if (i->TypeName == NAME_Megasphere) - return NULL; + auto it = static_cast(GetDefaultByType(i)); + + if (dmflags & DF_NO_HEALTH) + { + if (it->ItemFlags & IF_ISHEALTH) return nullptr; + } + if (dmflags & DF_NO_ITEMS) + { + // if (i->IsDescendantOf (RUNTIME_CLASS(AArtifact))) + // return; + } + if (dmflags & DF_NO_ARMOR) + { + if (it->ItemFlags & IF_ISARMOR) return nullptr; + } } } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 265dc079b4..4b65e6413e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -430,6 +430,8 @@ static FFlagDef InventoryFlagDefs[] = DEFINE_FLAG(IF, TRANSFER, AInventory, ItemFlags), DEFINE_FLAG(IF, NOTELEPORTFREEZE, AInventory, ItemFlags), DEFINE_FLAG(IF, NOSCREENBLINK, AInventory, ItemFlags), + DEFINE_FLAG(IF, ISARMOR, AInventory, ItemFlags), + DEFINE_FLAG(IF, ISHEALTH, AInventory, ItemFlags), DEFINE_DUMMY_FLAG(FORCERESPAWNINSURVIVAL, false), diff --git a/wadsrc/static/zscript/doom/doomartifacts.txt b/wadsrc/static/zscript/doom/doomartifacts.txt index ad5e304c66..a6996cb886 100644 --- a/wadsrc/static/zscript/doom/doomartifacts.txt +++ b/wadsrc/static/zscript/doom/doomartifacts.txt @@ -72,6 +72,8 @@ class Megasphere : CustomInventory { +COUNTITEM +INVENTORY.ALWAYSPICKUP + +INVENTORY.ISHEALTH + +INVENTORY.ISARMOR Inventory.PickupMessage "$GOTMSPHERE"; Inventory.PickupSound "misc/p_pkup"; } @@ -183,6 +185,7 @@ class Berserk : CustomInventory { +COUNTITEM +INVENTORY.ALWAYSPICKUP + +INVENTORY.ISHEALTH Inventory.PickupMessage "$GOTBERSERK"; Inventory.PickupSound "misc/p_pkup"; } diff --git a/wadsrc/static/zscript/inventory/armor.txt b/wadsrc/static/zscript/inventory/armor.txt index ae9ab562e2..600c4e5265 100644 --- a/wadsrc/static/zscript/inventory/armor.txt +++ b/wadsrc/static/zscript/inventory/armor.txt @@ -38,6 +38,7 @@ class Armor : Inventory Default { Inventory.PickupSound "misc/armor_pkup"; + +INVENTORY.ISARMOR } } diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt index e2fb8eacfd..e64bbfd4a9 100644 --- a/wadsrc/static/zscript/inventory/health.txt +++ b/wadsrc/static/zscript/inventory/health.txt @@ -43,6 +43,7 @@ class Health : Inventory Default { + +INVENTORY.ISHEALTH Inventory.Amount 1; Inventory.MaxAmount 0; Inventory.PickupSound "misc/health_pkup"; @@ -99,6 +100,7 @@ class HealthPickup : Inventory { Inventory.DefMaxAmount; +INVENTORY.INVBAR + +INVENTORY.ISHEALTH } //=========================================================================== From cb295e0441cccae57b011fd764b3e0d5c49774db Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Mar 2017 00:04:17 +0100 Subject: [PATCH 182/207] - added parameter to PLayerPawn::GetMaxHealth to return the real maximum health, including stamina upgrades. --- src/b_think.cpp | 2 +- src/d_player.h | 2 +- src/g_statusbar/sbarinfo_commands.cpp | 4 ++-- src/p_mobj.cpp | 2 +- src/p_user.cpp | 11 +++++++---- wadsrc/static/zscript/shared/player.txt | 2 +- wadsrc/static/zscript/shared/player_cheat.txt | 2 +- 7 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/b_think.cpp b/src/b_think.cpp index da3fb61246..f286dd30f5 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -358,7 +358,7 @@ void DBot::WhatToGet (AActor *item) } else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere) return; - else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina) + else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth(true)) return; if ((dest == NULL || diff --git a/src/d_player.h b/src/d_player.h index 39698d6d8a..2787df231d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -93,7 +93,7 @@ public: virtual bool UpdateWaterLevel (bool splash) override; bool ResetAirSupply (bool playgasp = true); - int GetMaxHealth() const; + int GetMaxHealth(bool withupgrades = false) const; void TweakSpeeds (double &forwardmove, double &sidemove); void MorphPlayerThink (); void ActivateMorphWeapon (); diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index ae6ba5b000..ad2da961d4 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -2744,7 +2744,7 @@ class CommandDrawBar : public SBarInfoCommand max = 0; } else //default to the class's health - max = statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->mo->stamina; + max = statusBar->CPlayer->mo->GetMaxHealth(true); break; case ARMOR: value = statusBar->armor != NULL ? statusBar->armor->Amount : 0; @@ -3251,7 +3251,7 @@ class CommandDrawGem : public SBarInfoCommand void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { goalValue = armor ? (statusBar->armor ? statusBar->armor->Amount : 0) : statusBar->CPlayer->mo->health; - int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->mo->stamina; + int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth(true); if(max != 0 && goalValue > 0) { goalValue = (goalValue*100)/max; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 104a424711..b4affd5394 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1330,7 +1330,7 @@ bool P_GiveBody(AActor *actor, int num, int max) // calls while supporting health pickups. if (max <= 0) { - max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; + max = static_cast(actor)->GetMaxHealth(true); // [MH] First step in predictable generic morph effects if (player->morphTics) { diff --git a/src/p_user.cpp b/src/p_user.cpp index 7509e9bca4..ab4390ba2c 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1350,15 +1350,18 @@ const char *APlayerPawn::GetSoundClass() const // //=========================================================================== -int APlayerPawn::GetMaxHealth() const +int APlayerPawn::GetMaxHealth(bool withupgrades) const { - return MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth); + int ret = MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth); + if (withupgrades) ret += stamina; + return ret; } DEFINE_ACTION_FUNCTION(APlayerPawn, GetMaxHealth) { PARAM_SELF_PROLOGUE(APlayerPawn); - ACTION_RETURN_INT(self->GetMaxHealth()); + PARAM_BOOL_DEF(withupgrades); + ACTION_RETURN_INT(self->GetMaxHealth(withupgrades)); } //=========================================================================== @@ -2869,7 +2872,7 @@ void P_PlayerThink (player_t *player) // Apply degeneration. if (dmflags2 & DF2_YES_DEGENERATION) { - int maxhealth = player->mo->GetMaxHealth() + player->mo->stamina; + int maxhealth = player->mo->GetMaxHealth(true); if ((level.time % TICRATE) == 0 && player->health > maxhealth) { if (player->health - 5 < maxhealth) diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 0b60e3d51a..97e065c2ab 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -166,7 +166,7 @@ class PlayerPawn : Actor native return -1, -1; } - native int GetMaxHealth(); + native int GetMaxHealth(bool withupgrades = false); native bool ResetAirSupply (bool playgasp = false); native void CheckWeaponSwitch(class item); native static String GetPrintableDisplayName(Class cls); diff --git a/wadsrc/static/zscript/shared/player_cheat.txt b/wadsrc/static/zscript/shared/player_cheat.txt index 2aaa01ba87..15bad043cf 100644 --- a/wadsrc/static/zscript/shared/player_cheat.txt +++ b/wadsrc/static/zscript/shared/player_cheat.txt @@ -76,7 +76,7 @@ extend class PlayerPawn } else { - player.health = health = GetMaxHealth(); + player.health = health = GetMaxHealth(true); } } From 05836916708c458d58c2ac2ce96b24a1bcd891d1 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Sun, 19 Feb 2017 06:08:50 -0800 Subject: [PATCH 183/207] Add bash-style console shortcuts --- src/c_console.cpp | 153 +++++++++++++++++++++++++++++++++++++- src/posix/sdl/i_input.cpp | 8 +- src/zstring.cpp | 1 - 3 files changed, 157 insertions(+), 5 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 0b1e582874..17e46e182e 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -206,6 +206,9 @@ struct FCommandBuffer unsigned CursorPos; unsigned StartPos; // First character to display + FString YankBuffer; // Deleted text buffer + bool AppendToYankBuffer; // Append consecutive deletes to buffer + FCommandBuffer() { CursorPos = StartPos = 0; @@ -278,6 +281,30 @@ struct FCommandBuffer StartPos = MAX(0, n); } + unsigned WordBoundaryRight() + { + unsigned index = CursorPos; + while (index < Text.Len() && Text[index] == ' ') { + index++; + } + while (index < Text.Len() && Text[index] != ' ') { + index++; + } + return index; + } + + unsigned WordBoundaryLeft() + { + int index = CursorPos - 1; + while (index > -1 && Text[index] == ' ') { + index--; + } + while (index > -1 && Text[index] != ' ') { + index--; + } + return (unsigned)index + 1; + } + void CursorStart() { CursorPos = 0; @@ -309,6 +336,18 @@ struct FCommandBuffer } } + void CursorWordLeft() + { + CursorPos = WordBoundaryLeft(); + MakeStartPosGood(); + } + + void CursorWordRight() + { + CursorPos = WordBoundaryRight(); + MakeStartPosGood(); + } + void DeleteLeft() { if (CursorPos > 0) @@ -328,6 +367,50 @@ struct FCommandBuffer } } + void DeleteWordLeft() + { + if (CursorPos > 0) + { + unsigned index = WordBoundaryLeft(); + if (AppendToYankBuffer) { + YankBuffer = FString(&Text[index], CursorPos - index) + YankBuffer; + } else { + YankBuffer = FString(&Text[index], CursorPos - index); + } + Text.Remove(index, CursorPos - index); + CursorPos = index; + MakeStartPosGood(); + } + } + + void DeleteLineLeft() + { + if (CursorPos > 0) + { + if (AppendToYankBuffer) { + YankBuffer = FString(&Text[0], CursorPos) + YankBuffer; + } else { + YankBuffer = FString(&Text[0], CursorPos); + } + Text.Remove(0, CursorPos); + CursorStart(); + } + } + + void DeleteLineRight() + { + if (CursorPos < Text.Len()) + { + if (AppendToYankBuffer) { + YankBuffer += FString(&Text[CursorPos], Text.Len() - CursorPos); + } else { + YankBuffer = FString(&Text[CursorPos], Text.Len() - CursorPos); + } + Text.Truncate(CursorPos); + CursorEnd(); + } + } + void AddChar(int character) { ///FIXME: Not Unicode-aware @@ -1345,6 +1428,7 @@ DEFINE_ACTION_FUNCTION(_Console, Printf) static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) { int data1 = ev->data1; + bool keepappending = false; switch (ev->subtype) { @@ -1352,8 +1436,22 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) return false; case EV_GUI_Char: + if (ev->data2) + { + // Bash-style shortcuts + if (data1 == 'b') + { + buffer.CursorWordLeft(); + break; + } + else if (data1 == 'f') + { + buffer.CursorWordRight(); + break; + } + } // Add keypress to command line - buffer.AddChar(ev->data1); + buffer.AddChar(data1); HistPos = NULL; TabbedLast = false; TabbedList = false; @@ -1654,6 +1752,56 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) break; } break; + + // Bash-style shortcuts + case 'A': + if (ev->data3 & GKM_CTRL) + { + buffer.CursorStart(); + } + break; + case 'E': + if (ev->data3 & GKM_CTRL) + { + buffer.CursorEnd(); + } + break; + case 'W': + if (ev->data3 & GKM_CTRL) + { + buffer.DeleteWordLeft(); + keepappending = true; + TabbedLast = false; + TabbedList = false; + } + break; + case 'U': + if (ev->data3 & GKM_CTRL) + { + buffer.DeleteLineLeft(); + keepappending = true; + TabbedLast = false; + TabbedList = false; + } + break; + case 'K': + if (ev->data3 & GKM_CTRL) + { + buffer.DeleteLineRight(); + keepappending = true; + TabbedLast = false; + TabbedList = false; + } + break; + case 'Y': + if (ev->data3 & GKM_CTRL) + { + buffer.AddString(buffer.YankBuffer); + TabbedLast = false; + TabbedList = false; + HistPos = NULL; + } + break; } break; @@ -1664,6 +1812,9 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) break; #endif } + + buffer.AppendToYankBuffer = keepappending; + // Ensure that the cursor is always visible while typing CursorTicker = C_BLINKRATE; cursoron = 1; diff --git a/src/posix/sdl/i_input.cpp b/src/posix/sdl/i_input.cpp index 759da062cd..57ea03d928 100644 --- a/src/posix/sdl/i_input.cpp +++ b/src/posix/sdl/i_input.cpp @@ -395,9 +395,10 @@ void MessagePump (const SDL_Event &sev) { event.type = EV_GUI_Event; event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp; - event.data3 = ((sev.key.keysym.mod & KMOD_SHIFT) ? GKM_SHIFT : 0) | - ((sev.key.keysym.mod & KMOD_CTRL) ? GKM_CTRL : 0) | - ((sev.key.keysym.mod & KMOD_ALT) ? GKM_ALT : 0); + SDL_Keymod kmod = SDL_GetModState(); + event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((kmod & KMOD_ALT) ? GKM_ALT : 0); if (event.subtype == EV_GUI_KeyDown) { @@ -458,6 +459,7 @@ void MessagePump (const SDL_Event &sev) event.type = EV_GUI_Event; event.subtype = EV_GUI_Char; event.data1 = sev.text.text[0]; + event.data2 = !!(SDL_GetModState() & KMOD_ALT); D_PostEvent (&event); } break; diff --git a/src/zstring.cpp b/src/zstring.cpp index 83a2a20d81..a74edd01b5 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -393,7 +393,6 @@ void FString::Remove(size_t index, size_t remlen) } else { - remlen = Len() - remlen < remlen ? Len() - remlen : remlen; if (Data()->RefCount == 1) { // Can do this in place memmove(Chars + index, Chars + index + remlen, Len() - index - remlen); From b5d4a5946524cb7b23893c2a2eff9bb11be3ddca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Mar 2017 20:09:50 +0100 Subject: [PATCH 184/207] - fixed: Meta properties must not be serialized. --- src/dobjtype.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index cd128b6560..c8a89e9551 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2307,7 +2307,7 @@ void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArrayFlags & VARF_Transient)) + if (!(field->Flags & (VARF_Transient|VARF_Meta))) { field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const BYTE *)addr + field->Offset); } @@ -2340,6 +2340,11 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", label, TypeName.GetChars()); } + else if ((static_cast(sym)->Flags & (VARF_Transient | VARF_Meta))) + { + DPrintf(DMSG_ERROR, "Symbol %s in %s is not a serializable field\n", + label, TypeName.GetChars()); + } else { readsomething |= static_cast(sym)->Type->ReadValue(ar, nullptr, @@ -2638,7 +2643,7 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * // Don't write this part if it has no non-transient variables for (unsigned i = 0; i < type->Fields.Size(); ++i) { - if (!(type->Fields[i]->Flags & VARF_Transient)) + if (!(type->Fields[i]->Flags & (VARF_Transient|VARF_Meta))) { // Tag this section with the class it came from in case // a more-derived class has variables that shadow a less- From 0de79042d4b388cf4e23478d661eb6f28e385719 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Mar 2017 20:20:46 +0100 Subject: [PATCH 185/207] - fixed: 'Bloodtype' cannot use the generic property definition because it needs special handling for optional arguments. This reinstates the native handler. --- src/scripting/thingdef_properties.cpp | 27 +++++++++++++++++++++++++++ wadsrc/static/zscript/actor.txt | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index e41523b8cf..af79e1d04c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1059,6 +1059,33 @@ DEFINE_PROPERTY(bloodcolor, C, Actor) static_cast(info)->BloodColor = pe; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(bloodtype, Sss, Actor) +{ + PROP_STRING_PARM(str, 0) + PROP_STRING_PARM(str1, 1) + PROP_STRING_PARM(str2, 2) + + FName blood = str; + // normal blood + defaults->NameVar("BloodType") = blood; + + if (PROP_PARM_COUNT > 1) + { + blood = str1; + } + // blood splatter + defaults->NameVar("BloodType2") = blood; + + if (PROP_PARM_COUNT > 2) + { + blood = str2; + } + // axe blood + defaults->NameVar("BloodType3") = blood; +} //========================================================================== // diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 97e2bf6bb8..4c62863df4 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -224,7 +224,7 @@ class Actor : Thinker native Property DontHurtShooter: DontHurtShooter; Property ExplosionRadius: ExplosionRadius; Property ExplosionDamage: ExplosionDamage; - Property BloodType: BloodType, BloodType2, BloodType3; + //Property BloodType: BloodType, BloodType2, BloodType3; Property FastSpeed: FastSpeed; Property HowlSound: HowlSound; Property GibHealth: GibHealth; From 9b2f31e69292c79c989955a70f2bcc243fd2d143 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Mar 2017 20:54:37 +0100 Subject: [PATCH 186/207] - had to add a hack because some people had to exploit implementation-dependent behavior of the PulseLight type. --- src/dobjtype.cpp | 1 - src/gl/dynlights/a_dynlight.cpp | 3 ++- src/gl/dynlights/gl_dynlight.cpp | 28 ++++++++++++++++++---------- src/gl/dynlights/gl_dynlight.h | 1 + 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c8a89e9551..a2a5a6883b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3402,7 +3402,6 @@ PClass *PClass::FindClassTentative(FName name) PClass *type = static_cast(GetClass()->CreateNew()); DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); - assert(MetaSize == 0); Derive(type, name); type->Size = TentativeClass; TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket); diff --git a/src/gl/dynlights/a_dynlight.cpp b/src/gl/dynlights/a_dynlight.cpp index 1255401ae9..bd25752165 100644 --- a/src/gl/dynlights/a_dynlight.cpp +++ b/src/gl/dynlights/a_dynlight.cpp @@ -204,7 +204,8 @@ void ADynamicLight::Activate(AActor *activator) float pulseTime = specialf1 / TICRATE; m_lastUpdate = level.maptime; - m_cycler.SetParams(float(args[LIGHT_SECONDARY_INTENSITY]), float(args[LIGHT_INTENSITY]), pulseTime); + if (!swapped) m_cycler.SetParams(float(args[LIGHT_SECONDARY_INTENSITY]), float(args[LIGHT_INTENSITY]), pulseTime); + else m_cycler.SetParams(float(args[LIGHT_INTENSITY]), float(args[LIGHT_SECONDARY_INTENSITY]), pulseTime); m_cycler.ShouldCycle(true); m_cycler.SetCycleType(CYCLE_Sin); m_currentRadius = m_cycler.GetVal(); diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index 5ce79fd09a..4b0eac499d 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -135,6 +135,16 @@ public: void SetDontLightSelf(bool add) { m_dontlightself = add; } void SetAttenuate(bool on) { m_attenuate = on; } void SetHalo(bool halo) { m_halo = halo; } + + void OrderIntensities() + { + if (m_Args[LIGHT_INTENSITY] > m_Args[LIGHT_SECONDARY_INTENSITY]) + { + std::swap(m_Args[LIGHT_INTENSITY], m_Args[LIGHT_SECONDARY_INTENSITY]); + m_swapped = true; + } + } + protected: FName m_Name; int m_Args[5]; @@ -143,6 +153,7 @@ protected: ELightType m_type; int8_t m_attenuate; bool m_subtractive, m_additive, m_halo, m_dontlightself; + bool m_swapped = false; }; TArray LightDefaults; @@ -178,8 +189,8 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const light->SetOffset(m_Pos); light->halo = m_halo; for (int a = 0; a < 3; a++) light->args[a] = clamp((int)(m_Args[a]), 0, 255); - light->args[LIGHT_INTENSITY] = int(m_Args[LIGHT_INTENSITY]); - light->args[LIGHT_SECONDARY_INTENSITY] = int(m_Args[LIGHT_SECONDARY_INTENSITY]); + light->args[LIGHT_INTENSITY] = m_Args[LIGHT_INTENSITY]; + light->args[LIGHT_SECONDARY_INTENSITY] = m_Args[LIGHT_SECONDARY_INTENSITY]; light->flags4 &= ~(MF4_ADDITIVE | MF4_SUBTRACTIVE | MF4_DONTLIGHTSELF); if (m_subtractive) light->flags4 |= MF4_SUBTRACTIVE; if (m_additive) light->flags4 |= MF4_ADDITIVE; @@ -190,11 +201,13 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const float pulseTime = float(m_Param / TICRATE); light->m_lastUpdate = level.maptime; - light->m_cycler.SetParams(float(light->args[LIGHT_SECONDARY_INTENSITY]), float(light->args[LIGHT_INTENSITY]), pulseTime, oldtype == PulseLight); + if (m_swapped) light->m_cycler.SetParams(float(light->args[LIGHT_SECONDARY_INTENSITY]), float(light->args[LIGHT_INTENSITY]), pulseTime, oldtype == PulseLight); + else light->m_cycler.SetParams(float(light->args[LIGHT_INTENSITY]), float(light->args[LIGHT_SECONDARY_INTENSITY]), pulseTime, oldtype == PulseLight); light->m_cycler.ShouldCycle(true); light->m_cycler.SetCycleType(CYCLE_Sin); light->m_currentRadius = light->m_cycler.GetVal(); if (light->m_currentRadius <= 0) light->m_currentRadius = 1; + light->swapped = m_swapped; } switch (m_attenuate) @@ -474,13 +487,7 @@ void gl_ParsePulseLight(FScanner &sc) sc.ScriptError("Unknown tag: %s\n", sc.String); } } - if (defaults->GetArg(LIGHT_INTENSITY) > defaults->GetArg(LIGHT_SECONDARY_INTENSITY)) - { - auto i = defaults->GetArg(LIGHT_INTENSITY); - auto j = defaults->GetArg(LIGHT_SECONDARY_INTENSITY); - defaults->SetArg(LIGHT_INTENSITY, j); - defaults->SetArg(LIGHT_SECONDARY_INTENSITY, i); - } + defaults->OrderIntensities(); gl_AddLightDefaults(defaults); } @@ -564,6 +571,7 @@ void gl_ParseFlickerLight(FScanner &sc) sc.ScriptError("Unknown tag: %s\n", sc.String); } } + defaults->OrderIntensities(); gl_AddLightDefaults(defaults); } else diff --git a/src/gl/dynlights/gl_dynlight.h b/src/gl/dynlights/gl_dynlight.h index ee581e74a7..4733d853f4 100644 --- a/src/gl/dynlights/gl_dynlight.h +++ b/src/gl/dynlights/gl_dynlight.h @@ -141,6 +141,7 @@ public: bool halo; BYTE color2[3]; bool visibletoplayer; + bool swapped; int bufferindex; From 3c21ca9cb18e240b2503cb255e02f452f71774e3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Mar 2017 22:06:39 +0100 Subject: [PATCH 187/207] - added a compatibility option to move vertices and applied it to E1M6 of Masters of Chaos. This map has a door/lift combination that could trap the player without any chance to get out because both elements are so close together that it was almost impossible to trigger the lift. Moved two vertices by one map unit to make enough room. --- src/compatibility.cpp | 25 ++++++++++++++++++++++++- wadsrc/static/compatibility.txt | 6 ++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 0b27a1efa0..37531d40fa 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -86,6 +86,7 @@ enum CP_SETTHINGZ, CP_SETTAG, CP_SETTHINGFLAGS, + CP_SETVERTEX, }; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -345,7 +346,19 @@ void ParseCompatibility() sc.MustGetNumber(); CompatParams.Push(sc.Number); } - else + else if (sc.Compare("setvertex")) + { + if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); + CompatParams.Push(CP_SETVERTEX); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + sc.MustGetFloat(); + CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels + sc.MustGetFloat(); + CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels + flags.CompatFlags[SLOT_BCOMPAT] |= BCOMPATF_REBUILDNODES; + } + else { sc.UnGet(); break; @@ -600,6 +613,16 @@ void SetCompatibilityParams() i += 3; break; } + case CP_SETVERTEX: + { + if ((unsigned)CompatParams[i + 1] < level.vertexes.Size()) + { + level.vertexes[CompatParams[i + 1]].p.X = CompatParams[i + 2] / 256.; + level.vertexes[CompatParams[i + 1]].p.Y = CompatParams[i + 3] / 256.; + } + i += 4; + break; + } } } } diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 020d8477d6..9f7564b95f 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -497,6 +497,12 @@ ABC4EB5A1535ECCD0061AD14F3547908 // Plutonia Experiment, map26 setsectorspecial 156 0 } +B68EB7CFB4CC481796E2919B9C16DFBD // Moc11.wad e1m6 +{ + setvertex 1650 -3072 2671 + setvertex 1642 -2944 2671 +} + 712BB4CFBD0753178CA0C6814BE4C288 // map12 BTSX_E1 - patch some rendering glitches that are problematic to detect { setsectortag 545 32000 From 384accbc860b46a5293784572421c649b067204c Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 2 Mar 2017 10:12:11 +0200 Subject: [PATCH 188/207] Fixed name and placement of 'All except doors' localized string --- wadsrc/static/language.eng | 1 - wadsrc/static/language.enu | 1 + wadsrc/static/menudef.txt | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/language.eng b/wadsrc/static/language.eng index 66757cee70..bf0a0a91d6 100644 --- a/wadsrc/static/language.eng +++ b/wadsrc/static/language.eng @@ -106,7 +106,6 @@ CMPTMNU_RENDERINGBEHAVIOR = "Rendering Behaviour"; CMPTMNU_SOUNDBEHAVIOR = "Sound Behaviour"; CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only"; -OPTVAL_NODOORS = "All except doors"; C_GRAY = "\ccgrey"; C_DARKGRAY = "\cudark grey"; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 64cf4034bf..55477ee2e2 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2286,6 +2286,7 @@ OPTVAL_FRONT = "Front"; OPTVAL_ANIMATED = "Animated"; OPTVAL_ROTATED = "Rotated"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colors only"; +OPTVAL_NODOORS = "All except doors"; OPTVAL_DOUBLE = "Double"; OPTVAL_TRIPLE = "Triple"; OPTVAL_QUADRUPLE = "Quadruple"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index b66b381bad..2dd3e5e559 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1014,7 +1014,7 @@ OptionValue MapBackTypes OptionValue MapTriggers { 0, "$OPTVAL_OFF" - 1, "$OPTVAL_NO_DOORS" + 1, "$OPTVAL_NODOORS" 2, "$OPTVAL_ON" } From 59bd4d608c767e8a9234268009736d285de5f9c5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 09:59:25 +0100 Subject: [PATCH 189/207] - fixed: Be a bit more paranoid about what to consider a mod with an empty top-level directory. This should only be accepted if the subdirectory contains at least one identifiable game definition lump to avoid catching some patch mods with only a few files. --- src/resourcefiles/file_zip.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index bd2990dec3..7b83084ab8 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -218,8 +218,11 @@ bool FZipFile::Open(bool quiet) char *dirptr = (char*)directory; FZipLump *lump_p = Lumps; - // Check if all files have the same prefix so that this can be stripped out. FString name0; + bool foundspeciallump = false; + + // Check if all files have the same prefix so that this can be stripped out. + // This will only be done if there is either a MAPINFO, ZMAPINFO or GAMEINFO lump in the subdirectory, denoting a ZDoom mod. if (NumLumps > 1) for (DWORD i = 0; i < NumLumps; i++) { FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; @@ -251,6 +254,7 @@ bool FZipFile::Open(bool quiet) !name.Compare("voxels/") || !name.Compare("colormaps/") || !name.Compare("acs/") || + !name.Compare("maps/") || !name.Compare("voices/") || !name.Compare("patches/") || !name.Compare("graphics/") || @@ -266,6 +270,23 @@ bool FZipFile::Open(bool quiet) name0 = ""; break; } + else if (!foundspeciallump) + { + // at least one of the more common definition lumps must be present. + if (name.IndexOf(name0 + "mapinfo") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "zmapinfo") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "gameinfo") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "sndinfo") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "sbarinfo") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "menudef") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "gldefs") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "animdefs") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "decorate.") == 0) foundspeciallump = true; // DECORATE is a common subdirectory name, so the check needs to be a bit different. + else if (name.Compare(name0 + "decorate") == 0) foundspeciallump = true; + else if (name.IndexOf(name0 + "zscript.") == 0) foundspeciallump = true; // same here. + else if (name.Compare(name0 + "zscript") == 0) foundspeciallump = true; + else if (name.Compare(name0 + "maps/") == 0) foundspeciallump = true; + } } } From 00dc59ebdce8405578e950324028ddef505ccb11 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 10:26:23 +0100 Subject: [PATCH 190/207] - separated the blood translation index from the BloodColor variable to allow more than 255 blood translations and as a prerequisite for allowing to change the blood color. --- src/actor.h | 7 ++--- src/info.cpp | 1 - src/info.h | 2 -- src/p_actionfunctions.cpp | 3 +- src/p_map.cpp | 9 +++--- src/p_mobj.cpp | 42 ++++++++++++--------------- src/scripting/thingdef_properties.cpp | 7 ++--- wadsrc/static/zscript/actor.txt | 3 +- 8 files changed, 30 insertions(+), 44 deletions(-) diff --git a/src/actor.h b/src/actor.h index 739f08f4ab..5cac230115 100644 --- a/src/actor.h +++ b/src/actor.h @@ -807,11 +807,6 @@ public: return (flags & MF_COUNTKILL) && !(flags & MF_FRIENDLY); } - PalEntry GetBloodColor() const - { - return GetClass()->BloodColor; - } - // These also set CF_INTERPVIEW for players. void SetPitch(DAngle p, bool interpolate, bool forceclamp = false); void SetAngle(DAngle ang, bool interpolate); @@ -1144,6 +1139,8 @@ public: BYTE FloatBobPhase; BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) DWORD Translation; + PalEntry BloodColor; + DWORD BloodTranslation; // [RH] Stuff that used to be part of an Actor Info FSoundIDNoInit SeeSound; diff --git a/src/info.cpp b/src/info.cpp index d51cad1155..fdda8633e2 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -295,7 +295,6 @@ void PClassActor::DeriveData(PClass *newclass) PClassActor *newa = static_cast(newclass); newa->DefaultStateUsage = DefaultStateUsage; - newa->BloodColor = BloodColor; newa->distancecheck = distancecheck; newa->DropItems = DropItems; diff --git a/src/info.h b/src/info.h index d5e3eff481..6caa273254 100644 --- a/src/info.h +++ b/src/info.h @@ -290,8 +290,6 @@ public: TArray VisibleToPlayerClass; - PalEntry BloodColor; // Colorized blood - FDropItem *DropItems; FString SourceLumpName; FIntCVar *distancecheck; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index b75949f01b..c32372b4e3 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -2580,8 +2580,7 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) else if (flags & SIXF_USEBLOODCOLOR) { // [XA] Use the spawning actor's BloodColor to translate the newly-spawned object. - PalEntry bloodcolor = self->GetBloodColor(); - mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + mo->Translation = self->BloodTranslation; } } if (flags & SIXF_TRANSFERPOINTERS) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7e110dcbf4..4d47b89c19 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4803,7 +4803,7 @@ void P_TraceBleed(int damage, const DVector3 &pos, AActor *actor, DAngle angle, { if (bleedtrace.HitType == TRACE_HitWall) { - PalEntry bloodcolor = actor->GetBloodColor(); + PalEntry bloodcolor = actor->BloodColor; if (bloodcolor != 0) { bloodcolor.r >>= 1; // the full color is too bright for blood decals @@ -5994,7 +5994,6 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) { if (!(thing->flags&MF_NOBLOOD)) { - PalEntry bloodcolor = thing->GetBloodColor(); PClassActor *bloodcls = thing->GetBloodType(); P_TraceBleed (newdam > 0 ? newdam : cpos->crushchange, thing); @@ -6006,9 +6005,9 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) mo->Vel.X = pr_crunch.Random2() / 16.; mo->Vel.Y = pr_crunch.Random2() / 16.; - if (bloodcolor != 0 && !(mo->flags2 & MF2_DONTTRANSLATE)) + if (thing->BloodTranslation != 0 && !(mo->flags2 & MF2_DONTTRANSLATE)) { - mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + mo->Translation = thing->BloodTranslation; } if (!(cl_bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE; @@ -6017,7 +6016,7 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos) DAngle an = (M_Random() - 128) * (360./256); if (cl_bloodtype >= 1) { - P_DrawSplash2(32, thing->PosPlusZ(thing->Height/2), an, 2, bloodcolor); + P_DrawSplash2(32, thing->PosPlusZ(thing->Height/2), an, 2, thing->BloodColor); } } if (thing->CrushPainSound != 0 && !S_GetSoundPlayingInfo(thing, thing->CrushPainSound)) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b4affd5394..db8964ef4f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -316,8 +316,8 @@ DEFINE_FIELD(AActor, RadiusDamageFactor) DEFINE_FIELD(AActor, SelfDamageFactor) DEFINE_FIELD(AActor, StealthAlpha) DEFINE_FIELD(AActor, WoundHealth) - -//DEFINE_FIELD(PClassActor, BloodColor) +DEFINE_FIELD(AActor, BloodColor) +DEFINE_FIELD(AActor, BloodTranslation) //========================================================================== // @@ -409,6 +409,8 @@ void AActor::Serialize(FSerializer &arc) A("inventoryid", InventoryID) A("floatbobphase", FloatBobPhase) A("translation", Translation) + A("bloodcolor", BloodColor) + A("bloodtranslation", BloodTranslation) A("seesound", SeeSound) A("attacksound", AttackSound) A("paimsound", PainSound) @@ -1665,8 +1667,7 @@ bool AActor::Grind(bool items) if (isgeneric) // Not a custom crush state, so colorize it appropriately. { S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); - PalEntry bloodcolor = GetBloodColor(); - if (bloodcolor!=0) Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + Translation = BloodTranslation; } return false; } @@ -1707,10 +1708,7 @@ bool AActor::Grind(bool items) gib->Alpha = Alpha; gib->Height = 0; gib->radius = 0; - - PalEntry bloodcolor = GetBloodColor(); - if (bloodcolor != 0) - gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + gib->Translation = BloodTranslation; } S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); } @@ -6051,7 +6049,6 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnPuff) void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *originator) { AActor *th; - PalEntry bloodcolor = originator->GetBloodColor(); PClassActor *bloodcls = originator->GetBloodType(); DVector3 pos = pos1; pos.Z += pr_spawnblood.Random2() / 64.; @@ -6076,9 +6073,9 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina th->tics = 1; } // colorize the blood - if (bloodcolor != 0 && !(th->flags2 & MF2_DONTTRANSLATE)) + if (!(th->flags2 & MF2_DONTTRANSLATE)) { - th->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + th->Translation = originator->BloodTranslation; } // Moved out of the blood actor so that replacing blood is easier @@ -6135,7 +6132,7 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina } if (bloodtype >= 1) - P_DrawSplash2 (40, pos, dir, 2, bloodcolor); + P_DrawSplash2 (40, pos, dir, 2, originator->BloodColor); } DEFINE_ACTION_FUNCTION(AActor, SpawnBlood) @@ -6159,7 +6156,6 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnBlood) void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle) { - PalEntry bloodcolor = originator->GetBloodColor(); PClassActor *bloodcls = originator->GetBloodType(1); int bloodtype = cl_bloodtype; @@ -6178,16 +6174,16 @@ void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle) mo->Vel.Z = 3; // colorize the blood! - if (bloodcolor!=0 && !(mo->flags2 & MF2_DONTTRANSLATE)) + if (!(mo->flags2 & MF2_DONTTRANSLATE)) { - mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + mo->Translation = originator->BloodTranslation; } if (!(bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE; } if (bloodtype >= 1) { - P_DrawSplash2 (40, pos, hitangle-180., 2, bloodcolor); + P_DrawSplash2 (40, pos, hitangle-180., 2, originator->BloodColor); } } @@ -6199,7 +6195,6 @@ void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle) void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle) { - PalEntry bloodcolor = originator->GetBloodColor(); PClassActor *bloodcls = originator->GetBloodType(2); int bloodtype = cl_bloodtype; @@ -6220,16 +6215,16 @@ void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle) mo->target = originator; // colorize the blood! - if (bloodcolor != 0 && !(mo->flags2 & MF2_DONTTRANSLATE)) + if (!(mo->flags2 & MF2_DONTTRANSLATE)) { - mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + mo->Translation = originator->BloodTranslation; } if (!(bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE; } if (bloodtype >= 1) { - P_DrawSplash2(40, pos + add, hitangle - 180., 2, bloodcolor); + P_DrawSplash2(40, pos + add, hitangle - 180., 2, originator->BloodColor); } } @@ -6255,7 +6250,6 @@ DEFINE_ACTION_FUNCTION(AActor, BloodSplatter) void P_RipperBlood (AActor *mo, AActor *bleeder) { - PalEntry bloodcolor = bleeder->GetBloodColor(); PClassActor *bloodcls = bleeder->GetBloodType(); double xo = pr_ripperblood.Random2() / 16.; @@ -6281,16 +6275,16 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) th->tics += pr_ripperblood () & 3; // colorize the blood! - if (bloodcolor!=0 && !(th->flags2 & MF2_DONTTRANSLATE)) + if (!(th->flags2 & MF2_DONTTRANSLATE)) { - th->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + th->Translation = bleeder->BloodTranslation; } if (!(bloodtype <= 1)) th->renderflags |= RF_INVISIBLE; } if (bloodtype >= 1) { - P_DrawSplash2(28, pos, bleeder->AngleTo(mo) + 180., 0, bloodcolor); + P_DrawSplash2(28, pos, bleeder->AngleTo(mo) + 180., 0, bleeder->BloodColor); } } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index af79e1d04c..6212f0ff1d 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1053,10 +1053,9 @@ DEFINE_PROPERTY(bloodcolor, C, Actor) { PROP_COLOR_PARM(color, 0); - PalEntry pe = color; - pe.a = CreateBloodTranslation(pe); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->BloodColor = pe; + defaults->BloodColor = color; + defaults->BloodColor.a = 255; // a should not be 0. + defaults->BloodTranslation = TRANSLATION(TRANSLATION_Blood, CreateBloodTranslation(color)); } //========================================================================== diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 4c62863df4..148fd4bd5e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -194,7 +194,8 @@ class Actor : Thinker native native double SelfDamageFactor; native double StealthAlpha; native int WoundHealth; // Health needed to enter wound state - //native color BloodColor; // won't be accessible for now because it needs refactoring to remove the 255-translations limit. + native readonly color BloodColor; + native readonly int BloodTranslation; meta String Obituary; // Player was killed by this actor meta String HitObituary; // Player was killed by this actor in melee From b194ba205ac8752593b4101bc3c7cbd0e9f72a99 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 11:39:52 +0100 Subject: [PATCH 191/207] - backported Zandronum's MaxHealth base class for the MaxHealthBonus item. --- src/d_player.h | 2 ++ src/p_acs.cpp | 4 +-- src/p_mobj.cpp | 4 +-- src/p_user.cpp | 4 ++- wadsrc/static/zscript/inventory/health.txt | 30 +++++++++++++++++++++- wadsrc/static/zscript/shared/player.txt | 1 + 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 2787df231d..379265cab1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -125,6 +125,8 @@ public: int crouchsprite; int MaxHealth; + int BonusHealth; + int MugShotMaxHealth; int RunHealth; int PlayerFlags; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 5ea7dfa075..4e1b7a026b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1330,7 +1330,7 @@ static int CheckInventory (AActor *activator, const char *type, bool max) if (max) { if (activator->IsKindOf (RUNTIME_CLASS (APlayerPawn))) - return static_cast(activator)->MaxHealth; + return static_cast(activator)->GetMaxHealth(); else return activator->SpawnHealth(); } @@ -3939,7 +3939,7 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_Dormant: return !!(actor->flags2 & MF2_DORMANT); case APROP_SpawnHealth: if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) { - return static_cast(actor)->MaxHealth; + return static_cast(actor)->GetMaxHealth(); } else { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index db8964ef4f..99f48a702c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1340,7 +1340,7 @@ bool P_GiveBody(AActor *actor, int num, int max) { if (!(player->MorphStyle & MORPH_ADDSTAMINA)) { - max -= player->mo->stamina; + max -= player->mo->stamina + player->mo->BonusHealth; } } else // old health behaviour @@ -1348,7 +1348,7 @@ bool P_GiveBody(AActor *actor, int num, int max) max = MAXMORPHHEALTH; if (player->MorphStyle & MORPH_ADDSTAMINA) { - max += player->mo->stamina; + max += player->mo->stamina + player->mo->BonusHealth; } } } diff --git a/src/p_user.cpp b/src/p_user.cpp index ab4390ba2c..9b65b559f8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -781,6 +781,7 @@ void APlayerPawn::Serialize(FSerializer &arc) arc("jumpz", JumpZ, def->JumpZ) ("maxhealth", MaxHealth, def->MaxHealth) + ("bonushealth", BonusHealth, def->BonusHealth) ("runhealth", RunHealth, def->RunHealth) ("spawnmask", SpawnMask, def->SpawnMask) ("forwardmove1", ForwardMove1, def->ForwardMove1) @@ -1353,7 +1354,7 @@ const char *APlayerPawn::GetSoundClass() const int APlayerPawn::GetMaxHealth(bool withupgrades) const { int ret = MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth); - if (withupgrades) ret += stamina; + if (withupgrades) ret += stamina + BonusHealth; return ret; } @@ -3345,6 +3346,7 @@ bool P_IsPlayerTotallyFrozen(const player_t *player) DEFINE_FIELD(APlayerPawn, crouchsprite) DEFINE_FIELD(APlayerPawn, MaxHealth) +DEFINE_FIELD(APlayerPawn, BonusHealth) DEFINE_FIELD(APlayerPawn, MugShotMaxHealth) DEFINE_FIELD(APlayerPawn, RunHealth) DEFINE_FIELD(APlayerPawn, PlayerFlags) diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt index e64bbfd4a9..986dc7069f 100644 --- a/wadsrc/static/zscript/inventory/health.txt +++ b/wadsrc/static/zscript/inventory/health.txt @@ -86,8 +86,36 @@ class Health : Inventory } return false; } +} - +class MaxHealth : Health +{ + //=========================================================================== + // + // TryPickup + // + //=========================================================================== + + override bool TryPickup (in out Actor other) + { + bool success = false; + int savedAmount = MaxAmount; + let player = PlayerPawn(other); + MaxAmount = Health; + if (player) + { + if (player.BonusHealth < savedAmount) + { + player.BonusHealth = min(player.BonusHealth + Amount, savedAmount); + success = true; + } + MaxAmount += player.BonusHealth; + } + success |= Super.TryPickup(other); + MaxAmount = saved; + if (success) GoAwayAndDie(); + return success; + } } class HealthPickup : Inventory diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 97e065c2ab..a802107141 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -3,6 +3,7 @@ class PlayerPawn : Actor native native int crouchsprite; native int MaxHealth; + native int BonusHealth; native int MugShotMaxHealth; native int RunHealth; native int PlayerFlags; From cfda1a49d427918ad94d873ac477a3fa5734694a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 11:58:30 +0100 Subject: [PATCH 192/207] - forgot to save the last fix for the previous commit. - let the script compiler also output the size of the allocated data for the script functions in addition to the actual code size. --- src/scripting/backend/vmbuilder.cpp | 6 +++++- wadsrc/static/zscript/inventory/health.txt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index 74f845248c..3be1000c59 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -846,6 +846,7 @@ void FFunctionBuildList::Build() { int errorcount = 0; int codesize = 0; + int datasize = 0; FILE *dump = nullptr; if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w"); @@ -927,6 +928,8 @@ void FFunctionBuildList::Build() { DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len()); codesize += sfunc->CodeSize; + datasize += sfunc->LineInfoCount * sizeof(FStatementInfo) + sfunc->ExtraSpace + sfunc->NumKonstD * sizeof(int) + + sfunc->NumKonstA * sizeof(void*) + sfunc->NumKonstF * sizeof(double) + sfunc->NumKonstS * sizeof(FString); } sfunc->Unsafe = ctx.Unsafe; } @@ -944,10 +947,11 @@ void FFunctionBuildList::Build() } if (dump != nullptr) { - fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); + fprintf(dump, "\n*************************************************************************\n%i code bytes\n%i data bytes", codesize * 4, datasize); fclose(dump); } FScriptPosition::StrictErrors = false; mItems.Clear(); + mItems.ShrinkToFit(); FxAlloc.FreeAllBlocks(); } \ No newline at end of file diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt index 986dc7069f..e69d85814d 100644 --- a/wadsrc/static/zscript/inventory/health.txt +++ b/wadsrc/static/zscript/inventory/health.txt @@ -112,7 +112,7 @@ class MaxHealth : Health MaxAmount += player.BonusHealth; } success |= Super.TryPickup(other); - MaxAmount = saved; + MaxAmount = savedAmount; if (success) GoAwayAndDie(); return success; } From 3532e5057548497c1aa964f6e410217e5a6f6aa4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 12:14:00 +0100 Subject: [PATCH 193/207] - check for RF_MASKROTATION before calling IsInsideVisibleAngles, because it is a bit faster this way. --- src/gl/scene/gl_sprite.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 5e8bdb560e..3a6abb3197 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -665,7 +665,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) bool isPicnumOverride = thing->picnum.isValid(); // Don't waste time projecting sprites that are definitely not visible. - if ((thing->sprite == 0 && !isPicnumOverride) || !thing->IsVisibleToPlayer() || !thing->IsInsideVisibleAngles()) + if ((thing->sprite == 0 && !isPicnumOverride) || !thing->IsVisibleToPlayer() || ((thing->renderflags & RF_MASKROTATION) && !thing->IsInsideVisibleAngles())) { return; } From 4dc0599a6c63a1c40fc854d2abe1f825aed0135b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 12:37:25 +0100 Subject: [PATCH 194/207] - did a bit of reordering AActor's variables to group the ones together which are accessed by the renderer. Tested with some actor-heavy maps this does provide a small, approx 3-4% speedup in the OpenGL sprite processing function. --- src/actor.h | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/actor.h b/src/actor.h index 5cac230115..4d1c7556bd 100644 --- a/src/actor.h +++ b/src/actor.h @@ -978,30 +978,43 @@ public: // NOTE: The first member variable *must* be snext. AActor *snext, **sprev; // links in sector (if needed) 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; - DAngle VisibleStartAngle; - DAngle VisibleStartPitch; - DAngle VisibleEndAngle; - DAngle VisibleEndPitch; DRotator Angles; - DVector3 Vel; - double Speed; - double FloatSpeed; + DVector2 Scale; // Scaling values; 1 is normal size int sprite; // used to find patch_t and flip value uint8_t frame; // sprite frame to draw uint8_t effects; // [RH] see p_effect.h uint8_t fountaincolor; // Split out of 'effect' to have easier access. - DVector2 Scale; // Scaling values; 1 is normal size FRenderStyle RenderStyle; // Style to draw this actor with ActorRenderFlags renderflags; // Different rendering flags FTextureID picnum; // Draw this instead of sprite if valid double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double. DWORD fillcolor; // Color to draw when STYLE_Shaded + ActorFlags flags; + ActorFlags2 flags2; // Heretic flags + ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable + ActorFlags4 flags4; // [RH] Even more flags! + ActorFlags5 flags5; // OMG! We need another one. + ActorFlags6 flags6; // Shit! Where did all the flags go? + ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? + double Floorclip; // value to use for floor clipping + DWORD Translation; + + + DAngle VisibleStartAngle; + DAngle VisibleStartPitch; + DAngle VisibleEndAngle; + DAngle VisibleEndPitch; + + DVector3 OldRenderPos; + DVector3 Vel; + double Speed; + double FloatSpeed; + // interaction info FBlockNode *BlockNode; // links in blocks (if needed) struct sector_t *Sector; @@ -1031,13 +1044,6 @@ public: int DamageVal; VMFunction *DamageFunc; int projectileKickback; - ActorFlags flags; - ActorFlags2 flags2; // Heretic flags - ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable - ActorFlags4 flags4; // [RH] Even more flags! - ActorFlags5 flags5; // OMG! We need another one. - ActorFlags6 flags6; // Shit! Where did all the flags go? - ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? // [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it. DWORD VisibleToTeam; @@ -1075,7 +1081,6 @@ public: TObjPtr alternative; // (Un)Morphed actors stored here. Those with the MF_UNMORPHED flag are the originals. TObjPtr tracer; // Thing being chased/attacked for tracers TObjPtr master; // Thing which spawned this one (prevents mutual attacks) - double Floorclip; // value to use for floor clipping int tid; // thing identifier int special; // special @@ -1138,7 +1143,6 @@ public: BYTE smokecounter; BYTE FloatBobPhase; BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) - DWORD Translation; PalEntry BloodColor; DWORD BloodTranslation; From ff88ecd3f00f4e8822cc1f10c4afd8eeadec841b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 12:55:04 +0100 Subject: [PATCH 195/207] - a bit more reordering for another minor performance gain. --- src/actor.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/actor.h b/src/actor.h index 4d1c7556bd..9fc1d10f12 100644 --- a/src/actor.h +++ b/src/actor.h @@ -983,17 +983,18 @@ public: DAngle SpriteRotation; DRotator Angles; DVector2 Scale; // Scaling values; 1 is normal size + double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double. int sprite; // used to find patch_t and flip value uint8_t frame; // sprite frame to draw uint8_t effects; // [RH] see p_effect.h uint8_t fountaincolor; // Split out of 'effect' to have easier access. FRenderStyle RenderStyle; // Style to draw this actor with - ActorRenderFlags renderflags; // Different rendering flags FTextureID picnum; // Draw this instead of sprite if valid - double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double. DWORD fillcolor; // Color to draw when STYLE_Shaded + DWORD Translation; + ActorRenderFlags renderflags; // Different rendering flags ActorFlags flags; ActorFlags2 flags2; // Heretic flags ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable @@ -1002,8 +1003,7 @@ public: ActorFlags6 flags6; // Shit! Where did all the flags go? ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? double Floorclip; // value to use for floor clipping - DWORD Translation; - + double radius, Height; // for movement checking DAngle VisibleStartAngle; DAngle VisibleStartPitch; @@ -1027,7 +1027,6 @@ public: int floorterrain; struct sector_t *ceilingsector; FTextureID ceilingpic; // contacted sec ceilingpic - double radius, Height; // for movement checking double renderradius; double projectilepassheight; // height for clipping projectile movement against this actor From 26f7902c3f5f9f6c007a2ce6731e31a877e31291 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Thu, 2 Mar 2017 06:27:18 -0500 Subject: [PATCH 196/207] - fixed: If player is killed by world, attacker was not checked for nullptr, causing a crash. --- src/p_interaction.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b4cb5d16f5..9629ccfe84 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -253,6 +253,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf } } if (message == nullptr) message = messagename; // fallback to defaults if possible. + if (attacker == nullptr) attacker = self; // world if (attacker->player == nullptr) attacker = self; // for the message creation if (message != NULL && message[0] == '$') From 62dd810a4edec42e1e9860531da11dcd0e75f6cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 13:09:25 +0100 Subject: [PATCH 197/207] - fixed: A_ProgrammerMelee damaged the caller, not the target. --- wadsrc/static/zscript/strife/programmer.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/strife/programmer.txt b/wadsrc/static/zscript/strife/programmer.txt index 3fa34b6595..90cdd53997 100644 --- a/wadsrc/static/zscript/strife/programmer.txt +++ b/wadsrc/static/zscript/strife/programmer.txt @@ -95,7 +95,7 @@ class Programmer : Actor A_PlaySound("programmer/clank", CHAN_WEAPON); int damage = ((random[Programmer]() % 10) + 1) * 6; - int newdam = DamageMobj (self, self, damage, 'Melee'); + int newdam = target.DamageMobj (self, self, damage, 'Melee'); target.TraceBleed (newdam > 0 ? newdam : damage, self); } From e64f1e645da0d3e9e1e9083a038dbc08f06f87ee Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 13:14:16 +0100 Subject: [PATCH 198/207] - exported constants for SetGlobalFogParameter to ZScript. --- wadsrc/static/zscript/constants.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index c15433cd63..1982c44727 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1005,6 +1005,13 @@ enum ERaise RF_NOCHECKPOSITION = 2 } +enum eFogParm +{ + FOGP_DENSITY = 0, + FOGP_OUTSIDEDENSITY = 1, + FOGP_SKYFOG = 2, +} + enum ETeleport { TELF_DESTFOG = 1, From 8253b91d9793ec8f1e63df980f5568014b0a8d87 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 18:18:34 +0100 Subject: [PATCH 199/207] - fixed: The stair and donut builders did not initialize FFloor::m_Instant. --- src/p_floor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 1bd0c53fce..8f7d935ee5 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -640,6 +640,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, floor->m_Delay = delay; floor->m_PauseTime = 0; floor->m_StepTime = floor->m_PerStepTime = persteptime; + floor->m_Instant = false; floor->m_Crush = (usespecials & DFloor::stairCrush) ? 10 : -1; //jff 2/27/98 fix uninitialized crush field floor->m_Hexencrush = false; @@ -755,6 +756,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, //jff 2/27/98 fix uninitialized crush field floor->m_Crush = (!(usespecials & DFloor::stairUseSpecials) && speed == 4) ? 10 : -1; //jff 2/27/98 fix uninitialized crush field floor->m_Hexencrush = false; + floor->m_Instant = false; floor->m_ResetCount = reset; // [RH] Tics until reset (0 if never) floor->m_OrgDist = sec->floorplane.fD(); // [RH] Height to reset to } @@ -817,6 +819,7 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed) floor->m_Direction = 1; floor->m_Sector = s2; floor->m_Speed = slimespeed; + floor->m_Instant = false; floor->m_Texture = s3->GetTexture(sector_t::floor); floor->m_NewSpecial.Clear(); height = s3->FindHighestFloorPoint (&spot); @@ -831,6 +834,7 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed) floor->m_Direction = -1; floor->m_Sector = s1; floor->m_Speed = pillarspeed; + floor->m_Instant = false; height = s3->FindHighestFloorPoint (&spot); floor->m_FloorDestDist = s1->floorplane.PointToDist (spot, height); floor->StartFloorSound (); From 1761da6079522e067388db438fc3418571619ec9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Mar 2017 18:40:01 +0100 Subject: [PATCH 200/207] - fixed: AActor::Howl checked HowlSound for the wrong type. --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 99f48a702c..1e2559ec58 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3508,7 +3508,7 @@ int AActor::GetMissileDamage (int mask, int add) void AActor::Howl () { - FSoundID howl = IntVar(NAME_HowlSound); + FSoundID howl = SoundVar(NAME_HowlSound); if (!S_IsActorPlayingSomething(this, CHAN_BODY, howl)) { S_Sound (this, CHAN_BODY, howl, 1, ATTN_NORM); From 6055f136d8a5afa952255ff30b29d44927cfdca3 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 3 Mar 2017 16:30:04 +0100 Subject: [PATCH 201/207] Make sure SwapInterval is only ever called while the default frame buffer is bound to avoid problems with some drivers --- src/gl/system/gl_framebuffer.cpp | 23 ++++++++++++++++++++++- src/gl/system/gl_framebuffer.h | 2 ++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 1a4582d801..864d796a81 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -83,7 +83,7 @@ OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int { // SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver. // If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed! - SetVSync(vid_vsync); + Super::SetVSync(vid_vsync); // Make sure all global variables tracking OpenGL context state are reset.. FHardwareTexture::InitGlobalState(); @@ -230,6 +230,27 @@ void OpenGLFrameBuffer::Swap() mDebug->Update(); } +//========================================================================== +// +// Enable/disable vertical sync +// +//========================================================================== + +void OpenGLFrameBuffer::SetVSync(bool vsync) +{ + // Switch to the default frame buffer because some drivers associate the vsync state with the bound FB object. + GLint oldDrawFramebufferBinding = 0, oldReadFramebufferBinding = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDrawFramebufferBinding); + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldReadFramebufferBinding); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + Super::SetVSync(vsync); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDrawFramebufferBinding); + glBindFramebuffer(GL_READ_FRAMEBUFFER, oldReadFramebufferBinding); +} + //=========================================================================== // // DoSetGamma diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 0eb289ffe1..d6306fcdf8 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -83,6 +83,8 @@ public: bool Is8BitMode() { return false; } bool IsHWGammaActive() const { return HWGammaActive; } + void SetVSync(bool vsync); + private: PalEntry Flash; From 7736e4274064fb358565d8e4658d0e3afc159f58 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 3 Mar 2017 18:53:11 +0100 Subject: [PATCH 202/207] - fixed: The respawn event handler was not called for a regular in-game respawn, only for a cheat resurrection. --- src/p_mobj.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 1e2559ec58..d7de2a18cc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5563,6 +5563,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) for (int ii=0; ii < BODYQUESIZE; ++ii) if (bodyque[ii] == p->mo) bodyque[ii] = oldactor; + E_PlayerRespawned(int(p - players)); FBehavior::StaticStartTypedScripts (SCRIPT_Respawn, p->mo, true); } } From 217bcb847d2a703ecf5fd302127feeac73b3fa3c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 3 Mar 2017 19:19:19 +0100 Subject: [PATCH 203/207] - fixed: When the savegame code errors out, some cleanup is required in G_DoSaveGame. --- src/dobjtype.cpp | 3 +-- src/g_game.cpp | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index a2a5a6883b..98a893391b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1398,8 +1398,7 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con } else { - assert(0 && "Pointer points to a type we don't handle"); - I_Error("Attempt to save pointer to unhandled type"); + I_Error("Attempt to save pointer to unhandled type %s", PointedType->DescriptiveName()); } } diff --git a/src/g_game.cpp b/src/g_game.cpp index b39ee52a8d..4391a05710 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2270,7 +2270,29 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio I_FreezeTime(true); insave = true; - G_SnapshotLevel (); + try + { + G_SnapshotLevel(); + } + catch(CRecoverableError &err) + { + // delete the snapshot. Since the save failed it is broken. + insave = false; + level.info->Snapshot.Clean(); + Printf(PRINT_HIGH, "Save failed\n"); + Printf(PRINT_HIGH, "%s\n", err.GetMessage()); + // The time freeze must be reset if the save fails. + if (cl_waitforsave) + I_FreezeTime(false); + return; + } + catch (...) + { + insave = false; + if (cl_waitforsave) + I_FreezeTime(false); + throw; + } BufferWriter savepic; FSerializer savegameinfo; // this is for displayable info about the savegame From f563a296c2315b463387a864ed3902e5f720d33d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 3 Mar 2017 19:23:27 +0100 Subject: [PATCH 204/207] - added an ACS ScriptCall function. So far only superficially tested. --- src/p_acs.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 140 insertions(+), 24 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 4e1b7a026b..027b614ea1 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -180,7 +180,7 @@ inline int PitchToACS(DAngle ang) struct CallReturn { - CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway) + CallReturn(int pc, ScriptFunction *func, FBehavior *module, int32_t *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway) : ReturnFunction(func), ReturnModule(module), ReturnLocals(locals), @@ -192,7 +192,7 @@ struct CallReturn ScriptFunction *ReturnFunction; FBehavior *ReturnModule; - SDWORD *ReturnLocals; + int32_t *ReturnLocals; ACSLocalArrays *ReturnArrays; int ReturnAddress; int bDiscardResult; @@ -206,7 +206,7 @@ static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, cons struct FBehavior::ArrayInfo { DWORD ArraySize; - SDWORD *Elements; + int32_t *Elements; }; TArray FBehavior::StaticModules; @@ -243,11 +243,11 @@ inline int uallong(const int &foo) //============================================================================ // ACS variables with world scope -SDWORD ACS_WorldVars[NUM_WORLDVARS]; +int32_t ACS_WorldVars[NUM_WORLDVARS]; FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS]; // ACS variables with global scope -SDWORD ACS_GlobalVars[NUM_GLOBALVARS]; +int32_t ACS_GlobalVars[NUM_GLOBALVARS]; FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; //---------------------------------------------------------------------------- @@ -261,7 +261,7 @@ FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; struct FACSStack { - SDWORD buffer[STACK_SIZE]; + int32_t buffer[STACK_SIZE]; int sp; FACSStack *next; FACSStack *prev; @@ -979,7 +979,7 @@ void P_ClearACSVars(bool alsoglobal) // //============================================================================ -static void WriteVars (FSerializer &file, SDWORD *vars, size_t count, const char *key) +static void WriteVars (FSerializer &file, int32_t *vars, size_t count, const char *key) { size_t i, j; @@ -1007,7 +1007,7 @@ static void WriteVars (FSerializer &file, SDWORD *vars, size_t count, const char // //============================================================================ -static void ReadVars (FSerializer &arc, SDWORD *vars, size_t count, const char *key) +static void ReadVars (FSerializer &arc, int32_t *vars, size_t count, const char *key) { memset(&vars[0], 0, count * 4); arc.Array(key, vars, (int)count); @@ -1684,10 +1684,10 @@ void FBehavior::SerializeVars (FSerializer &arc) } } -void FBehavior::SerializeVarSet (FSerializer &arc, SDWORD *vars, int max) +void FBehavior::SerializeVarSet (FSerializer &arc, int32_t *vars, int max) { - SDWORD count; - SDWORD first, last; + int32_t count; + int32_t first, last; if (arc.BeginObject(nullptr)) { @@ -1997,7 +1997,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len) { MapVarStore[LittleLong(chunk[2+i*2])] = i; ArrayStore[i].ArraySize = LittleLong(chunk[3+i*2]); - ArrayStore[i].Elements = new SDWORD[ArrayStore[i].ArraySize]; + ArrayStore[i].Elements = new int32_t[ArrayStore[i].ArraySize]; memset(ArrayStore[i].Elements, 0, ArrayStore[i].ArraySize*sizeof(DWORD)); } } @@ -2013,7 +2013,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len) // optimizer. Might be some undefined behavior in this code, // but I don't know what it is. unsigned int initsize = MIN (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4); - SDWORD *elems = ArrayStore[arraynum].Elements; + int32_t *elems = ArrayStore[arraynum].Elements; for (unsigned int j = 0; j < initsize; ++j) { elems[j] = LittleLong(chunk[3+j]); @@ -2062,7 +2062,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len) int arraynum = MapVarStore[LittleLong(chunk[i+2])]; if ((unsigned)arraynum < (unsigned)NumArrays) { - SDWORD *elems = ArrayStore[arraynum].Elements; + int32_t *elems = ArrayStore[arraynum].Elements; for (int j = ArrayStore[arraynum].ArraySize; j > 0; --j, ++elems) { // *elems |= LibraryID; @@ -2088,7 +2088,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len) chunkData += 4; if ((unsigned)arraynum < (unsigned)NumArrays) { - SDWORD *elems = ArrayStore[arraynum].Elements; + int32_t *elems = ArrayStore[arraynum].Elements; // Ending zeros may be left out. for (int j = MIN(LittleLong(chunk[1])-5, ArrayStore[arraynum].ArraySize); j > 0; --j, ++elems, ++chunkData) { @@ -4371,6 +4371,7 @@ enum EACSFunctions ACSF_Floor, ACSF_Round, ACSF_Ceil, + ACSF_ScriptCall, // OpenGL stuff @@ -4753,9 +4754,121 @@ static int SwapActorTeleFog(AActor *activator, int tid) return count; } +static int ScriptCall(unsigned argc, int32_t *args) +{ + int retval = 0; + if (argc >= 2) + { + auto clsname = FBehavior::StaticLookupString(args[0]); + auto funcname = FBehavior::StaticLookupString(args[1]); + auto cls = PClass::FindClass(clsname); + if (!cls) + { + I_Error("ACS call to unknown class in script function %s.%s", cls, funcname); + } + auto funcsym = dyn_cast(cls->Symbols.FindSymbol(funcname, true)); + if (funcsym == nullptr) + { + I_Error("ACS call to unknown script function %s.%s", cls, funcname); + } + auto func = funcsym->Variants[0].Implementation; + if (func->ImplicitArgs > 0) + { + I_Error("ACS call to non-static script function %s.%s", cls, funcname); + } + TArray params; + for (unsigned i = 2; i < argc; i++) + { + if (func->Proto->ArgumentTypes.Size() < i - 1) + { + I_Error("Too many parameters in call to %s.%s", cls, funcname); + } + auto argtype = func->Proto->ArgumentTypes[i - 2]; + // The only types allowed are int, bool, double, Name, Sound, Color and String + if (argtype == TypeSInt32 || argtype == TypeColor) + { + params.Push(args[i]); + } + else if (argtype == TypeBool) + { + params.Push(!!args[i]); + } + else if (argtype == TypeFloat64) + { + params.Push(ACSToDouble(args[i])); + } + else if (argtype == TypeName) + { + params.Push(FName(FBehavior::StaticLookupString(args[i])).GetIndex()); + } + else if (argtype == TypeString) + { + params.Push(FBehavior::StaticLookupString(args[i])); + } + else if (argtype == TypeSound) + { + params.Push(int(FSoundID(FBehavior::StaticLookupString(args[i])))); + } + else + { + I_Error("Invalid type %s in call to %s.%s", argtype->DescriptiveName(), cls, funcname); + } + } + if (func->Proto->ArgumentTypes.Size() > params.Size()) + { + // Check if we got enough parameters. That means we either cover the full argument list of the function or the next argument is optional. + if (!(funcsym->Variants[0].ArgFlags[params.Size()] & VARF_Optional)) + { + I_Error("Insufficient parameters in call to %s.%s", cls, funcname); + } + } + // The return value can be the same types as the parameter types, plus void + if (func->Proto->ReturnTypes.Size() == 0) + { + GlobalVMStack.Call(func, ¶ms[0], params.Size(), nullptr, 0); + } + else + { + auto rettype = func->Proto->ReturnTypes[0]; + if (rettype == TypeSInt32 || rettype == TypeBool || rettype == TypeColor || rettype == TypeName || rettype == TypeSound) + { + VMReturn ret(&retval); + GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1); + if (rettype == TypeName) + { + retval = GlobalACSStrings.AddString(FName(ENamedName(retval))); + } + else if (rettype == TypeSound) + { + retval = GlobalACSStrings.AddString(FSoundID(retval)); + } + } + else if (rettype == TypeFloat64) + { + double d; + VMReturn ret(&d); + GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1); + retval = DoubleToACS(d); + } + else if (rettype == TypeString) + { + FString d; + VMReturn ret(&d); + GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1); + retval = GlobalACSStrings.AddString(d); + } + else + { + // All other return values can not be handled so ignore them. + GlobalVMStack.Call(func, ¶ms[0], params.Size(), nullptr, 0); + } + } + } + return retval; +} -int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) +int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args) { AActor *actor; switch(funcIndex) @@ -6103,6 +6216,9 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_Round: return (args[0] + 32768) & ~0xffff; + case ACSF_ScriptCall: + return ScriptCall(argCount, args); + default: break; } @@ -6192,7 +6308,7 @@ static void SetMarineSprite(AActor *marine, PClassActor *source) int DLevelScript::RunScript () { DACSThinker *controller = DACSThinker::ActiveThinker; - SDWORD *locals = &Localvars[0]; + int32_t *locals = &Localvars[0]; ACSLocalArrays noarrays; ACSLocalArrays *localarrays = &noarrays; ScriptFunction *activeFunction = NULL; @@ -6266,7 +6382,7 @@ int DLevelScript::RunScript () } FACSStack stackobj; - SDWORD *Stack = stackobj.buffer; + int32_t *Stack = stackobj.buffer; int &sp = stackobj.sp; int *pc = this->pc; @@ -6560,7 +6676,7 @@ int DLevelScript::RunScript () int i; ScriptFunction *func; FBehavior *module; - SDWORD *mylocals; + int32_t *mylocals; if(pcd == PCD_CALLSTACK) { @@ -6615,7 +6731,7 @@ int DLevelScript::RunScript () int value; union { - SDWORD *retsp; + int32_t *retsp; CallReturn *ret; }; @@ -7770,7 +7886,7 @@ scriptwait: while (min <= max) { int mid = (min + max) / 2; - SDWORD caseval = LittleLong(pc[mid*2]); + int32_t caseval = LittleLong(pc[mid*2]); if (caseval == STACK(1)) { pc = activeBehavior->Ofs2PC (LittleLong(pc[mid*2+1])); @@ -9185,7 +9301,7 @@ scriptwait: const char *str = FBehavior::StaticLookupString(STACK(1)); if (str != NULL) { - STACK(1) = SDWORD(strlen(str)); + STACK(1) = int32_t(strlen(str)); break; } @@ -9355,7 +9471,7 @@ scriptwait: switch (STACK(1)) { case PLAYERINFO_TEAM: STACK(2) = userinfo->GetTeam(); break; - case PLAYERINFO_AIMDIST: STACK(2) = (SDWORD)(userinfo->GetAimDist() * (0x40000000/90.)); break; // Yes, this has been returning a BAM since its creation. + case PLAYERINFO_AIMDIST: STACK(2) = (int32_t)(userinfo->GetAimDist() * (0x40000000/90.)); break; // Yes, this has been returning a BAM since its creation. case PLAYERINFO_COLOR: STACK(2) = userinfo->GetColor(); break; case PLAYERINFO_GENDER: STACK(2) = userinfo->GetGender(); break; case PLAYERINFO_NEVERSWITCH: STACK(2) = userinfo->GetNeverSwitch(); break; @@ -9762,7 +9878,7 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr script = num; assert(code->VarCount >= code->ArgCount); Localvars.Resize(code->VarCount); - memset(&Localvars[0], 0, code->VarCount * sizeof(SDWORD)); + memset(&Localvars[0], 0, code->VarCount * sizeof(int32_t)); for (int i = 0; i < MIN(argcount, code->ArgCount); ++i) { Localvars[i] = args[i]; From c630b070113f04ca7bc6a5dd8339a630b79faf09 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 3 Mar 2017 19:35:08 +0100 Subject: [PATCH 205/207] - replaced SDWORD with int32_t globally. This type wasn't used in the software rendering code so it could be removed already. The other homegrown types will have to be dealt with later. --- src/actor.h | 10 +++---- src/basictypes.h | 3 +- src/c_console.cpp | 2 +- src/doomdata.h | 4 +-- src/fragglescript/t_func.cpp | 2 +- src/fragglescript/t_script.h | 2 +- src/gl/system/gl_wipe.cpp | 12 ++++---- src/oplsynth/dosbox/opl.cpp | 2 +- src/oplsynth/nukedopl3.h | 2 +- src/p_acs.h | 14 +++++----- src/p_buildmap.cpp | 16 +++++------ src/p_conversation.cpp | 34 +++++++++++------------ src/p_glnodes.cpp | 14 +++++----- src/p_switch.cpp | 2 +- src/po_man.cpp | 2 +- src/resourcefiles/file_zip.cpp | 2 +- src/s_advsound.cpp | 2 +- src/s_sndseq.cpp | 6 ++-- src/s_sndseq.h | 6 ++-- src/s_sound.cpp | 4 +-- src/scripting/decorate/olddecorations.cpp | 2 +- src/textures/backdroptexture.cpp | 14 +++++----- src/textures/ddstexture.cpp | 4 +-- src/timidity/instrum_dls.cpp | 10 +++---- src/timidity/instrum_sf2.cpp | 10 +++---- src/timidity/mix.cpp | 12 ++++---- src/timidity/timidity.h | 4 +-- 27 files changed, 98 insertions(+), 99 deletions(-) diff --git a/src/actor.h b/src/actor.h index 9fc1d10f12..e435a1fb72 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1037,7 +1037,7 @@ public: double StealthAlpha; // Minmum alpha for MF_STEALTH. int WoundHealth; // Health needed to enter wound state - SDWORD tics; // state tic counter + int32_t tics; // state tic counter FState *state; //VMFunction *Damage; // For missiles and monster railgun int DamageVal; @@ -1062,10 +1062,10 @@ public: // also the originator for missiles TObjPtr lastenemy; // Last known enemy -- killough 2/15/98 TObjPtr LastHeard; // [RH] Last actor this one heard - SDWORD reactiontime; // if non 0, don't attack yet; used by + int32_t reactiontime; // if non 0, don't attack yet; used by // player to freeze a bit after teleporting - SDWORD threshold; // if > 0, the target will be chased - SDWORD DefThreshold; // [MC] Default threshold which the actor will reset its threshold to after switching targets + int32_t threshold; // if > 0, the target will be chased + int32_t DefThreshold; // [MC] Default threshold which the actor will reset its threshold to after switching targets // no matter what (even if shot) player_t *player; // only valid if type of APlayerPawn TObjPtr LastLookActor; // Actor last looked for (if TIDtoHate != 0) @@ -1159,7 +1159,7 @@ public: double MaxDropOffHeight; double MaxStepHeight; - SDWORD Mass; + int32_t Mass; SWORD PainChance; int PainThreshold; FNameNoInit DamageType; diff --git a/src/basictypes.h b/src/basictypes.h index ff2cd972e6..acb499c0d4 100644 --- a/src/basictypes.h +++ b/src/basictypes.h @@ -7,7 +7,6 @@ typedef int8_t SBYTE; typedef uint8_t BYTE; typedef int16_t SWORD; typedef uint16_t WORD; -typedef int32_t SDWORD; typedef uint32_t uint32; typedef int64_t SQWORD; typedef uint64_t QWORD; @@ -63,7 +62,7 @@ union QWORD_UNION #define FRACBITS 16 #define FRACUNIT (1<DrawChar (ConFont, CR_ORANGE, (int)i, tickerY, 0x13, TAG_DONE); else diff --git a/src/doomdata.h b/src/doomdata.h index 39f0d184a5..0c1fb4a970 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -262,8 +262,8 @@ struct mapseg_t struct mapseg4_t { - SDWORD v1; - SDWORD v2; + int32_t v1; + int32_t v2; SWORD angle; WORD linedef; SWORD side; diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 68d9407046..1a979824f7 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -479,7 +479,7 @@ DFsSection *FParser::looping_section() int n; // check thru all the hashchains - SDWORD rover_index = Script->MakeIndex(Rover); + int32_t rover_index = Script->MakeIndex(Rover); for(n=0; n, InitIntToZero> FWorldGlobalArray; +typedef TMap, InitIntToZero> FWorldGlobalArray; // ACS variables with world scope -extern SDWORD ACS_WorldVars[NUM_WORLDVARS]; +extern int32_t ACS_WorldVars[NUM_WORLDVARS]; extern FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS]; // ACS variables with global scope -extern SDWORD ACS_GlobalVars[NUM_GLOBALVARS]; +extern int32_t ACS_GlobalVars[NUM_GLOBALVARS]; extern FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; #define LIBRARYID_MASK 0xFFF00000 @@ -323,7 +323,7 @@ public: ACSProfileInfo *GetFunctionProfileData(ScriptFunction *func) { return GetFunctionProfileData((int)(func - (ScriptFunction *)Functions)); } const char *LookupString (DWORD index) const; - SDWORD *MapVars[NUM_MAPVARS]; + int32_t *MapVars[NUM_MAPVARS]; static FBehavior *StaticLoadModule (int lumpnum, FileReader * fr=NULL, int len=0); static void StaticLoadDefaultModules (); @@ -359,7 +359,7 @@ private: ArrayInfo **Arrays; int NumTotalArrays; DWORD StringTable; - SDWORD MapVarStore[NUM_MAPVARS]; + int32_t MapVarStore[NUM_MAPVARS]; TArray Imports; DWORD LibraryID; char ModuleName[9]; @@ -375,7 +375,7 @@ private: int FindStringInChunk (DWORD *chunk, const char *varname) const; void SerializeVars (FSerializer &arc); - void SerializeVarSet (FSerializer &arc, SDWORD *vars, int max); + void SerializeVarSet (FSerializer &arc, int32_t *vars, int max); void MarkMapVarStrings() const; void LockMapVarStrings() const; @@ -919,7 +919,7 @@ protected: int DoSpawnSpot (int type, int spot, int tid, int angle, bool forced); int DoSpawnSpotFacing (int type, int spot, int tid, bool forced); int DoClassifyActor (int tid); - int CallFunction(int argCount, int funcIndex, SDWORD *args); + int CallFunction(int argCount, int funcIndex, int32_t *args); void DoFadeTo (int r, int g, int b, int a, int time); void DoFadeRange (int r1, int g1, int b1, int a1, diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 3d1e77d6da..1be648bc2f 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -46,7 +46,7 @@ struct sectortype { SWORD wallptr, wallnum; - SDWORD ceilingZ, floorZ; + int32_t ceilingZ, floorZ; SWORD ceilingstat, floorstat; SWORD ceilingpicnum, ceilingheinum; SBYTE ceilingshade; @@ -74,7 +74,7 @@ struct sectortype //32 bytes struct walltype { - SDWORD x, y; + int32_t x, y; SWORD point2, nextwall, nextsector, cstat; SWORD picnum, overpicnum; SBYTE shade; @@ -100,7 +100,7 @@ struct walltype //44 bytes struct spritetype { - SDWORD x, y, z; + int32_t x, y, z; SWORD cstat, picnum; SBYTE shade; BYTE pal, clipdist, filler; @@ -146,8 +146,8 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **sprites, int *nu static void LoadSectors (sectortype *bsectors, int count); static void LoadWalls (walltype *walls, int numwalls, sectortype *bsectors); static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, sectortype *bsectors, FMapThing *mapthings); -static vertex_t *FindVertex (SDWORD x, SDWORD y); -static void CreateStartSpot (SDWORD *pos, FMapThing *start); +static vertex_t *FindVertex (int32_t x, int32_t y); +static void CreateStartSpot (int32_t *pos, FMapThing *start); static void CalcPlane (SlopeWork &slope, secplane_t &plane); static void Decrypt (void *to, const void *from, int len, int key); @@ -232,7 +232,7 @@ bool P_LoadBuildMap (BYTE *data, size_t len, FMapThing **sprites, int *numspr) numsprites = *(WORD *)(data + 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)); *sprites = new FMapThing[numsprites + 1]; - CreateStartSpot ((SDWORD *)(data + 4), *sprites); + CreateStartSpot ((int32_t *)(data + 4), *sprites); *numspr = 1 + LoadSprites ((spritetype *)(data + 26 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)), NULL, numsprites, (sectortype *)(data + 22), *sprites + 1); @@ -755,7 +755,7 @@ static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, // //========================================================================== -vertex_t *FindVertex (SDWORD xx, SDWORD yy) +vertex_t *FindVertex (int32_t xx, int32_t yy) { int i; @@ -780,7 +780,7 @@ vertex_t *FindVertex (SDWORD xx, SDWORD yy) // //========================================================================== -static void CreateStartSpot (SDWORD *pos, FMapThing *start) +static void CreateStartSpot (int32_t *pos, FMapThing *start) { short angle = LittleShort(*(WORD *)(&pos[3])); FMapThing mt = { 0, }; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index f43313682a..0ac80171ca 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -66,22 +66,22 @@ // The conversations as they exist inside a SCRIPTxx lump. struct Response { - SDWORD GiveType; - SDWORD Item[3]; - SDWORD Count[3]; + int32_t GiveType; + int32_t Item[3]; + int32_t Count[3]; char Reply[32]; char Yes[80]; - SDWORD Link; - DWORD Log; + int32_t Link; + uint32_t Log; char No[80]; }; struct Speech { - DWORD SpeakerType; - SDWORD DropType; - SDWORD ItemCheck[3]; - SDWORD Link; + uint32_t SpeakerType; + int32_t DropType; + int32_t ItemCheck[3]; + int32_t Link; char Name[16]; char Sound[8]; char Backdrop[8]; @@ -92,9 +92,9 @@ struct Speech // The Teaser version of the game uses an older version of the structure struct TeaserSpeech { - DWORD SpeakerType; - SDWORD DropType; - DWORD VoiceNumber; + uint32_t SpeakerType; + int32_t DropType; + uint32_t VoiceNumber; char Name[16]; char Dialogue[320]; Response Responses[5]; @@ -116,8 +116,8 @@ static int ConversationPauseTic; static int StaticLastReply; static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool include, int type); -static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeakerType); -static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeakerType); +static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, uint32_t &prevSpeakerType); +static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, uint32_t &prevSpeakerType); static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses); static bool DrawConversationMenu (); static void PickConversationReply (int replyindex); @@ -243,7 +243,7 @@ bool LoadScriptFile (const char *name, bool include, int type) static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool include, int type) { int i; - DWORD prevSpeakerType; + uint32_t prevSpeakerType; FStrifeDialogueNode *node; char buffer[4]; @@ -317,7 +317,7 @@ static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool inc // //============================================================================ -static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeakerType) +static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, uint32_t &prevSpeakerType) { FStrifeDialogueNode *node; Speech speech; @@ -393,7 +393,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker // //============================================================================ -static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeakerType) +static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, uint32_t &prevSpeakerType) { FStrifeDialogueNode *node; TeaserSpeech speech; diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 43ed096e0c..d30cb812ee 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -82,13 +82,13 @@ static void CreateCachedNodes(MapData *map); // fixed 32 bit gl_vert format v2.0+ (glBsp 1.91) struct mapglvertex_t { - SDWORD x,y; + int32_t x,y; }; struct gl3_mapsubsector_t { - SDWORD numsegs; - SDWORD firstseg; // Index of first one; segs are stored sequentially. + int32_t numsegs; + int32_t firstseg; // Index of first one; segs are stored sequentially. }; struct glseg_t @@ -102,11 +102,11 @@ struct glseg_t struct glseg3_t { - SDWORD v1; - SDWORD v2; + int32_t v1; + int32_t v2; WORD linedef; WORD side; - SDWORD partner; + int32_t partner; }; struct gl5_mapnode_t @@ -621,7 +621,7 @@ static bool LoadNodes (FileReader * lump) no->dy = LittleShort(mn->dy)<children[j]); + int32_t child = LittleLong(mn->children[j]); if (child & GL5_NF_SUBSECTOR) { child &= ~GL5_NF_SUBSECTOR; diff --git a/src/p_switch.cpp b/src/p_switch.cpp index ae7cf21432..3e956f691b 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -69,7 +69,7 @@ public: bool bFlippable; bool bReturning; FSwitchDef *m_SwitchDef; - SDWORD m_Frame; + int32_t m_Frame; DWORD m_Timer; DVector2 m_Pos; diff --git a/src/po_man.cpp b/src/po_man.cpp index c2c8f5a7da..ebe39cccae 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -147,7 +147,7 @@ polyspawns_t *polyspawns; // [RH] Let P_SpawnMapThings() find our thingies for u // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static TArray KnownPolySides; +static TArray KnownPolySides; static FPolyNode *FreePolyNodes; // CODE -------------------------------------------------------------------- diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 7b83084ab8..a48a17ca25 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -151,7 +151,7 @@ static DWORD Zip_FindCentralDir(FileReader * fin) if (fin->Seek(uReadPos, SEEK_SET) != 0) break; - if (fin->Read(buf, (SDWORD)uReadSize) != (SDWORD)uReadSize) break; + if (fin->Read(buf, (int32_t)uReadSize) != (int32_t)uReadSize) break; for (i = (int)uReadSize - 3; (i--) > 0;) { diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 952a40d09f..687a27a433 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -167,7 +167,7 @@ struct FBloodSFX int Pitch; // pitch change int PitchRange; // range of random pitch DWORD Format; // format of audio 1=11025 5=22050 - SDWORD LoopStart; // loop position (-1 means no looping) + int32_t LoopStart; // loop position (-1 means no looping) char RawName[9]; // name of RAW resource }; diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 6506f303bc..af3f3617b3 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -34,8 +34,8 @@ // MACROS ------------------------------------------------------------------ #define GetCommand(a) ((a) & 255) -#define GetData(a) (SDWORD(a) >> 8 ) -#define GetFloatData(a) float((SDWORD(a) >> 8 )/65536.f) +#define GetData(a) (int32_t(a) >> 8 ) +#define GetFloatData(a) float((int32_t(a) >> 8 )/65536.f) #define MakeCommand(a,b) ((a) | ((b) << 8)) #define HexenPlatSeq(a) (a) #define HexenDoorSeq(a) ((a) | 0x40) @@ -1390,7 +1390,7 @@ void SN_StopAllSequences (void) // //========================================================================== -ptrdiff_t SN_GetSequenceOffset (int sequence, SDWORD *sequencePtr) +ptrdiff_t SN_GetSequenceOffset (int sequence, int32_t *sequencePtr) { return sequencePtr - Sequences[sequence]->Script; } diff --git a/src/s_sndseq.h b/src/s_sndseq.h index a35fab026d..e77df22719 100644 --- a/src/s_sndseq.h +++ b/src/s_sndseq.h @@ -44,7 +44,7 @@ protected: DSeqNode (); DSeqNode (int sequence, int modenum); - SDWORD *m_SequencePtr; + int32_t *m_SequencePtr; int m_Sequence; FSoundID m_CurrentSoundID; @@ -74,7 +74,7 @@ struct FSoundSequence FName SeqName; FName Slot; FSoundID StopSound; - SDWORD Script[1]; // + more until end of sequence script + int32_t Script[1]; // + more until end of sequence script }; void S_ParseSndSeq (int levellump); @@ -93,7 +93,7 @@ void SN_StopSequence (FPolyObj *poly); bool SN_AreModesSame(int sequence, seqtype_t type, int mode1, int mode2); bool SN_AreModesSame(FName name, int mode1, int mode2); void SN_UpdateActiveSequences (void); -ptrdiff_t SN_GetSequenceOffset (int sequence, SDWORD *sequencePtr); +ptrdiff_t SN_GetSequenceOffset (int sequence, int32_t *sequencePtr); void SN_DoStop (void *); void SN_ChangeNodeData (int nodeNum, int seqOffset, int delayTics, float volume, int currentSoundID); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 840559127a..89fc13365a 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1400,7 +1400,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) FWadLump wlump = Wads.OpenLumpNum(sfx->lumpnum); BYTE *sfxdata = new BYTE[size]; wlump.Read(sfxdata, size); - SDWORD dmxlen = LittleLong(((SDWORD *)sfxdata)[1]); + int32_t dmxlen = LittleLong(((int32_t *)sfxdata)[1]); std::pair snd; // If the sound is voc, use the custom loader. @@ -1460,7 +1460,7 @@ static void S_LoadSound3D(sfxinfo_t *sfx) FWadLump wlump = Wads.OpenLumpNum(sfx->lumpnum); BYTE *sfxdata = new BYTE[size]; wlump.Read(sfxdata, size); - SDWORD dmxlen = LittleLong(((SDWORD *)sfxdata)[1]); + int32_t dmxlen = LittleLong(((int32_t *)sfxdata)[1]); std::pair snd; // If the sound is voc, use the custom loader. diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 7370ddb54f..e656445fc0 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -483,7 +483,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, else if (sc.Compare ("Mass")) { sc.MustGetFloat (); - defaults->Mass = SDWORD(sc.Float); + defaults->Mass = int32_t(sc.Float); } else if (sc.Compare ("Translation1")) { diff --git a/src/textures/backdroptexture.cpp b/src/textures/backdroptexture.cpp index b4b2793dc2..0f18fe6d6c 100644 --- a/src/textures/backdroptexture.cpp +++ b/src/textures/backdroptexture.cpp @@ -289,7 +289,7 @@ void FBackdropTexture::Render() DWORD a1, a2, a3, a4; - SDWORD c1, c2, c3, c4; + int32_t c1, c2, c3, c4; DWORD tx, ty, tc, ts; DWORD ux, uy, uc, us; DWORD ltx, lty, lux, luy; @@ -302,10 +302,10 @@ void FBackdropTexture::Render() double z1 = (cos(TORAD(z2ang)) / 4 + 0.5) * (0x8000000); double z2 = (cos(TORAD(z1ang)) / 4 + 0.75) * (0x8000000); - tc = SDWORD(cos(TORAD(t1ang)) * z1); - ts = SDWORD(sin(TORAD(t1ang)) * z1); - uc = SDWORD(cos(TORAD(t2ang)) * z2); - us = SDWORD(sin(TORAD(t2ang)) * z2); + tc = int32_t(cos(TORAD(t1ang)) * z1); + ts = int32_t(sin(TORAD(t1ang)) * z1); + uc = int32_t(cos(TORAD(t2ang)) * z2); + us = int32_t(sin(TORAD(t2ang)) * z2); ltx = -width / 2 * tc; lty = -width / 2 * ts; @@ -316,8 +316,8 @@ void FBackdropTexture::Render() { a1 = time1; a2 = time2; - c3 = SDWORD(cos(TORAD(a3)) * 65536.0); - c4 = SDWORD(cos(TORAD(a4)) * 65536.0); + c3 = int32_t(cos(TORAD(a3)) * 65536.0); + c4 = int32_t(cos(TORAD(a4)) * 65536.0); tx = ltx - (y - height / 2)*ts; ty = lty + (y - height / 2)*tc; ux = lux - (y - height / 2)*us; diff --git a/src/textures/ddstexture.cpp b/src/textures/ddstexture.cpp index a2c69b38b2..c55cf11bb3 100644 --- a/src/textures/ddstexture.cpp +++ b/src/textures/ddstexture.cpp @@ -126,7 +126,7 @@ struct DDSURFACEDESC2 DWORD Width; union { - SDWORD Pitch; + int32_t Pitch; DWORD LinearSize; }; DWORD Depth; @@ -172,7 +172,7 @@ protected: BYTE RShiftL, GShiftL, BShiftL, AShiftL; BYTE RShiftR, GShiftR, BShiftR, AShiftR; - SDWORD Pitch; + int32_t Pitch; DWORD LinearSize; static void CalcBitShift (DWORD mask, BYTE *lshift, BYTE *rshift); diff --git a/src/timidity/instrum_dls.cpp b/src/timidity/instrum_dls.cpp index fefac19e0c..c882cd84e2 100644 --- a/src/timidity/instrum_dls.cpp +++ b/src/timidity/instrum_dls.cpp @@ -253,7 +253,7 @@ http://www.midi.org/about-midi/dls/dlsspec.shtml #define FAR typedef SWORD SHORT; typedef WORD USHORT; -typedef SDWORD LONG; +typedef int32_t LONG; typedef DWORD ULONG; #define mmioFOURCC MAKE_ID #define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M) @@ -1075,15 +1075,15 @@ static double to_normalized_percent(int decipercent) } /* convert from 8bit value to fractional offset (15.15) */ -static SDWORD to_offset(int offset) +static int32_t to_offset(int offset) { - return (SDWORD)offset << (7+15); + return (int32_t)offset << (7+15); } /* calculate ramp rate in fractional unit; * diff = 8bit, time = msec */ -static SDWORD calc_rate(Renderer *song, int diff, int sample_rate, double msec) +static int32_t calc_rate(Renderer *song, int diff, int sample_rate, double msec) { double rate; @@ -1093,7 +1093,7 @@ static SDWORD calc_rate(Renderer *song, int diff, int sample_rate, double msec) diff = 255; diff <<= (7+15); rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec; - return (SDWORD)rate; + return (int32_t)rate; } static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination) diff --git a/src/timidity/instrum_sf2.cpp b/src/timidity/instrum_sf2.cpp index cae7ae57f6..2e9d7d0c00 100644 --- a/src/timidity/instrum_sf2.cpp +++ b/src/timidity/instrum_sf2.cpp @@ -199,12 +199,12 @@ static double timecent_to_sec(SWORD timecent) return pow(2.0, timecent / 1200.0); } -static SDWORD to_offset(int offset) +static int32_t to_offset(int offset) { - return (SDWORD)offset << (7+15); + return (int32_t)offset << (7+15); } -static SDWORD calc_rate(Renderer *song, int diff, double sec) +static int32_t calc_rate(Renderer *song, int diff, double sec) { double rate; @@ -214,7 +214,7 @@ static SDWORD calc_rate(Renderer *song, int diff, double sec) diff = 255; diff <<= (7+15); rate = ((double)diff / song->rate) * song->control_ratio / sec; - return (SDWORD)rate; + return (int32_t)rate; } @@ -1524,7 +1524,7 @@ void SFFile::LoadSample(SFSample *sample) { BYTE samp; *fp >> samp; - sample->InMemoryData[i] = ((((SDWORD(sample->InMemoryData[i] * 32768) << 8) | samp) << 8) >> 8) / 8388608.f; + sample->InMemoryData[i] = ((((int32_t(sample->InMemoryData[i] * 32768) << 8) | samp) << 8) >> 8) / 8388608.f; } } // Final 0 byte is for interpolation. diff --git a/src/timidity/mix.cpp b/src/timidity/mix.cpp index cd1ede89d8..037226c2c2 100644 --- a/src/timidity/mix.cpp +++ b/src/timidity/mix.cpp @@ -426,7 +426,7 @@ static int update_signal(Voice *v) return 0; } -static void mix_mystery_signal(SDWORD control_ratio, const sample_t *sp, float *lp, Voice *v, int count) +static void mix_mystery_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) { final_volume_t left = v->left_mix, @@ -477,7 +477,7 @@ static void mix_mystery_signal(SDWORD control_ratio, const sample_t *sp, float * } } -static void mix_single_signal(SDWORD control_ratio, const sample_t *sp, float *lp, Voice *v, float *ampat, int count) +static void mix_single_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, float *ampat, int count) { final_volume_t amp; int cc; @@ -518,17 +518,17 @@ static void mix_single_signal(SDWORD control_ratio, const sample_t *sp, float *l } } -static void mix_single_left_signal(SDWORD control_ratio, const sample_t *sp, float *lp, Voice *v, int count) +static void mix_single_left_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) { mix_single_signal(control_ratio, sp, lp, v, &v->left_mix, count); } -static void mix_single_right_signal(SDWORD control_ratio, const sample_t *sp, float *lp, Voice *v, int count) +static void mix_single_right_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) { mix_single_signal(control_ratio, sp, lp + 1, v, &v->right_mix, count); } -static void mix_mono_signal(SDWORD control_ratio, const sample_t *sp, float *lp, Voice *v, int count) +static void mix_mono_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) { final_volume_t left = v->left_mix; @@ -568,7 +568,7 @@ static void mix_mono_signal(SDWORD control_ratio, const sample_t *sp, float *lp, } } -static void mix_mystery(SDWORD control_ratio, const sample_t *sp, float *lp, Voice *v, int count) +static void mix_mystery(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) { final_volume_t left = v->left_mix, diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 2ca64a59a6..b3a1e2c809 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -211,7 +211,7 @@ enum struct Sample { - SDWORD + int32_t loop_start, loop_end, data_length, sample_rate; float @@ -233,7 +233,7 @@ struct Sample } sf2; } envelope; sample_t *data; - SDWORD + int32_t tremolo_sweep_increment, tremolo_phase_increment, vibrato_sweep_increment, vibrato_control_ratio; BYTE From fd20e1d78ff1d6d048cc903535fe82270c972020 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 3 Mar 2017 20:11:13 +0100 Subject: [PATCH 206/207] - allow hooking custom serializers into PPointer so that serializable types can be handled without having to create new type classes which would be a bit unwieldy thanks to how the type system works. --- src/dobjtype.cpp | 8 ++++ src/dobjtype.h | 13 ++++++ src/scripting/thingdef_data.cpp | 80 +++++++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 98a893391b..1a582d3662 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1396,6 +1396,10 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con ar(key, *(DObject **)addr); } } + else if (writer != nullptr) + { + writer(ar, key, addr); + } else { I_Error("Attempt to save pointer to unhandled type %s", PointedType->DescriptiveName()); @@ -1425,6 +1429,10 @@ bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const } return res; } + else if (reader != nullptr) + { + return reader(ar, key, addr); + } return false; } diff --git a/src/dobjtype.h b/src/dobjtype.h index f589b4e489..1a30b42ed7 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -362,13 +362,26 @@ public: class PPointer : public PBasicType { DECLARE_CLASS(PPointer, PBasicType); + public: + typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr); + typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr); + PPointer(); PPointer(PType *pointsat, bool isconst = false); PType *PointedType; bool IsConst; + WriteHandler writer = nullptr; + ReadHandler reader = nullptr; + + void InstallHandlers(WriteHandler w, ReadHandler r) + { + writer = w; + reader = r; + } + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 4b65e6413e..c50b7f65bf 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -59,6 +59,7 @@ #include "menu/menu.h" #include "teaminfo.h" #include "r_data/sprites.h" +#include "serializer.h" static TArray properties; static TArray AFTable; @@ -741,7 +742,7 @@ static int fieldcmp(const void * a, const void * b) void InitThingdef() { // Create all global variables here because this cannot be done on the script side and really isn't worth adding support for. - // Also create all special fields here that cannot be declared by script syntax. + // Also create all special fields here that cannot be declared by script syntax plus the pointer serializers. Doing all these with class overrides would be a bit messy. auto secplanestruct = NewNativeStruct("Secplane", nullptr); secplanestruct->Size = sizeof(secplane_t); @@ -750,18 +751,62 @@ void InitThingdef() auto sectorstruct = NewNativeStruct("Sector", nullptr); sectorstruct->Size = sizeof(sector_t); sectorstruct->Align = alignof(sector_t); + NewPointer(sectorstruct, false)->InstallHandlers( + [](FSerializer &ar, const char *key, const void *addr) + { + ar(key, *(sector_t **)addr); + }, + [](FSerializer &ar, const char *key, void *addr) + { + Serialize(ar, key, *(sector_t **)addr, nullptr); + return true; + } + ); auto linestruct = NewNativeStruct("Line", nullptr); linestruct->Size = sizeof(line_t); linestruct->Align = alignof(line_t); + NewPointer(linestruct, false)->InstallHandlers( + [](FSerializer &ar, const char *key, const void *addr) + { + ar(key, *(line_t **)addr); + }, + [](FSerializer &ar, const char *key, void *addr) + { + Serialize(ar, key, *(line_t **)addr, nullptr); + return true; + } + ); auto sidestruct = NewNativeStruct("Side", nullptr); sidestruct->Size = sizeof(side_t); sidestruct->Align = alignof(side_t); + NewPointer(sidestruct, false)->InstallHandlers( + [](FSerializer &ar, const char *key, const void *addr) + { + ar(key, *(side_t **)addr); + }, + [](FSerializer &ar, const char *key, void *addr) + { + Serialize(ar, key, *(side_t **)addr, nullptr); + return true; + } + ); auto vertstruct = NewNativeStruct("Vertex", nullptr); vertstruct->Size = sizeof(vertex_t); vertstruct->Align = alignof(vertex_t); + NewPointer(vertstruct, false)->InstallHandlers( + [](FSerializer &ar, const char *key, const void *addr) + { + ar(key, *(vertex_t **)addr); + }, + [](FSerializer &ar, const char *key, void *addr) + { + Serialize(ar, key, *(vertex_t **)addr, nullptr); + return true; + } + ); auto sectorportalstruct = NewNativeStruct("SectorPortal", nullptr); sectorportalstruct->Size = sizeof(FSectorPortal); @@ -779,6 +824,36 @@ void InitThingdef() teamstruct->Size = sizeof(FTeam); teamstruct->Align = alignof(FTeam); + PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); + pstruct->Size = sizeof(player_t); + pstruct->Align = alignof(player_t); + NewPointer(pstruct, false)->InstallHandlers( + [](FSerializer &ar, const char *key, const void *addr) + { + ar(key, *(player_t **)addr); + }, + [](FSerializer &ar, const char *key, void *addr) + { + Serialize(ar, key, *(player_t **)addr, nullptr); + return true; + } + ); + + auto fontstruct = NewNativeStruct("FFont", nullptr); + fontstruct->Size = sizeof(FFont); + fontstruct->Align = alignof(FFont); + NewPointer(fontstruct, false)->InstallHandlers( + [](FSerializer &ar, const char *key, const void *addr) + { + ar(key, *(FFont **)addr); + }, + [](FSerializer &ar, const char *key, void *addr) + { + Serialize(ar, key, *(FFont **)addr, nullptr); + return true; + } + ); + // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. sectorstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(linestruct, false)), false), myoffsetof(sector_t, Lines), VARF_Native); @@ -843,9 +918,6 @@ void InitThingdef() Namespaces.GlobalNamespace->Symbols.AddSymbol(gi); // set up a variable for the global players array. - PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); - pstruct->Size = sizeof(player_t); - pstruct->Align = alignof(player_t); PArray *parray = NewArray(pstruct, MAXPLAYERS); PField *fieldptr = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); From 4b63092c7a20a42e361a90b57f66d5643c8998e6 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Fri, 3 Mar 2017 12:48:56 -0500 Subject: [PATCH 207/207] - disable size checking in windowed mode for vid_setmode, allowing it to set arbitrary sizes. --- src/v_video.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/v_video.cpp b/src/v_video.cpp index aca00cfb37..d993204a27 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -72,6 +72,7 @@ FRenderer *Renderer; IMPLEMENT_CLASS(DCanvas, true, false) IMPLEMENT_CLASS(DFrameBuffer, true, false) +EXTERN_CVAR (Bool, fullscreen) #if defined(_DEBUG) && defined(_M_IX86) && !defined(__MINGW32__) #define DBGBREAK { __asm int 3 } @@ -1489,6 +1490,9 @@ CCMD (vid_setmode) goodmode = true; } + if (!fullscreen) + goodmode = true; + if (goodmode) { // The actual change of resolution will take place