diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 6541e9a02..d501cb884 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -237,6 +237,7 @@ Note: All fields default to false unless mentioned otherwise. scalex = ; // Vertical scaling on thing. Default = 0 (ignored). scaley = ; // Horizontal scaling on thing. Default = 0 (ignored). scale = ; // Vertical and horizontal scaling on thing. Default = 0 (ignored). + floatbobphase = ; // Sets the thing's floatbobphase. Valid phase values are 0-63. Default = -1 (use actor class default). * Note about arg0str diff --git a/src/decallib.cpp b/src/decallib.cpp index 0ea3423c4..784998977 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -432,7 +432,7 @@ WORD FDecalLib::GetDecalID (FScanner &sc) unsigned long num = strtoul (sc.String, NULL, 10); if (num < 1 || num > 65535) { - sc.MustGetStringName ("Decal ID must be between 1 and 65535"); + sc.ScriptError ("Decal ID must be between 1 and 65535"); } return (WORD)num; } @@ -603,16 +603,18 @@ void FDecalLib::ParseGenerator (FScanner &sc) { const PClass *type; FDecalBase *decal; - AActor *actor; + bool optional = false; // Get name of generator (actor) sc.MustGetString (); + optional = sc.Compare("optional"); + if (optional) sc.MustGetString(); + type = PClass::FindClass (sc.String); if (type == NULL || type->ActorInfo == NULL) { - sc.ScriptError ("%s is not an actor.", sc.String); + if (!optional) sc.ScriptError ("%s is not an actor.", sc.String); } - actor = (AActor *)type->Defaults; // Get name of generated decal sc.MustGetString (); @@ -625,14 +627,17 @@ void FDecalLib::ParseGenerator (FScanner &sc) decal = ScanTreeForName (sc.String, Root); if (decal == NULL) { - sc.ScriptError ("%s has not been defined.", sc.String); + if (!optional) sc.ScriptError ("%s has not been defined.", sc.String); } } - - actor->DecalGenerator = decal; - if (decal != NULL) + if (type != NULL) { - decal->Users.Push (type); + AActor *actor = (AActor *)type->Defaults; + actor->DecalGenerator = decal; + if (decal != NULL) + { + decal->Users.Push(type); + } } } diff --git a/src/doomdata.h b/src/doomdata.h index 71e581e26..0877aee90 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -365,6 +365,7 @@ struct FMapThing short pitch; short roll; DWORD RenderStyle; + int FloatbobPhase; }; diff --git a/src/g_level.h b/src/g_level.h index 496c5c0f4..018737f09 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -563,8 +563,10 @@ enum ESkillProperty SKILLP_FriendlyHealth, SKILLP_NoPain, SKILLP_ArmorFactor, + SKILLP_HealthFactor, SKILLP_EasyKey, SKILLP_SlowMonsters, + SKILLP_Infight, }; int G_SkillProperty(ESkillProperty prop); const char * G_SkillName(); @@ -602,7 +604,9 @@ struct FSkillInfo fixed_t MonsterHealth; fixed_t FriendlyHealth; bool NoPain; + int Infighting; fixed_t ArmorFactor; + fixed_t HealthFactor; FSkillInfo() {} FSkillInfo(const FSkillInfo &other) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index e87929677..eb2831024 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -236,10 +236,12 @@ bool P_GiveBody (AActor *actor, int num, int max) return true; } } - else + else if (num > 0) { if (player->health < max) { + num = FixedMul(num, G_SkillProperty(SKILLP_HealthFactor)); + if (num < 1) num = 1; player->health += num; if (player->health > max) { diff --git a/src/g_skill.cpp b/src/g_skill.cpp index ddfdbb4cc..f4cb63ea5 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -83,6 +83,8 @@ void FMapInfoParser::ParseSkill () skill.FriendlyHealth = FRACUNIT; skill.NoPain = false; skill.ArmorFactor = FRACUNIT; + skill.Infighting = 0; + skill.HealthFactor = FRACUNIT; sc.MustGetString(); skill.Name = sc.String; @@ -266,6 +268,20 @@ void FMapInfoParser::ParseSkill () sc.MustGetFloat(); skill.ArmorFactor = FLOAT2FIXED(sc.Float); } + else if (sc.Compare("HealthFactor")) + { + ParseAssign(); + sc.MustGetFloat(); + skill.HealthFactor = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("NoInfighting")) + { + skill.Infighting = LEVEL2_NOINFIGHTING; + } + else if (sc.Compare("TotalInfighting")) + { + skill.Infighting = LEVEL2_TOTALINFIGHTING; + } else if (sc.Compare("DefaultSkill")) { if (DefaultSkill >= 0) @@ -384,6 +400,17 @@ int G_SkillProperty(ESkillProperty prop) case SKILLP_ArmorFactor: return AllSkills[gameskill].ArmorFactor; + + case SKILLP_HealthFactor: + return AllSkills[gameskill].HealthFactor; + + case SKILLP_Infight: + // This property also needs to consider the level flags for the same info. + if (level.flags2 & LEVEL2_TOTALINFIGHTING) return 1; + if (level.flags2 & LEVEL2_NOINFIGHTING) return -1; + if (AllSkills[gameskill].Infighting == LEVEL2_TOTALINFIGHTING) return 1; + if (AllSkills[gameskill].Infighting == LEVEL2_NOINFIGHTING) return -1; + return infighting; } } return 0; @@ -463,7 +490,9 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) MonsterHealth = other.MonsterHealth; FriendlyHealth = other.FriendlyHealth; NoPain = other.NoPain; + Infighting = other.Infighting; ArmorFactor = other.ArmorFactor; + HealthFactor = other.HealthFactor; return *this; } diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index e87e78483..c63359f4b 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -1045,6 +1045,19 @@ public: return text; } + int Draw(FOptionMenuDescriptor*desc, int y, int indent, bool selected) + { + if (mEntering) + { + // reposition the text so that the cursor is visible when in entering mode. + FString text = Represent(); + int tlen = SmallFont->StringWidth(text) * CleanXfac_1; + int newindent = screen->GetWidth() - tlen - CURSORSPACE; + if (newindent < indent) indent = newindent; + } + return FOptionMenuFieldBase::Draw(desc, y, indent, selected); + } + bool MenuEvent ( int mkey, bool fromcontroller ) { if ( mkey == MKEY_Enter ) diff --git a/src/namedef.h b/src/namedef.h index 0d49bba76..22dbe1b51 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -396,6 +396,7 @@ xx(Roll) xx(Scale) xx(ScaleX) xx(ScaleY) +xx(Floatbobphase) xx(Blocking) xx(Blockmonsters) diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 46c2b9f4c..670f53751 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -707,6 +707,7 @@ static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, mapthings[count].RenderStyle = STYLE_Count; mapthings[count].alpha = -1; mapthings[count].health = -1; + mapthings[count].FloatbobPhase = -1; if (xsprites != NULL && sprites[i].lotag == 710) { // Blood ambient sound diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 25724172c..203d1688d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1639,10 +1639,8 @@ bool AActor::OkayToSwitchTarget (AActor *other) int infight; if (flags5 & MF5_NOINFIGHTING) infight=-1; - else if (level.flags2 & LEVEL2_TOTALINFIGHTING) infight=1; - else if (level.flags2 & LEVEL2_NOINFIGHTING) infight=-1; - else infight = infighting; - + else infight = G_SkillProperty(SKILLP_Infight); + if (infight < 0 && other->player == NULL && !IsHostile (other)) { return false; // infighting off: Non-friendlies don't target other non-friendlies diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 35b0300ef..9c93ca15c 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1600,6 +1600,11 @@ FUNC(LS_Thing_Move) // [BC] return P_Thing_Move (arg0, it, arg1, arg2 ? false : true); } +enum +{ + TRANSLATION_ICE = 0x100007 +}; + FUNC(LS_Thing_SetTranslation) // Thing_SetTranslation (tid, range) { @@ -1616,6 +1621,10 @@ FUNC(LS_Thing_SetTranslation) { range = TRANSLATION(TRANSLATION_LevelScripted, (arg1-1)); } + else if (arg1 == TRANSLATION_ICE) + { + range = TRANSLATION(TRANSLATION_Standard, 7); + } else { range = 0; @@ -2991,7 +3000,7 @@ FUNC(LS_SendToCommunicator) FString msg; msg.Format("TXT_COMM%d", arg2); const char *str = GStrings[msg]; - if (msg != NULL) + if (str != NULL) { Printf (PRINT_CHAT, "%s\n", str); } diff --git a/src/p_map.cpp b/src/p_map.cpp index e8e5d6c84..5dd0967b9 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -938,10 +938,7 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // to harm / be harmed by anything. if (!victim->player && !shooter->player) { - int infight; - if (level.flags2 & LEVEL2_TOTALINFIGHTING) infight = 1; - else if (level.flags2 & LEVEL2_NOINFIGHTING) infight = -1; - else infight = infighting; + int infight = G_SkillProperty(SKILLP_Infight); if (infight < 0) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d5c5eb5d9..ab89ae04c 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4917,6 +4917,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mobj->SpawnPoint[2] = mthing->z; mobj->SpawnAngle = mthing->angle; mobj->SpawnFlags = mthing->flags; + if (mthing->FloatbobPhase >= 0 && mthing->FloatbobPhase < 64) mobj->FloatBobPhase = mthing->FloatbobPhase; if (mthing->gravity < 0) mobj->gravity = -mthing->gravity; else if (mthing->gravity > 0) mobj->gravity = FixedMul(mobj->gravity, mthing->gravity); else mobj->flags &= ~MF_NOGRAVITY; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 311bf8fc4..50e7f41d6 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1758,6 +1758,7 @@ void P_LoadThings (MapData * map) mti[i].RenderStyle = STYLE_Count; mti[i].alpha = -1; mti[i].health = 1; + mti[i].FloatbobPhase = -1; flags &= ~MTF_SKILLMASK; mti[i].flags = (short)((flags & 0xf) | 0x7e0); if (gameinfo.gametype == GAME_Strife) @@ -1842,6 +1843,7 @@ void P_LoadThings2 (MapData * map) mti[i].RenderStyle = STYLE_Count; mti[i].alpha = -1; mti[i].health = 1; + mti[i].FloatbobPhase = -1; } delete[] mtp; } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 0434d8bce..269ce7e3d 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -474,6 +474,7 @@ public: th->RenderStyle = STYLE_Count; th->alpha = -1; th->health = 1; + th->FloatbobPhase = -1; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { @@ -631,6 +632,11 @@ public: Flag(th->flags, MTF_SECRET, key); break; + case NAME_Floatbobphase: + CHECK_N(Zd | Zdt) + th->FloatbobPhase = CheckInt(key); + break; + case NAME_Renderstyle: { FName style = CheckString(key); diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index ec2843c79..dbc56cc56 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -713,11 +713,11 @@ BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) if ( hRT ) { - // Must wait process to terminate to guarantee that it has exited... - WaitForSingleObject(hProcess, INFINITE); - + // Must wait for process to terminate to guarantee that it has exited... + DWORD res = WaitForSingleObject(hProcess, 1000); CloseHandle(hRT); - bSuccess = TRUE; + bSuccess = (res == WAIT_OBJECT_0); + dwErr = WAIT_TIMEOUT; } if ( !bSuccess ) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 14440d884..9fd631d16 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1414,6 +1414,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) ACTION_PARAM_FIXED(LifeSteal, 5); ACTION_PARAM_INT(lifestealmax, 6); ACTION_PARAM_CLASS(armorbonustype, 7); + ACTION_PARAM_SOUND(MeleeSound, 8); + ACTION_PARAM_SOUND(MissSound, 9); if (!self->player) return; @@ -1443,7 +1445,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) P_LineAttack (self, angle, Range, pitch, Damage, NAME_Melee, PuffType, puffFlags, &linetarget, &actualdamage); - if (linetarget) + if (!linetarget) + { + if (MissSound) S_Sound(self, CHAN_WEAPON, MissSound, 1, ATTN_NORM); + } + else { if (LifeSteal && !(linetarget->flags5 & MF5_DONTDRAIN)) { @@ -1474,7 +1480,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (weapon != NULL) { - S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); + if (MeleeSound) S_Sound(self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); + else S_Sound (self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); } if (!(flags & CPF_NOTURN)) diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 13ae00936..a44515efb 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -8,7 +8,7 @@ ACTOR Inventory native Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG" action native A_JumpIfNoAmmo(state label); - action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); + action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = ""); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0); action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 2c43c10c6..fbe40cb43 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1602,10 +1602,24 @@ OptionMenu AdvSoundOptions Option "OPL Emulator Core", "opl_core", "OplCores" StaticText " " StaticText "GUS Emulation", 1 + TextField "GUS config file", "midi_config" Slider "MIDI voices", "midi_voices", 16, 256, 4, 0 Option "Emulate TiMidity", "midi_timiditylike", "OnOff" Option "Read DMXGUS lumps", "midi_dmxgus", "OnOff" Option "GUS memory size", "gus_memsize", "GusMemory" + StaticText " " + StaticText "FluidSynth", 1 + TextField "Patch set", "fluid_patchset" + Slider "Gain", "fluid_gain", 0, 10, 0.5, 1 + Option "Reverb", "fluid_reverb", "OnOff" + Slider "MIDI voices", "fluid_voices", 16, 4096, 16, 1 + // Leaving out the more advanced stuff for now. + StaticText " " + StaticText "Timidity++", 1 + TextField "Path for executable", "timidity_exe" + Option "Reverb", "timidity_reverb", "OnOff" + Option "Chorus", "timidity_chorus", "OnOff" + Slider "Relative volume", "timidity_mastervolume", 0, 4, 0.2, 1 } /*=======================================