diff --git a/language.def_base b/language.def_base index 58037e563..04aa6051d 100644 --- a/language.def_base +++ b/language.def_base @@ -632,6 +632,11 @@ SWWM_GAMMAMODE1 = "Semi-Auto"; SWWM_GAMMAMODE2 = "3-Round Burst"; SWWM_GAMMAMODE3 = "Full Auto"; SWWM_GAMMAMODE4 = "FULLER AUTO"; +SWWM_DMRANK = "Rank:"; +SWWM_DMSPREAD = "Spread:"; +SWWM_PLACE1 = "1st"; +SWWM_PLACE2 = "2nd"; +SWWM_PLACE3 = "3rd"; // NOTE: do not localize these SWWM_ZNVTXT1 = "\cdDemolitionist\c-, it is me, \chZanaveth The Corruptor\c-. I have been witness of the act you have now acted, yes."; SWWM_ZNVTXT2 = "It is \cf%d\c- years since... and those magic words, I can see them again. Much impressed, very much impressed."; diff --git a/language.es_base b/language.es_base index 3243db92b..56ca3ce5c 100644 --- a/language.es_base +++ b/language.es_base @@ -543,6 +543,14 @@ SWWM_GAMMAMODE1 = "Semiautomático"; SWWM_GAMMAMODE2 = "Triple Ráfaga"; SWWM_GAMMAMODE3 = "Automático"; SWWM_GAMMAMODE4 = "SUPERAUTOMÁTICO"; +SWWM_DMRANK = "Posición:"; +SWWM_DMSPREAD = "Distancia:"; +SWWM_PLACE1 = "1º"; +SWWM_PLACE2 = "2º"; +SWWM_PLACE3 = "3º"; +SWWM_PLACE1_GENDER1 = "1ª"; +SWWM_PLACE2_GENDER1 = "2ª"; +SWWM_PLACE3_GENDER1 = "3ª"; // boss tags BT_BRUISERS = "Hermanos de Guerra"; BT_CYBIE = "Tirano de Babel"; diff --git a/language.version b/language.version index c8c96d007..7526fb60a 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r525 \cu(Fri 4 Jun 18:59:04 CEST 2021)\c-"; -SWWM_SHORTVER="\cw0.9.11b-pre r525 \cu(2021-06-04 18:59:04)\c-"; +SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r526 \cu(Fri 4 Jun 21:35:17 CEST 2021)\c-"; +SWWM_SHORTVER="\cw0.9.11b-pre r526 \cu(2021-06-04 21:35:17)\c-"; diff --git a/zscript/handler/swwm_handler_damage.zsc b/zscript/handler/swwm_handler_damage.zsc index fbf2e969a..470935f0a 100644 --- a/zscript/handler/swwm_handler_damage.zsc +++ b/zscript/handler/swwm_handler_damage.zsc @@ -73,7 +73,8 @@ extend Class SWWMHandler } if ( spawnme ) SWWMScoreObj.Spawn(-e.Damage,e.Thing.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+e.Thing.Height/2),ST_Damage,e.Thing); // update combat tracker for it - if ( !(e.Thing is 'BossBrain') ) + // note: don't update if it's a hostile player unless hurt by you or a friend + if ( !(e.Thing is 'BossBrain') && (!e.Thing.player || (!e.Thing.IsFriend(players[consoleplayer].mo) && e.DamageSource && e.DamageSource.IsFriend(players[consoleplayer].mo))) ) { for ( SWWMCombatTracker t=trackers; t; t=t.next ) { diff --git a/zscript/handler/swwm_handler_worldtick.zsc b/zscript/handler/swwm_handler_worldtick.zsc index fb212925f..880fbfb39 100644 --- a/zscript/handler/swwm_handler_worldtick.zsc +++ b/zscript/handler/swwm_handler_worldtick.zsc @@ -235,7 +235,7 @@ extend Class SWWMHandler continue; if ( !a.player && !a.bSOLID && !a.bSHOOTABLE && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') ) continue; - if ( !thesight && !(a.IsFriend(players[consoleplayer].mo) && !(a.player && (a.player.mo != a))) && !players[consoleplayer].Camera.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) + if ( !thesight && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !(a.IsFriend(players[consoleplayer].mo) && !(a.player && (a.player.mo != a))) && !players[consoleplayer].Camera.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; if ( a.bKILLED || (a.Health <= 0) ) continue; @@ -291,7 +291,7 @@ extend Class SWWMHandler continue; if ( !a.player && !a.bSOLID && !a.bSHOOTABLE && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') ) continue; - if ( !thesight && !a.IsFriend(players[consoleplayer].mo) && !players[consoleplayer].Camera.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) + if ( !thesight && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !a.IsFriend(players[consoleplayer].mo) && !players[consoleplayer].Camera.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; if ( a.bKILLED || (a.Health <= 0) ) continue; diff --git a/zscript/hud/swwm_hud.zsc b/zscript/hud/swwm_hud.zsc index 279e059ee..5aba29f02 100644 --- a/zscript/hud/swwm_hud.zsc +++ b/zscript/hud/swwm_hud.zsc @@ -70,6 +70,13 @@ Class SWWMStatusBar : BaseStatusBar Color mm_backcolor, mm_cdwallcolor, mm_efwallcolor, mm_fdwallcolor, mm_gridcolor, mm_interlevelcolor, mm_intralevelcolor, mm_lockedcolor, mm_notseencolor, mm_portalcolor, mm_secretsectorcolor, mm_secretwallcolor, mm_specialwallcolor, mm_thingcolor, mm_thingcolor_citem, mm_thingcolor_friend, mm_thingcolor_item, mm_thingcolor_monster, mm_thingcolor_ncmonster, mm_thingcolor_shootable, mm_thingcolor_vipitem, mm_thingcolor_missile, mm_tswallcolor, mm_unexploredsecretcolor, mm_wallcolor, mm_xhaircolor, mm_yourcolor; bool mm_displaylocks, mm_drawautopage; + // deathmatch stuff + int playercount, rank, lead; + bool tiedscore; + Array sortplayers; + Array teamactive; + Array teamscore; + // if playing in Japanese, returns an alternate font of the same height // Tewi -> MPlus // Miniwi -> k6x8 @@ -375,6 +382,34 @@ Class SWWMStatusBar : BaseStatusBar qsort_itemsense(a,p+1,h); } + // quicksort (player scores) + private int partition_playerscore( Array a, int l, int h ) + { + PlayerInfo pv = a[h]; + int i = (l-1); + for ( int j=l; j<=(h-1); j++ ) + { + if ( pv.fragcount < a[j].fragcount ) + { + i++; + PlayerInfo tmp = a[j]; + a[j] = a[i]; + a[i] = tmp; + } + } + PlayerInfo tmp = a[h]; + a[h] = a[i+1]; + a[i+1] = tmp; + return i+1; + } + private void qsort_playerscore( Array a, int l, int h ) + { + if ( l >= h ) return; + int p = partition_playerscore(a,l,h); + qsort_playerscore(a,l,p-1); + qsort_playerscore(a,p+1,h); + } + override void Tick() { Super.Tick(); @@ -465,7 +500,6 @@ Class SWWMStatusBar : BaseStatusBar if ( !trk.mytarget || trk.mytarget.bDORMANT || trk.mytarget.bINVISIBLE ) continue; // ignore local player if ( trk.mytarget == CPlayer.mo ) continue; - if ( trk.myplayer && deathmatch ) continue; // no players in dm if ( trk.mytarget is 'PlayerGone' ) continue; // ignore "gone" players int mtime = 35; if ( thesight && (trk.lasthealth > 0) ) mtime += 105; @@ -587,6 +621,55 @@ Class SWWMStatusBar : BaseStatusBar // also try with different endianness, just in case DetachMessageID(0x4e504557); // WEPN DetachMessageID(0x564e4953); // SINV + // deathmatch stuff + if ( !deathmatch ) return; + if ( teamplay ) + { + if ( teamactive.Size() != Teams.Size() ) teamactive.Resize(Teams.Size()); + if ( teamscore.Size() != Teams.Size() ) teamscore.Resize(Teams.Size()); + for ( int i=0; i CPlayer.fragcount ) + rank += 1; + else if ( players[i].fragcount == CPlayer.fragcount ) + tiedscore = true; + if ( players[i].fragcount > highscore ) + highscore = players[i].fragcount; + } + if ( sortplayers.Size() != playercount ) sortplayers.Resize(playercount); + for ( int i=0, j=0; i= 1. ) continue; Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc); tag = targ.mytag; - if ( tag != "" ) + if ( (tag != "") && !targ.myplayer ) { if ( targ.legged && (targ.mutated || swwm_ldspoil) ) { @@ -767,8 +850,15 @@ Class SWWMStatusBar : BaseStatusBar Vector2 barpos = vpos-(barsiz/2.); barpos.y -= 16.; Font fnt = LangFont(swwm_bigtags?mTewiFont:mMiniwiFont); + int col = Font.CR_WHITE; + if ( teamplay ) + { + int team = targ.myplayer.GetTeam(); + if ( team != -1 ) col = Font.FindFontColor(Teams[team].mName); // this works in practice because team names are the same as their text colors + if ( col == -1 ) col = Font.CR_WHITE; + } if ( swwm_targettags || targ.myplayer && (tag != "") ) - Screen.DrawText(fnt,Font.CR_WHITE,(barpos.x+barsiz.x/2.-(fnt.StringWidth(tag)*hsb.x)/2.)/hsb.x,(barpos.y-fnt.GetHeight()*hsb.y)/hsb.y,tag,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright); + Screen.DrawText(fnt,col,(barpos.x+barsiz.x/2.-(fnt.StringWidth(tag)*hsb.x)/2.)/hsb.x,(barpos.y-fnt.GetHeight()*hsb.y)/hsb.y,tag,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright); Screen.DrawTexture(EnemyBTex,false,barpos.x/hsb.x,barpos.y/hsb.y,DTA_VirtualWidthF,ssb.x,DTA_VirtualHeightF,ssb.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipTop,cliptop,DTA_ClipBottom,clipbottom,DTA_ClipLeft,clipleft,DTA_ClipRight,clipright); double ht = clamp(targ.intp.GetValue(),0,targ.maxhealth*10); double hw = (min(ht,targ.maxhealth)*50.)/targ.maxhealth; @@ -1479,6 +1569,14 @@ Class SWWMStatusBar : BaseStatusBar } } + private String OrdinalStr( int val, int gender ) + { + String lstr = "SWWM_PLACE"..val.."_GENDER"..gender; + String str = StringTable.Localize("$"..lstr); + if ( str != lstr ) return str; + return StringTable.Localize("$SWWM_PLACE"..val); + } + private void DrawScore() { String sstr; @@ -1539,19 +1637,19 @@ Class SWWMStatusBar : BaseStatusBar yy += fnt.GetHeight(); } fnt = LangFont(mMiniwiFont); - if ( (level.total_monsters > 0) && am_showmonsters ) + if ( (level.total_monsters > 0) && am_showmonsters && !deathmatch ) { str = String.Format("\cxK \c-%d\cu/\c-%d",level.killed_monsters,level.total_monsters); Screen.DrawText(fnt,(level.killed_monsters>=level.total_monsters)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); yy += fnt.GetHeight(); } - if ( (level.total_items > 0) && am_showitems ) + if ( (level.total_items > 0) && am_showitems && !deathmatch ) { str = String.Format("\cxI \c-%d\cu/\c-%d",level.found_items,level.total_items); Screen.DrawText(fnt,(level.found_items>=level.total_items)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); yy += fnt.GetHeight(); } - if ( (level.total_secrets > 0) && am_showsecrets ) + if ( (level.total_secrets > 0) && am_showsecrets && !deathmatch ) { str = String.Format("\cxS \c-%d\cu/\c-%d",level.found_secrets,level.total_secrets); Screen.DrawText(fnt,(level.found_secrets>=level.total_secrets)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); @@ -1574,8 +1672,47 @@ Class SWWMStatusBar : BaseStatusBar } yy += 3; } + if ( deathmatch ) + { + yy += 9; + if ( playercount <= 1 ) return; + xx = int(ss.x-(margin+2)); + String str; + Font fnt = LangFont(mTewiFont); + if ( teamplay ) + { + // draw team scores + for ( int i=0; i 0 ) str = String.Format("\cx%s \cj+%d\c-",StringTable.Localize("$SWWM_DMSPREAD"),lead); + else str = String.Format("\cx%s \cj%d\c-",StringTable.Localize("$SWWM_DMSPREAD"),lead); + Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); + yy += fnt.GetHeight()+3; + // draw top 3 players + for ( int i=0; i= maxhealth) ) return; @@ -470,8 +463,13 @@ Class SWWMCombatTracker : Thinker } if ( (mytarget.bISMONSTER || mytarget.player) && !mytarget.bINVISIBLE && !mytarget.bCORPSE ) { - // players (but not voodoo dolls), always visible - if ( mytarget.player && (mytarget.player.mo == mytarget) ) updated = level.maptime+35; + // players (but not voodoo dolls), always if friendly, otherwise only update if visible + if ( mytarget.player && (mytarget.player.mo == mytarget) ) + { + if ( mytarget.IsFriend(players[consoleplayer].mo) ) updated = level.maptime+35; + else if ( ((mxdist <= 0) || (mytarget.Vec3To(players[consoleplayer].Camera).length() < mxdist)) && players[consoleplayer].Camera.CheckSight(mytarget,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) + updated = level.maptime; + } // friendlies within a set distance else if ( mytarget.bFRIENDLY && ((mxdist <= 0) || (mytarget.Vec3To(players[consoleplayer].Camera).length() < mxdist)) && players[consoleplayer].Camera.CheckSight(mytarget,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) updated = level.maptime+35; // enemies within a set distance that have us as target