Stuff and things.

This commit is contained in:
Mari the Deer 2020-01-26 21:17:20 +01:00
commit cf29142ff5
8 changed files with 283 additions and 39 deletions

View file

@ -463,9 +463,12 @@ be configurable.
### Top left corner
Message display, with separate queues for chat, critical messages and
obituaries so you won't miss anything important. Max lines of each type are
configurable, along with their lifespan.
Message display. Can be configured to show different numbers of lines depending
on whether the chat prompt is open. Chat messages take much longer to expire
than others, so there's less of a chance to miss them, as they might pop back
up when the less important ones expire. A full message history can also be read
at any time in the Knowledge Base. Repeated messages are compressed with a
multiplier suffix.
### Top right corner
@ -495,8 +498,8 @@ Your health and armor, along with an inventory bar.
### Bottom border
Pickup messages. Can configure how many to display and how long they stay, plus
an additional option to merge repeated messages (given a multiplier suffix).
Pickup messages. Repeated pickups will have a multiplier suffix added. Total
lines shown are also configurable.
### Bottom right corner

View file

@ -11,4 +11,7 @@ user int swwm_mutevoice = 0; // mute demolitionist voice
// 1 - combat comments
// 2 - item/secret comments
// 3 - map start comment
// 4 - pain/death and grunts
// 4 - pain/death and grunts
user int swwm_chatduration = 900; // lifespan of chat messages
user int swwm_msgduration = 240; // lifespan of other messages
user int swwm_pickduration = 120; // lifespan of pickup messages

View file

@ -106,7 +106,11 @@ D_RAGEKIT = "The Ragekit has ragequit.";
D_REFRESHER = "The Refresher boost has ended.";
D_WARARMOR = "The War Armor is no more.";
// messages
SWWM_FINDSECRET = "%s found a secret. +%d";
SWWM_FINDSECRET = "\cf%s\cf found a secret. +%d\c-";
SWWM_FINDKEY = "\cf%s\cf got the %s. +%d\c-";
SWWM_LASTSECRET = "\cf%s\cf found the last secret. +%d\c-";
SWWM_LASTITEM = "\cf%s\cf got the last item. +%d\c-";
SWWM_LASTMONSTER = "\cf%s\cf killed the last monster. +%d\c-";
/* SUBTITLES */
// new weapon received

View file

