From 67d8235459d1f14a5cdd0a68eaf5dba31bc5e86c Mon Sep 17 00:00:00 2001 From: Marisa the Magician Date: Wed, 15 Jan 2025 16:49:55 +0100 Subject: [PATCH] Overhaul the "swap weapon" prompt display. --- language.def_base | 2 +- language.es_base | 2 +- language.version | 4 +- zscript/handler/swwm_handler_process.zsc | 25 +++ zscript/hud/swwm_hud.zsc | 1 + zscript/hud/swwm_hudextra.zsc | 196 +++++++++++++++++++++++ zscript/weapons/swwm_baseweapon.zsc | 22 ++- 7 files changed, 240 insertions(+), 12 deletions(-) diff --git a/language.def_base b/language.def_base index ba8b0ca4c..6cbd8469a 100644 --- a/language.def_base +++ b/language.def_base @@ -732,7 +732,7 @@ D_SENTRYEMPTY = "Sentry has run our of ammo."; D_SENTRYFAR = "You're too far to recall the sentry."; D_ANDIRA = "\cjShe knows where you are...\c-"; SWWM_YNYKRONREADY = "The Ynykron Artifact is ready for firing."; -SWWM_SWAPWEAPON = "\cjPress \cfUse\cj to swap \cf%s\cj for \cf%s\cj.\c-"; +SWWM_SWAPWEAPON = "\cjPress \cfUse\cj to swap\n\cf%s\cj for \cf%s\c-"; SWWM_TODOWEAPON = "\cjThe \cf%s\cj is not yet implemented.\c-"; SWWM_TITLEPRESENTSA = "UnSX Team"; SWWM_TITLEPRESENTSB = "presents"; diff --git a/language.es_base b/language.es_base index 9c3c1bc81..67ea695c0 100644 --- a/language.es_base +++ b/language.es_base @@ -603,7 +603,7 @@ D_SPRITE = "El Sprite Divino ha soplado su último aliento."; D_TETHERFAIL = "El vínculo del Enlace de Seguridad fue obstruído."; D_ANDIRA = "\cjSabe donde estás...\c-"; SWWM_YNYKRONREADY = "El Artefacto Ynykron está listo para disparar."; -SWWM_SWAPWEAPON = "\cjPulsa \cfUsar\cj para cambiar \cf%s\cj por \cf%s\cj.\c-"; +SWWM_SWAPWEAPON = "\cjPulsa \cfUsar\cj para cambiar\n\cf%s\cj por \cf%s\c-"; SWWM_TODOWEAPON = "\cjEl \cf%s\cj aun no está implementado.\c-"; SWWM_TODOWEAPON_FEM = "\cjLa \cf%s\cj aun no está implementada.\c-"; SWWM_TITLEPRESENTSB = "presenta"; diff --git a/language.version b/language.version index 3de62ec0b..dc825940b 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r1165 \cu(Wed Jan 15 13:48:46 CET 2025)\c-"; -SWWM_SHORTVER="\cw1.3pre r1165 \cu(2025-01-15 13:48:46)\c-"; +SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r1166 \cu(Wed Jan 15 16:49:55 CET 2025)\c-"; +SWWM_SHORTVER="\cw1.3pre r1166 \cu(2025-01-15 16:49:55)\c-"; diff --git a/zscript/handler/swwm_handler_process.zsc b/zscript/handler/swwm_handler_process.zsc index 342d8c7f9..6ef4a6c2f 100644 --- a/zscript/handler/swwm_handler_process.zsc +++ b/zscript/handler/swwm_handler_process.zsc @@ -136,6 +136,31 @@ extend Class SWWMHandler } } } + else if ( e.Name.Left(15) ~== "swwmwpnswaptip." ) + { + let bar = SWWMStatusBar(StatusBar); + if ( !bar ) return; + // network IDs finally becoming useful here + uint ida = e.Name.Mid(15,8).ToInt(16); + uint idb = e.Name.Mid(23,8).ToInt(16); + let wa = Inventory(Object.GetNetworkEntity(ida)); + let wb = Inventory(Object.GetNetworkEntity(idb)); + if ( !wa || !wb ) return; + if ( e.Args[0] ) + { + // force to expire + if ( bar.cstip ) bar.cstip.Expire(wa,wb); + return; + } + if ( bar.cstip ) + { + bar.cstip.Poke(wa,wb); + return; + } + let tt = new("SWWMWeaponSwapTip").Init(wa,wb); + bar.cstip = tt; + bar.AttachMessage(tt,-2911); + } else if ( e.Name.Left(12) ~== "swwmnametag." ) { let bar = SWWMStatusBar(StatusBar); diff --git a/zscript/hud/swwm_hud.zsc b/zscript/hud/swwm_hud.zsc index eac00c189..f0d385ba3 100644 --- a/zscript/hud/swwm_hud.zsc +++ b/zscript/hud/swwm_hud.zsc @@ -142,6 +142,7 @@ Class SWWMStatusBar : BaseStatusBar int puzzlecnt, realpuzzlecnt; SWWMWeaponTooltip ctip; + SWWMWeaponSwapTip cstip; double mm_zoom; transient ThinkerIterator mi; // for map markers diff --git a/zscript/hud/swwm_hudextra.zsc b/zscript/hud/swwm_hudextra.zsc index 8e8aa4549..fdde726d5 100644 --- a/zscript/hud/swwm_hudextra.zsc +++ b/zscript/hud/swwm_hudextra.zsc @@ -225,6 +225,202 @@ Class SWWMAchievementNotification : HUDMessageBase } } +// weapon swap prompt +Class SWWMWeaponSwapTip : HUDMessageBase +{ + Inventory wa, wb; + SWWMWeapon swa, swb; + bool duala, dualb; + String wpna, wpnb, txt; + transient BrokenLines l; + double tics, holdtics, fadeintics, fadeouttics; + TextureID icoa, icob; + Font mSmallFont; + + // just code deduplication here + private void UpdateMe( Inventory fromweapon, Inventory toweapon ) + { + wa = fromweapon; + swa = SWWMWeapon(wa); + if ( !swa ) ThrowAbortException("swap from (%s) is not SWWMWeapon",wa?wa.GetClassName():'Null'); + // are we swapping from a dual weapon? + if ( swa.SisterWeapon && (swa.Amount>1) ) + { + wpna = swa.SisterWeapon.GetTag(); + icoa = GetIcon(swa.SisterWeapon); + duala = true; + } + else + { + wpna = swa.GetTag(); + icoa = GetIcon(swa); + duala = false; + } + wb = toweapon; + // are we swapping to a dual weapon? + if ( wb is 'SWWMDualWeaponGiver' ) + { + swb = SWWMDualWeaponGiver(wb).giveme[0]; + wpnb = wb.GetTag(); + icob = GetIcon(swb); + dualb = true; + } + else if ( wb is 'SWWMWeapon' ) + { + swb = SWWMWeapon(wb); + wpnb = swb.GetTag(); + icob = GetIcon(swb); + dualb = false; + } + else ThrowAbortException("swap to (%s) is not SWWMWeapon or SWWMDualWeaponGiver",wb?wb.GetClassName():'Null'); + txt = String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),wpna,wpnb); + if ( l ) l.Destroy(); + } + + private TextureID GetIcon( Weapon w ) + { + let [ico, applyScale] = StatusBar.GetInventoryIcon(w,StatusBar.DI_SKIPALTICON|StatusBar.DI_SKIPREADY); + return ico; + } + + SWWMWeaponSwapTip Init( Inventory fromweapon, Inventory toweapon ) + { + UpdateMe(fromweapon,toweapon); + holdtics = 50; + fadeintics = 5; + fadeouttics = 15; + tics = 0; + mSmallFont = Font.GetFont('TewiFont'); + return self; + } + + // used by weapons when an existing tip is already there + void Poke( Inventory fromweapon, Inventory toweapon ) + { + // update icons and text if different weapons + if ( (fromweapon != wa) || (toweapon != wb) ) + UpdateMe(fromweapon,toweapon); + // invert the fade out into a fade-in + // otherwise just wind the tics back to right after fade-in + if ( tics > (fadeintics+holdtics) ) + tics = fadeintics-(tics-(fadeintics+holdtics))/(fadeouttics/fadeintics); + else if ( tics > fadeintics ) + tics = fadeintics; + } + + // used by weapons when the swap has already happened + void Expire( Inventory fromweapon, Inventory toweapon ) + { + // just forces a fade out + if ( (fromweapon == wa) && (toweapon == wb) ) + tics = max(tics,fadeintics+holdtics); + } + + override bool Tick() + { + tics++; + return (tics > holdtics+fadeintics+fadeouttics); + } + + override void Draw( int bottom, int visibility ) + { + if ( tics <= 0 ) return; + double ymargin; + double hs; + Vector2 ss; + if ( SWWMStatusBar(StatusBar) ) + { + ymargin = SWWMStatusBar(StatusBar).ymargin0; + hs = SWWMStatusBar(StatusBar).hs0; + ss = SWWMStatusBar(StatusBar).ss0; + } + else + { + ymargin = clamp(swwm_hudmargin,0,10); + hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.); + ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs); + } + double fractic = System.GetTimeFrac(); + double ftics = tics+fractic; + double alpha = (ftics txtw ) txtw = lw; + } + int icow = 16; + int icoh = mSmallFont.GetHeight()*2; + if ( icoa.IsValid() ) + { + Vector2 sz = TexMan.GetScaledSize(icoa)*.125; + icow += int(sz.x)+(duala?12:4); + icoh = int(sz.y)+(duala?12:4); + } + else icow += mSmallFont.StringWidth(wpna); + if ( icob.IsValid() ) + { + Vector2 sz = TexMan.GetScaledSize(icob)*.125; + icow += int(sz.x)+(dualb?12:4); + icoh = max(icoh,int(sz.y)+(dualb?12:4)); + } + else + { + icow += mSmallFont.StringWidth(wpnb); + icoh = max(icoh,mSmallFont.GetHeight()); + } + int w = max(txtw,icow); + int h = icoh+4+mSmallFont.GetHeight()*l.Count(); + Vector2 pos = (int(ss.x/2),ss.y-(ymargin+80+h)); + Screen.Dim("Black",.5*alpha,int((pos.x-(w+4)/2)*hs),int((pos.y-2)*hs),int((w+4)*hs),int((h+4)*hs)); + // Left Icon + double x = pos.x-(icow/2); + if ( icoa.IsValid() ) + { + Vector2 sz = TexMan.GetScaledSize(icoa)*.125; + if ( duala ) + { + x += sz.x/2+6; + Screen.DrawTexture(icoa,false,(x-4)*hs,((pos.y+icoh/2)-4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true); + Screen.DrawTexture(icoa,false,(x+4)*hs,((pos.y+icoh/2)+4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true); + x += sz.x/2+6; + } + else + { + x += sz.x/2+2; + Screen.DrawTexture(icoa,false,x*hs,(pos.y+icoh/2)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true); + x += sz.x/2+2; + } + } + // Swap Arrow + String arr = "→"; + Screen.DrawText(mSmallFont,Font.CR_GREEN,x+(16-mSmallFont.StringWidth(arr))/2,pos.y+(icoh/2-mSmallFont.GetHeight()),arr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha); + arr = "←"; + Screen.DrawText(mSmallFont,Font.CR_GREEN,x+(16-mSmallFont.StringWidth(arr))/2,pos.y+(icoh/2),arr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha); + x += 16; + // Right Icon + if ( icob.IsValid() ) + { + Vector2 sz = TexMan.GetScaledSize(icob)*.125; + if ( dualb ) + { + x += sz.x/2+6; + Screen.DrawTexture(icob,false,(x-4)*hs,((pos.y+icoh/2)-4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true); + Screen.DrawTexture(icob,false,(x+4)*hs,((pos.y+icoh/2)+4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true); + } + else + { + x += sz.x/2+2; + Screen.DrawTexture(icob,false,x*hs,(pos.y+icoh/2)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true); + } + } + // Swap Message + for ( int i=0; i 1) ) - Console.MidPrint(SmallFont,String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),sw.SisterWeapon.GetTag(),GetTag())); - else Console.MidPrint(SmallFont,String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),sw.GetTag(),GetTag())); + uint ida = sw.GetNetworkID(); + uint idb = GetNetworkID(); + EventHandler.SendInterfaceEvent(consoleplayer,String.Format("swwmwpnswaptip.%08x%08x",ida,idb)); } return; } @@ -165,6 +164,10 @@ Class SWWMWeapon : Weapon abstract d.bSPECIAL = false; d.DropTime = 30; } + // notify the HUD tip (if any) to expire + uint ida = sw.GetNetworkID(); + uint idb = GetNetworkID(); + EventHandler.SendInterfaceEvent(consoleplayer,String.Format("swwmwpnswaptip.%08x%08x",ida,idb),1); } bUsePickup = true; bSWAPPEDTO = true; @@ -799,10 +802,9 @@ Class SWWMDualWeaponGiver : Inventory { if ( toucher.CheckLocalView() ) { - // use sisterweapon tag for dual wield (slot 2 weapons) - if ( sw.SisterWeapon && (sw.Amount > 1) ) - Console.MidPrint(SmallFont,String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),sw.SisterWeapon.GetTag(),GetTag())); - else Console.MidPrint(SmallFont,String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),sw.GetTag(),GetTag())); + uint ida = sw.GetNetworkID(); + uint idb = GetNetworkID(); + EventHandler.SendInterfaceEvent(consoleplayer,String.Format("swwmwpnswaptip.%08x%08x",ida,idb)); } return; } @@ -863,6 +865,10 @@ Class SWWMDualWeaponGiver : Inventory user.player.ReadyWeapon = null; user.player.PendingWeapon = WP_NOCHANGE; } + // notify the HUD tip (if any) to expire + uint ida = sw.GetNetworkID(); + uint idb = GetNetworkID(); + EventHandler.SendInterfaceEvent(consoleplayer,String.Format("swwmwpnswaptip.%08x%08x",ida,idb),1); } bUsePickup = true; Touch(user);