From a54f1495c73ea9380ba06d33f4b338d6d57d2131 Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Sun, 29 Sep 2019 17:21:32 +0200 Subject: [PATCH] Beta 4. - Fix Dispersion Pistol altfire not ending early when releasing the button. - Dispersion Pistol now changes fire speed based on upgrade level, as intended. - Reduced Razorclaw twiddle animation frequency, it was getting annoying. - Impaler altfire now doesn't work underwater, as intended. - Impaler crystals deal less damage when underwater. - Impaler no longer loses charge underwater while the crystal is unloaded. - Impaler beam no longer homes in onto friendlies. - Fixed missing Impaler melee obituary. - Flamegun disallows firing while underwater, to prevent wasting ammo uselessly. - Flares and Seeds can be stacked until int.max (give cheats and whatnot are still capped at 20 though). - Fixed Minigun not displaying the bullet box ammo icon in the 0.83 hud. - Fixed mouse input in the main menu at high resolutions (wasn't accounting for scaling, oops). - Added " selected." messages. Dunno if DT will need this too. - Light Sentry now uses the more reliable native IsHostile() function to detect targets. - [flak_m] Added " has no ammo." messages. --- GunLore.md | 10 +++++--- Readme.md | 6 +++++ language.txt | 2 ++ zscript/bonesaw.zsc | 3 ++- zscript/dispersionpistol.zsc | 41 ++++++++++++++--------------- zscript/flamegun.zsc | 8 +++--- zscript/impaler.zsc | 19 +++++++++----- zscript/miscitems.zsc | 8 +++--- zscript/uhealitems.zsc | 1 + zscript/unrealcommon.zsc | 28 +++++++++++++++++--- zscript/unrealhud.zsc | 50 ++++++++++++++++++++---------------- zscript/unrealmenus.zsc | 5 ++++ 12 files changed, 117 insertions(+), 64 deletions(-) diff --git a/GunLore.md b/GunLore.md index bebf91c..2466e28 100644 --- a/GunLore.md +++ b/GunLore.md @@ -258,15 +258,17 @@ A powerful energy weapon that uses enriched Tarydium crystals. Wielded by members of the Krall Dark Angel clan. Primary fire: Releases the currently held crystal, upon contact with any -solid object or surface it will explode spectacularly (depends on charge). +solid object or surface it will explode spectacularly depending on its charge. +Its effects and damage are severely weakened when underwater. Secondary fire: Redirects the energy contained within the crystal into an unstable beam of energy that arcs between any living creatures in front of the -user. +user. Doesn't work underwater. -Reload: Manually switches between projectile and melee mode. +Reload: Manually loads/unloads the crystal. Useful if you need to go for a +swim and don't want to lose that precious charge. -If no crystal is loaded, both fire modes will be replaced with a stab. +With no crystal loaded, both fire modes will be replaced with a melee attack. ## Flamethrower diff --git a/Readme.md b/Readme.md index b48f017..2994792 100644 --- a/Readme.md +++ b/Readme.md @@ -80,6 +80,12 @@ Doom Tournament (currently the devel branch is required). - Impaler "slice" animation for melee alt - Separate proto content into an add-on (if people want) + - Alternate flamethrower secondary that behaves more like the Unreal Bible + describes (unlit blobs at a rate of 4 per second that catch on fire with + explosions/lava/etc). + - Alternate Impaler primary that follows the Bible (laser shots from the + crystal), shifts crystal shooting to pressing both buttons at once. + - Actual Bonesaw? - RTNP add-on - Monster pack (someday) diff --git a/language.txt b/language.txt index 8f3100e..09247e8 100644 --- a/language.txt +++ b/language.txt @@ -211,6 +211,7 @@ M_MSNOFLOOR = "Cannot deploy Sentry at this height."; M_MSNOFLAT = "Cannot deploy Sentry on such a steep slope."; M_NSTOOFAR = "Cannot recall Sentry from this distance."; M_FFNOROOM = "No room to activate Force Field."; +M_ISELECT = "%s selected."; S_MINHUD = "Health %d Score %d Ammo %d"; S_MINHUD2 = "Health %d Score %d Ammo %d/%d"; /* Menus */ @@ -454,6 +455,7 @@ M_MSNOFLOOR = "No se puede colocar la Torreta a esta altura."; M_MSNOFLAT = "No se puede colocar la Torreta en una cuesta tan inclinada."; M_NSTOOFAR = "No se puede retirar la Torreta desde esta distancia."; M_FFNOROOM = "No hay espacio para activar el Campo de Fuerza."; +M_ISELECT = "Seleccionado %s."; S_MINHUD = "Salud %d Puntuación %d Munición %d"; S_MINHUD2 = "Salud %d Puntuación %d Munición %d/%d"; /* Menus */ diff --git a/zscript/bonesaw.zsc b/zscript/bonesaw.zsc index 7dcbcdb..125f5a0 100644 --- a/zscript/bonesaw.zsc +++ b/zscript/bonesaw.zsc @@ -132,7 +132,8 @@ Class Bonesaw : UnrealWeapon Wait; Idle: #### # 2 A_Overlay(-9999,"Dummy"); - CSWI ABCDE 15 A_Jump(32,"Twiddle"); + CSWI ABCDE 15; + CSWI A 0 A_Jump(32,"Twiddle"); Goto Idle+1; Twiddle: #### # 2; diff --git a/zscript/dispersionpistol.zsc b/zscript/dispersionpistol.zsc index 1b8d861..7700316 100644 --- a/zscript/dispersionpistol.zsc +++ b/zscript/dispersionpistol.zsc @@ -661,6 +661,7 @@ Class DispersionPistol : UnrealWeapon { Weapon weap = Weapon(invoker); if ( !weap ) return ResolveState(null); + if ( !(player.cmd.buttons&BT_ALTATTACK) ) return ResolveState(next); DefaultAmmo(weap.Ammo1).rechargephase = 0; UTMainHandler.DoSwing(self,(FRandom[DPistol](-1,1),FRandom[DPistol](-1,1)),0.02*invoker.chargesize,0,2,SWING_Spring); A_WeaponOffset(FRandom[DPistol](-1,1)*1.2*invoker.chargesize,32+FRandom[DPistol](-1,1)*1.2*invoker.chargesize); @@ -787,28 +788,28 @@ Class DispersionPistol : UnrealWeapon } Fire1: #### # 3 A_DispFire(); - DPF1 ABC 5; - DPI1 A 5 A_Refire("Fire1"); + DPF1 ABC 3; + DPI1 A 3 A_Refire("Fire1"); Goto Idle; Fire2: #### # 3 A_DispFire(); - DPF2 ABC 5; - DPI2 A 5 A_Refire("Fire2"); + DPF2 ABC 4; + DPI2 A 3 A_Refire("Fire2"); Goto Idle; Fire3: #### # 3 A_DispFire(); - DPF3 ABC 5; - DPI3 A 5 A_Refire("Fire3"); + DPF3 ABC 6; + DPI3 A 3 A_Refire("Fire3"); Goto Idle; Fire4: #### # 3 A_DispFire(); - DPF4 ABC 5; - DPI4 A 5 A_Refire("Fire4"); + DPF4 ABC 8; + DPI4 A 3 A_Refire("Fire4"); Goto Idle; Fire5: #### # 3 A_DispFire(); - DPF5 ABC 5; - DPI5 A 5 A_Refire("Fire5"); + DPF5 ABC 10; + DPI5 A 3 A_Refire("Fire5"); Goto Idle; AltFire: #### # 0 @@ -831,40 +832,40 @@ Class DispersionPistol : UnrealWeapon Wait; AltRelease1: #### # 3 A_DispAltFire(); - DPF1 ABC 8; - DPI1 A 6; + DPF1 ABC 6; + DPI1 A 3; Goto Idle; AltFire2: #### # 1 A_DispCharge(1); Wait; AltRelease2: #### # 3 A_DispAltFire(); - DPF2 ABC 8; - DPI2 A 6; + DPF2 ABC 6; + DPI2 A 3; Goto Idle; AltFire3: #### # 1 A_DispCharge(1); Wait; AltRelease3: #### # 3 A_DispAltFire(); - DPF3 ABC 8; - DPI3 A 6; + DPF3 ABC 6; + DPI3 A 3; Goto Idle; AltFire4: #### # 1 A_DispCharge(1); Wait; AltRelease4: #### # 3 A_DispAltFire(); - DPF4 ABC 8; - DPI4 A 6; + DPF4 ABC 6; + DPI4 A 3; Goto Idle; AltFire5: #### # 1 A_DispCharge(1); Wait; AltRelease5: #### # 3 A_DispAltFire(); - DPF5 ABC 8; - DPI5 A 6; + DPF5 ABC 6; + DPI5 A 3; Goto Idle; Upgrade: #### # 1 diff --git a/zscript/flamegun.zsc b/zscript/flamegun.zsc index 660c559..b202648 100644 --- a/zscript/flamegun.zsc +++ b/zscript/flamegun.zsc @@ -356,8 +356,10 @@ Class FlameGun : UnrealWeapon TNT1 A 1 { A_CheckReload(); - if ( invoker.Ammo1.Amount >= 30 ) A_WeaponReady(); - else A_WeaponReady(WRF_NOSECONDARY); + int flags = (waterlevel>=2)?WRF_NOFIRE:0; + if ( invoker.Ammo1.Amount < 30 ) + flags |= WRF_NOSECONDARY; + A_WeaponReady(flags); } Wait; Idle: @@ -381,7 +383,7 @@ Class FlameGun : UnrealWeapon FGNF CDEF 1; FGNF G 0 { - if ( invoker.CheckAmmo(0,false,true) ) + if ( invoker.CheckAmmo(0,false,true) && (waterlevel < 2) ) A_Refire("Refire"); } FGNF G 0 A_ClearRefire(); diff --git a/zscript/impaler.zsc b/zscript/impaler.zsc index 539d12f..196bce4 100644 --- a/zscript/impaler.zsc +++ b/zscript/impaler.zsc @@ -284,7 +284,7 @@ Class ImpalerBolt : Actor while ( bt.Next() ) { let a = bt.Thing; - if ( !a || !a.bSHOOTABLE || !a.bISMONSTER || (a.Health <= 0) || !CheckSight(a) || (start.Hitlist.Find(a) < start.HitList.Size()) ) continue; + if ( !a || !a.bSHOOTABLE || !a.bISMONSTER || (a.Health <= 0) || target.IsFriend(a) || !CheckSight(a) || (start.Hitlist.Find(a) < start.HitList.Size()) ) continue; Vector3 dirto = level.Vec3Diff(pos,a.Vec3Offset(0,0,a.height/2)); double dist = dirto.length(); dirto /= dist; @@ -341,7 +341,7 @@ Class ImpalerBolt : Actor s.scale *= .4; s.vel = (FRandom[Impaler](-1,1),FRandom[Impaler](-1,1),FRandom[Impaler](-1,1)).unit()*FRandom[Impaler](.2,.8); } - if ( (special1 < int(10*specialf1)) && (special2 < int(40*specialf1**.5)) && (start.hitlist.Size() < int(4*specialf1)) ) + if ( (special1 < int(10*specialf1)) && (special2 < int(40*specialf1**.5)) && (start.hitlist.Size() < int(4*specialf1)) && (waterlevel <= 0) ) { if ( !next ) { @@ -612,6 +612,12 @@ Class ImpalerProjectile : Actor Spawn: TPRJ A 1 { + if ( waterlevel > 0 ) + { + let b = Spawn("UTBubble",pos); + b.vel = vel*0.5; + special1 = -30; + } roll += 15.; double ang, pt; int numpt; @@ -676,7 +682,7 @@ Class Impaler : UnrealWeapon override int, int, bool, bool GetClipAmount() { - return ClipCount, -1, (ClipCount<10), false; + return HasGem?ClipCount:-1, -1, (ClipCount<10), false; } action void A_ImpalerFire() { @@ -836,7 +842,7 @@ Class Impaler : UnrealWeapon if ( (Ammo1.Amount <= 0) && (ClipCount <= 0) ) SelectionOrder = 6600; else SelectionOrder = default.SelectionOrder; if ( Owner.player.ReadyWeapon != self ) return; - if ( (Owner.waterlevel > 2) && !(level.maptime%5) ) + if ( (Owner.waterlevel > 2) && !(level.maptime%5) && HasGem ) ClipCount = max(0,ClipCount-1); let psp = Owner.player.FindPSprite(-2); if ( psp ) psp.alpha = clamp(ClipCount/double(default.ClipCount),0.,1.); @@ -849,6 +855,7 @@ Class Impaler : UnrealWeapon Default { Tag "$T_IMPALER"; + Obituary "$O_IMPALERHIT"; Inventory.PickupMessage "$I_IMPALER"; Weapon.UpSound "impaler/select"; Weapon.SlotNumber 7; @@ -891,7 +898,7 @@ Class Impaler : UnrealWeapon let weap = Weapon(invoker); int flags = 0; if ( weap.Ammo1.Amount > 0 ) flags |= WRF_ALLOWRELOAD; - if ( invoker.HasGem && (invoker.ClipCount <= 0) ) flags |= WRF_NOSECONDARY; + if ( invoker.HasGem && ((invoker.ClipCount <= 0) || (waterlevel >= 2)) ) flags |= WRF_NOSECONDARY; A_WeaponReady(flags); } Wait; @@ -943,7 +950,7 @@ Class Impaler : UnrealWeapon { A_DrainAmmo(); invoker.special1++; - return A_JumpIf((invoker.ClipCount<=0)||!(player.cmd.buttons&BT_ALTATTACK),"AltRelease"); + return A_JumpIf((invoker.ClipCount<=0)||!(player.cmd.buttons&BT_ALTATTACK)||(waterlevel>=2),"AltRelease"); } Loop; AltRelease: diff --git a/zscript/miscitems.zsc b/zscript/miscitems.zsc index 694172d..f036dbe 100644 --- a/zscript/miscitems.zsc +++ b/zscript/miscitems.zsc @@ -482,6 +482,7 @@ Class Flare : UnrealInventory Inventory.PickupMessage "$I_FLARES"; Inventory.Icon "I_Flare"; Inventory.MaxAmount 20; + +UNREALINVENTORY.UNLIMITEDCOPIES; } override bool Use( bool pickup ) { @@ -2160,9 +2161,9 @@ Class MinigunSentryBase : Actor { if ( !user.player || !InStateSequence(CurState,FindState("Idle")) ) return false; if ( abs(DeltaAngle(angle,AngleTo(user))) < 120 ) return false; - if ( deathmatch || !master ) + if ( !master || ((user != master) && master.IsHostile(user)) ) { - if ( master && (user != master) && master.CheckLocalView() ) + if ( master && master.CheckLocalView() ) Console.Printf(StringTable.Localize("$M_SENTRYHIJACK")); if ( SentryItem.TransferOwnership(user,self) ) return false; // on first touch only transfer ownership @@ -2404,8 +2405,7 @@ Class SentryGun : Actor bool IsEnemy( Actor a ) { if ( !a || !a.bSHOOTABLE || !a.bISMONSTER || (a.Health <= 0) ) return false; - if ( deathmatch ) return ((a != master) && (a.master != master)); - return (!bFRIENDLY || (!a.bFRIENDLY && !a.player)); + return IsHostile(a); } bool HasTarget() { diff --git a/zscript/uhealitems.zsc b/zscript/uhealitems.zsc index 274cb5a..12eea57 100644 --- a/zscript/uhealitems.zsc +++ b/zscript/uhealitems.zsc @@ -179,6 +179,7 @@ Class Seeds : UnrealInventory Inventory.PickupMessage "$I_SEEDS"; Inventory.Icon "I_Seed"; Inventory.MaxAmount 20; + +UNREALINVENTORY.UNLIMITEDCOPIES; } override bool Use( bool pickup ) { diff --git a/zscript/unrealcommon.zsc b/zscript/unrealcommon.zsc index c08fe29..a79a98a 100644 --- a/zscript/unrealcommon.zsc +++ b/zscript/unrealcommon.zsc @@ -643,6 +643,7 @@ Class UnrealInventory : Inventory Property Charge : DefaultCharge; FlagDef DrawSpecial : UItemFlags, 0; // hud draws special1 as amount + FlagDef UnlimitedCopies : UItemFlags, 1; // can pick up unlimited copies // Drawstuffs under HUD virtual ui void PreRender( double lbottom ) {} @@ -666,7 +667,8 @@ Class UnrealInventory : Inventory { Super.AttachToOwner(other); if ( !Charge ) Charge = DefaultCharge; - InterHubAmount = MaxAmount; // it's annoying to set this per-subclass + // it's annoying to set this per-subclass + InterHubAmount = bUNLIMITEDCOPIES?int.max:MaxAmount; } override bool HandlePickup( Inventory item ) { @@ -681,17 +683,35 @@ Class UnrealInventory : Inventory // if there's charge to spare, increase amount if ( addcharge > charge ) { - Amount = min(MaxAmount,Amount+item.Amount); + if ( (Amount > 0) && (Amount+item.Amount < 0) ) Amount = int.max; + Amount = min(bUNLIMITEDCOPIES?int.max:MaxAmount,Amount+item.Amount); charge = addcharge-charge; } } - else Amount = min(MaxAmount,Amount+item.Amount); // fully charged new copy, just increase + else + { + if ( (Amount > 0) && (Amount+item.Amount < 0) ) Amount = int.max; + Amount = min(bUNLIMITEDCOPIES?int.max:MaxAmount,Amount+item.Amount); // fully charged new copy, just increase + } } else Charge = DefaultCharge; // reset charge item.bPickupGood = true; return true; } - return Super.HandlePickup(item); + if ( item.GetClass() == GetClass() ) + { + if ( (Amount < MaxAmount) || bUNLIMITEDCOPIES || (sv_unlimited_pickup && !item.ShouldStay()) ) + { + if ( (Amount > 0) && (Amount+item.Amount < 0) ) + Amount = int.max; + else Amount += item.Amount; + if ( Amount > MaxAmount && !sv_unlimited_pickup && !bUNLIMITEDCOPIES ) + Amount = MaxAmount; + item.bPickupGood = true; + } + return true; + } + return false; } override void Tick() { diff --git a/zscript/unrealhud.zsc b/zscript/unrealhud.zsc index 0fc50c0..9fce7d6 100644 --- a/zscript/unrealhud.zsc +++ b/zscript/unrealhud.zsc @@ -89,16 +89,17 @@ Class UnrealHUD : BaseStatusBar mMapFont = HUDFont.Create(WhiteFont); OldLargeFont = Font.GetFont('UOldLargeFont'); OldSmallFont = Font.GetFont('UOldSmallFont'); - OldAmmo[0] = "Disp083"; - OldAmmo[1] = "Clip083"; - OldAmmo[2] = "Tary083"; - OldAmmo[3] = "Asmd083"; - OldAmmo[4] = "Rokt083"; - OldAmmo[5] = "Flak083"; - OldAmmo[6] = "Razor083"; - OldAmmo[7] = "Bio083"; - OldAmmo[8] = "Rifle083"; - OldAmmo[9] = "Mini083"; + // arranged so weapon-specific icons are checked first + OldAmmo[0] = "Mini083"; + OldAmmo[1] = "Disp083"; + OldAmmo[2] = "Clip083"; + OldAmmo[3] = "Tary083"; + OldAmmo[4] = "Asmd083"; + OldAmmo[5] = "Rokt083"; + OldAmmo[6] = "Flak083"; + OldAmmo[7] = "Razor083"; + OldAmmo[8] = "Bio083"; + OldAmmo[9] = "Rifle083"; OldAmmo[10] = "Shell083"; OldAmmo[11] = "Impal083"; OldAmmo[12] = "Flame083"; @@ -108,16 +109,16 @@ Class UnrealHUD : BaseStatusBar OldAmmo[16] = "Smini083"; OldAmmo[17] = "Peace083"; OldAmmo[18] = "OLSMP083"; - OldAmmoType[0] = "DefaultAmmo"; - OldAmmoType[1] = "UMiniAmmo"; - OldAmmoType[2] = "StingerAmmo"; - OldAmmoType[3] = "AsmdAmmo"; - OldAmmoType[4] = "URocketAmmo"; - OldAmmoType[5] = "UFlakBox"; - OldAmmoType[6] = "RazorAmmo"; - OldAmmoType[7] = "UBioAmmo"; - OldAmmoType[8] = "URifleAmmo"; - OldAmmoType[9] = "UMinigun"; + OldAmmoType[0] = "UMinigun"; + OldAmmoType[1] = "DefaultAmmo"; + OldAmmoType[2] = "UMiniAmmo"; + OldAmmoType[3] = "StingerAmmo"; + OldAmmoType[4] = "AsmdAmmo"; + OldAmmoType[5] = "URocketAmmo"; + OldAmmoType[6] = "UFlakBox"; + OldAmmoType[7] = "RazorAmmo"; + OldAmmoType[8] = "UBioAmmo"; + OldAmmoType[9] = "URifleAmmo"; OldAmmoType[10] = "UShells"; OldAmmoType[11] = "ImpalerAmmo"; OldAmmoType[12] = "FlameAmmo"; @@ -193,7 +194,7 @@ Class UnrealHUD : BaseStatusBar { if ( (i.Amount <= 1) && !((i is 'UnrealInventory') && UnrealInventory(i).bDRAWSPECIAL) ) return; double TempX = CurX, TempY = CurY; - string itxt = String.Format("%d",((i is 'UnrealInventory')&&UnrealInventory(i).bDRAWSPECIAL)?i.special1:i.Amount); + string itxt = String.Format("%d",((i is 'UnrealInventory')&&UnrealInventory(i).bDRAWSPECIAL)?i.special1:min(99999,i.Amount)); CurX += 30; CurY += 23; CurX -= TinyRedFont.StringWidth(itxt); @@ -724,7 +725,12 @@ Class UnrealHUD : BaseStatusBar override void Tick() { Super.Tick(); - CPlayer.inventorytics = 0; + if ( CPlayer.inventorytics > 0 ) + { + if ( CPlayer.mo.InvSel ) + Console.Printf(StringTable.Localize("$M_ISELECT"),CPlayer.mo.InvSel.GetTag()); + CPlayer.inventorytics = 0; + } vtracer.ignore = CPlayer.mo; vtracer.trace(CPlayer.mo.Vec2OffsetZ(0,0,CPlayer.viewz),CPlayer.mo.CurSector,(cos(CPlayer.mo.angle)*cos(CPlayer.mo.pitch),sin(CPlayer.mo.angle)*cos(CPlayer.mo.pitch),-sin(CPlayer.mo.pitch)),1000,0); if ( vtracer.Results.HitType != TRACE_HitActor ) return; diff --git a/zscript/unrealmenus.zsc b/zscript/unrealmenus.zsc index ae9b95d..11e491c 100644 --- a/zscript/unrealmenus.zsc +++ b/zscript/unrealmenus.zsc @@ -25,11 +25,16 @@ Class UnrealListMenu : ListMenu int sel = -1; if ( mFocusControl ) { + x = ((x-(screen.GetWidth()/2))/CleanXfac)+160; + y = ((y-(screen.GetHeight()/2))/CleanYfac)+100; mFocusControl.MouseEvent(type,x,y); return true; } else { + // menu uses different scaling + x /= CleanXfac_1; + y /= CleanYfac_1; for ( int i=0; i