@ -10,6 +10,50 @@ enum ESWWMGZChannels
CHAN_JETPACK = 63206
};
// Scoreing
Class SWWMCredits : Thinker
{
PlayerInfo myplayer;
int credits;
static void GiveCredits( PlayerInfo p, int amount )
{
let c = FindCredits(p);
if ( (c.credits+amount < c.credits) || (c.credits+amount > 999999999) ) c.credits = 999999999;
else c.credits += amount;
}
static bool TakeCredits( PlayerInfo p, int amount )
{
let c = FindCredits(p);
// too much!
if ( (c.credits-amount < 0) || (c.credits-amount > c.credits) ) return false;
c.credits -= amount;
return true;
}
static int GetCredits( PlayerInfo p )
{
let c = FindCredits(p);
return c.credits;
}
private static SWWMCredits FindCredits( PlayerInfo p )
{
let ti = ThinkerIterator.Create("SWWMCredits",STAT_STATIC);
SWWMCredits t;
while ( t = SWWMCredits(ti.Next()) )
{
if ( t.myplayer != p ) continue;
return t;
}
t = new("SWWMCredits");
t.ChangeStatNum(STAT_STATIC);
t.myplayer = p;
return t;
}
}
// One-liners
Class SWWMOneLiner : HUDMessageBase
{
@ -579,6 +623,8 @@ Class SWWMHandler : EventHandler
int spreecount[MAXPLAYERS];
int lastkill[MAXPLAYERS];
int multilevel[MAXPLAYERS];
int lastitemcount[MAXPLAYERS];
int creditsbridge[MAXPLAYERS]; // curse the gap between play/ui
transient CVar mutevoice;
@ -642,6 +688,24 @@ Class SWWMHandler : EventHandler
flashes.Delete(i);
i--;
}
// countable item scoring
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] ) continue;
// while we're at it, also update the bridge var for counting credits
creditsbridge[i] = SWWMCredits.GetCredits(players[i]);
if ( players[i].itemcount > lastitemcount[i] )
{
int score = 25;
if ( level.total_items == level.found_items )
{
score = 2500;
Console.Printf(StringTable.Localize("$SWWM_LASTITEM"),players[i].GetUserName(),score);
}
SWWMCredits.GiveCredits(players[i],score);
lastitemcount[i] = players[i].itemcount;
}
}
// combat tracking
// prune old entries
for ( int i=0; i<combatactors.Size(); i++ )
@ -715,6 +779,14 @@ Class SWWMHandler : EventHandler
if ( !e.Thing.player && !e.Thing.bIsMonster && !e.Thing.bCountKill ) return;
if ( (e.DamageSource && e.DamageSource.player && (e.DamageSource != e.Thing)) )
{
if ( e.DamageSource == players[consoleplayer].mo )
{
highesttic = gametic;
if ( (!lastcombat || (gametic > lastcombat+20)) && (mutevoice.GetInt() < 1) )
lastcombat = AddOneliner("scorekill",15);
}
if ( !e.Thing.default.bCountKill ) // no credits
return;
int pnum = e.DamageSource.PlayerNumber();
if ( level.maptime < (lastkill[pnum]+5*Thinker.TICRATE) )
multilevel[pnum]++;
@ -726,14 +798,14 @@ Class SWWMHandler : EventHandler
score = int(score*(1.+.5*min(multilevel[pnum],16)));
if ( !tookdamage[pnum] ) score += 100+50*spreecount[pnum];
if ( e.Thing.bBOSS ) score += 10000;
if ( level.killed_monsters == level.total_monsters ) score += 5000;
e.DamageSource.GiveInventory("SWWMCredits",score);
if ( level.killed_monsters == level.total_monsters )
{
score += 5000;
Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER",e.DamageSource.player.GetUserName()),5000);
}
SWWMCredits.GiveCredits(e.DamageSource.player,score);
// TODO floating score for HUD
spreecount[pnum]++;
if ( e.DamageSource != players[consoleplayer].mo ) return;
highesttic = gametic;
if ( (!lastcombat || (gametic > lastcombat+20)) && (mutevoice.GetInt() < 1) )
lastcombat = AddOneliner("scorekill",15);
}
}

View file

