- 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 "<item> 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 "<weapon> has no ammo." messages.
This commit is contained in:
Marisa the Magician 2019-09-29 17:21:32 +02:00
commit a54f1495c7
12 changed files with 117 additions and 64 deletions

View file

@ -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

View file

@ -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)

View file

@ -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 */

View file

@ -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;

View file

@ -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

View file

@ -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();

View file

@ -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:

View file

@ -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()
{

View file

@ -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 )
{

View file

@ -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()
{

View file

@ -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;

View file

@ -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<mDesc.mItems.Size(); i++ )
{
if ( mDesc.mItems[i].CheckCoordinate(x,y) )