From 8cac2d8c849cb7333d54d2c41ecd53e4ffaf9eb1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:27:02 +0100 Subject: [PATCH 01/12] - 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 797d092ef..f4af55f2d 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 9cd0a19ec..bb42fc76d 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 2fb040a93..5841e6b99 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 0ba75fc4c..27293b918 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 08c27bfd3..abf43fdf1 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 02/12] - 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 27532e7e9..5dddef105 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 71c0ff645..8b0bf35e9 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 224aa24f0..64cf4034b 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 db2adcdfd..954567d0f 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 03/12] - 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 9e9d4dae8..a74b61d16 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 04/12] - 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 1ae3c4b5e..9259561b0 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 9b52e7271..99c23c7bf 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 05/12] - 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 90d847fcc..81912150b 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 05785f90b..50db1e4b6 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 7699fe376..38d9cd375 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 06/12] - 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 a74b61d16..c15433cd6 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 07/12] - 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 03fa70dcd..06a91259a 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 dd772a745..25108c0df 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 6d7bdc927..0b6b55ea2 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 bc95198f2..dc4fff1a7 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 08/12] - 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 d767c6cb2..2ed004740 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 58aaefc17..9b3a257ec 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 656b75402..265dc079b 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 09/12] - 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 3ae708823..18f690205 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 10/12] - 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 aac1b7161..233bb8958 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 394203c75..ee70dcee5 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 11/12] - 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 f4af55f2d..553c75360 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 bb42fc76d..28de56818 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 27293b918..b9300f654 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 12/12] - 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 736384e62..5542130e6 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();