@ -12,37 +12,105 @@ Class SWWMStatusBar : BaseStatusBar
HealthTex[4], FuelTex, DashTex;
HUDFont mTewiFont;
Array<MsgLine> ChatMsgs, DeathMsgs, MiscMsgs, PickMsgs;
// "Full History" contains all messages since session start, nothing is flushed
// this can be accessed from a section of the knowledge base
Array<MsgLine> MainQueue, PickupQueue, FullHistory;
Actor targetactors[40], scoreactors[60], keyactors[10];
Vector3 exitpoints[10], uselines[10];
// client cvars
transient CVar safezone, maxchat[2], maxpick;
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol;
// shared stuff
Vector2 ss, hs;
int margin;
double FracTic;
int chatopen;
DynamicValueInterpolator HealthInter, ScoreInter, FuelInter, DashInter;
override void FlushNotify()
{
ChatMsgs.Clear();
DeathMsgs.Clear();
MiscMsgs.Clear();
PickMsgs.Clear();
// flush non-chat messages
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( MainQueue[i].type >= PRINT_CHAT ) continue;
MainQueue.Delete(i);
i--;
}
}
override bool ProcessNotify( EPrintLevel printlevel, String outline )
{
if ( !chatduration ) chatduration = CVar.GetCVar('swwm_chatduration',players[consoleplayer]);
if ( !msgduration ) msgduration = CVar.GetCVar('swwm_msgduration',players[consoleplayer]);
if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]);
let m = new("MsgLine");
m.str = outline.Left(outline.Length()-1); // strip newline
m.type = printlevel;
m.tic = gametic;
// set lifespan for each type
if ( printlevel == PRINT_LOW ) m.tic += pickduration.GetInt();
else if ( printlevel <= PRINT_HIGH ) m.tic += msgduration.GetInt();
else m.tic += chatduration.GetInt();
m.rep = 1;
// append to full history
FullHistory.Push(m);
// ignore during intermission
if ( gamestate != GS_LEVEL ) return false;
if ( (printlevel < PRINT_LOW) || (printlevel > PRINT_TEAMCHAT) ) return true; // we couldn't care less about these
if ( printlevel == PRINT_LOW )
{
// check if repeated
for ( int i=0; i<PickupQueue.Size(); i++ )
{
if ( PickupQueue[i].str != m.str ) continue;
// delete old one and add its repeats
m.rep += PickupQueue[i].rep;
PickupQueue.Delete(i);
break;
}
PickupQueue.Push(m);
}
else
{
// check if repeated
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( MainQueue[i].str != m.str ) continue;
// delete old one and add its repeats
m.rep += MainQueue[i].rep;
MainQueue.Delete(i);
break;
}
MainQueue.Push(m);
}
return true;
}
override void Tick()
{
Super.Tick();
// prune old messages
for ( int i=0; i<PickupQueue.Size(); i++ )
{
if ( gametic < PickupQueue[i].tic ) continue;
PickupQueue.Delete(i);
i--;
}
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( gametic < MainQueue[i].tic ) continue;
MainQueue.Delete(i);
i--;
}
// update target actors
// update floating scores
// update interpolators
HealthInter.Update(CPlayer.health);
ScoreInter.Update(CPlayer.mo.CountInv("SWWMCredits"));
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd ) ScoreInter.Update(hnd.creditsbridge[CPlayer.mo.PlayerNumber()]);
else ScoreInter.Update(0);
let d = Demolitionist(CPlayer.mo);
if ( d )
{
@ -69,6 +137,9 @@ Class SWWMStatusBar : BaseStatusBar
HealthTex[3] = TexMan.CheckForTexture("graphics/HUD/HealthBar3.png",TexMan.Type_Any);
ScoreTex = TexMan.CheckForTexture("graphics/HUD/ScoreBox.png",TexMan.Type_Any);
WeaponTex = TexMan.CheckForTexture("graphics/HUD/WeaponBox.png",TexMan.Type_Any);
ChatTex[0] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop.png",TexMan.Type_Any);
ChatTex[1] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine.png",TexMan.Type_Any);
ChatTex[2] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom.png",TexMan.Type_Any);
mTewiFont = HUDFont.Create("TewiShaded");
HealthInter = DynamicValueInterpolator.Create(100,.1,1,100);
ScoreInter = DynamicValueInterpolator.Create(0,.1,1,1000);
@ -171,8 +242,95 @@ Class SWWMStatusBar : BaseStatusBar
private void DrawMessages()
{
if ( !pickcol ) pickcol = CVar.GetCVar('msg0color',players[consoleplayer]);
if ( !obitcol ) obitcol = CVar.GetCVar('msg1color',players[consoleplayer]);
if ( !critcol ) critcol = CVar.GetCVar('msg2color',players[consoleplayer]);
if ( !chatcol ) chatcol = CVar.GetCVar('msg3color',players[consoleplayer]);
if ( !teamcol ) teamcol = CVar.GetCVar('msg4color',players[consoleplayer]);
// common message area
if ( MainQueue.Size() > 0 )
{
int mstart = max(0,MainQueue.Size()-(1+maxchat[chatopen>=gametic].GetInt()));
double xx = margin, yy = margin;
Screen.DrawTexture(ChatTex[0],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy++;
for ( int i=mstart; i<MainQueue.Size(); i++ )
{
int col = critcol.GetInt();
if ( MainQueue[i].type == PRINT_MEDIUM ) col = obitcol.GetInt();
else if ( MainQueue[i].type == PRINT_CHAT ) col = chatcol.GetInt();
else if ( MainQueue[i].type == PRINT_TEAMCHAT ) col = teamcol.GetInt();
String cstr = MainQueue[i].str;
if ( MainQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",MainQueue[i].rep);
BrokenLines l = mTewiFont.mFont.BreakLines(cstr,361);
for ( int j=0; j<l.Count(); j++ )
{
Screen.DrawTexture(ChatTex[1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,col,xx+4,yy,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy += 13;
}
}
Screen.DrawTexture(ChatTex[2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
// pickup messages
if ( PickupQueue.Size() > 0 )
{
// reverse order since they're drawn bottom to top
int mend = max(0,PickupQueue.Size()-(1+maxpick.GetInt()));
double yy = ss.y-(margin+40);
for ( int i=PickupQueue.Size()-1; i>=mend; i-- )
{
String cstr = PickupQueue[i].str;
if ( PickupQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",PickupQueue[i].rep);
BrokenLines l = mTewiFont.mFont.BreakLines(cstr,int(ss.x*.75));
for ( int j=l.Count()-1; j>=0; j-- )
{
int len = mTewiFont.mFont.StringWidth(l.StringAt(j));
double xx = (ss.x-len)/2.;
Screen.Dim("Black",.8,int((xx-6)*hs.x),int(yy*hs.y),int((len+12)*hs.x),int(15*hs.y));
Screen.DrawText(mTewiFont.mFont,pickcol.GetInt(),xx,yy+1,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
yy -= 15;
}
}
}
}
override bool DrawChat( String txt )
{
// ignore during intermission
if ( gamestate != GS_LEVEL ) return false;
chatopen = gametic+1; // have to add 1 because DrawChat is called after everything else
double xx = 2;
double yy = ss.y-14;
Screen.Dim("Black",.8,0,Screen.GetHeight()-int(15*hs.y),Screen.GetWidth(),int(15*hs.y));
String pname = players[consoleplayer].GetUserName();
// strip colors
for ( int i=0; i<pname.CodePointCount(); i++ )
{
int remlen = 0;
if ( pname.GetNextCodePoint(i) != 0x1C )
continue;
remlen++;
if ( pname.GetNextCodePoint(i+remlen) == 0x5B )
while ( pname.GetNextCodePoint(i+remlen) != 0x5D )
remlen++;
remlen++;
pname.Remove(i,remlen);
}
String fullstr = String.Format("\cq%s\cd@\cqdemolitionist%d\cn ~ \c-wall %s%s",pname,consoleplayer+1,txt,mTewiFont.mFont.GetCursor());
// cut out to fit
int w = mTewiFont.mFont.StringWidth(fullstr);
if ( w > ss.x-4 )
{
// draw trailing dots
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,xx,yy,"...",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// shift back
xx -= w-(ss.x-4);
// draw trimmed
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ClipLeft,int(26*hs.x));
}
else Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return true;
}
override void Draw( int state, double TicFrac )

View file

@ -1,17 +1,3 @@
// Scoring
Class SWWMCredits : Inventory
{
Default
{
+INVENTORY.UNTOSSABLE;
+INVENTORY.UNDROPPABLE;
+INVENTORY.UNCLEARABLE;
+INVENTORY.ALWAYSPICKUP;
Inventory.MaxAmount 999999999;
Inventory.InterHubAmount 999999999;
}
}
// Base class for all SWWM Armors
Class SWWMArmor : Armor
{

View file

@ -6,6 +6,7 @@ Class Demolitionist : PlayerPawn
double dashfuel, dashboost;
int dashcooldown, boostcooldown, fuelcooldown;
bool dashsnd;
bool key_reentrant;
int lastdamage;
bool lastground;
@ -109,6 +110,8 @@ Class Demolitionist : PlayerPawn
override void Tick()
{
Super.Tick();
if ( !myvoice ) myvoice = CVar.GetCVar('swwm_voicetype',player);
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
if ( player.onground && !bNoGravity && !lastground && (waterlevel < 2) && (health > 0) )
{
if ( lastvelz < -30 )
@ -127,6 +130,8 @@ Class Demolitionist : PlayerPawn
}
}
if ( lastvelz < -10 ) A_StartSound("demolitionist/runstop",CHAN_FOOTSTEP,CHANF_OVERLAP);
if ( (lastvelz < -gruntspeed) && (mute.GetInt() < 4) )
A_StartSound(String.Format("voice/%s/grunt",myvoice.GetString()),CHAN_DEMOVOICE,CHANF_OVERLAP);
A_Footstep(0,true,clamp(-lastvelz*0.05,0.01,1.0));
}
lastground = player.onground;
@ -454,11 +459,15 @@ Class Demolitionist : PlayerPawn
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
int score = 500;
// last secret (this is called before counting it up, so have to subtract)
if ( level.found_secrets == level.total_secrets-1 ) score = 5000;
Console.Printf(StringTable.Localize("$SWWM_FINDSECRET"),player.GetUserName(),score);
if ( level.found_secrets == level.total_secrets-1 )
{
score = 5000;
Console.Printf(StringTable.Localize("$SWWM_LASTSECRET"),player.GetUserName(),score);
}
else Console.Printf(StringTable.Localize("$SWWM_FINDSECRET"),player.GetUserName(),score);
if ( CheckLocalView() && (mute.GetInt() < 2) ) SWWMHandler.AddOneliner("findsecret",40);
GiveInventory("SWWMCredits",score);
return true;
SWWMCredits.GiveCredits(player,score);
return false;
}
override void AddInventory( Inventory item )
{
@ -466,14 +475,20 @@ Class Demolitionist : PlayerPawn
Super.AddInventory(item);
if ( (item is 'Weapon') && CheckLocalView() && (mute.GetInt() < 2) )
SWWMHandler.AddOneliner("getweapon");
if ( multiplayer && (item is 'Key') )
if ( (item is 'Key') && !key_reentrant )
{
// score
int score = 250;
Console.Printf(StringTable.Localize("$SWWM_FINDKEY"),player.GetUserName(),item.GetTag(),score);
SWWMCredits.GiveCredits(player,score);
// share all keys in mp
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || !players[i].mo || (i == PlayerNumber()) )
continue;
if ( players[i].mo is 'Demolitionist' ) Demolitionist(players[i].mo).key_reentrant = true;
players[i].mo.GiveInventory(item.GetClass(),1);
if ( players[i].mo is 'Demolitionist' ) Demolitionist(players[i].mo).key_reentrant = false;
}
}
}

View file

@ -398,6 +398,7 @@ Class ExplodiumGun : SWWMWeapon
p.pitch = asin(-dir.z);
p.vel = dir*p.speed;
p.vel.z += 5.;
p.vel += vel*.5;
}
action void A_DropMag( bool loaded = false )
@ -409,6 +410,7 @@ Class ExplodiumGun : SWWMWeapon
c.angle = angle;
c.pitch = pitch;
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](-1.2,.3)-(0,0,FRandom[Junk](2,3));
c.vel += vel*.5;
}
action void A_DropCasing()
@ -421,6 +423,7 @@ Class ExplodiumGun : SWWMWeapon
c.angle = angle;
c.pitch = pitch;
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](2,4)-(0,0,FRandom[Junk](2,3));
c.vel += vel*.5;
}
Default