swwmgz_m/zscript/swwm_hud.zsc
Marisa Kirisame 88afdafd1d Initial implementation of Eviscerator. Animations + Sounds.
Force weapons to always bob, like in DT/Doomreal. Will fine tune this later so the bobbing doesn't make firing guns look awkward.
Fixed crash when opening the chat prompt due to an excess %s.
Consider the possibility of adding dual wielding to the Explodium Gun eventually.
2020-03-12 12:18:03 +01:00

912 lines
36 KiB
Text

// The SWWM GZ HUD is mostly built on top of what I had already done for SWWM Z, also a bit of Dark Souls
Class MsgLine
{
String str;
int tic, type, rep;
}
Class SWWMStatusBar : BaseStatusBar
{
TextureID StatusTex, WeaponTex, ScoreTex, InventoryTex, ChatTex[6],
HealthTex[5], FuelTex, DashTex, EnemyBTex, EnemyHTex[5];
HUDFont mTewiFont, mMiniwiFont, mMPlusFont;
// "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;
// sorted arrays of various elements
Array<SWWMInterest> intpoints;
Array<SWWMScoreObj> scoreobjs;
Array<SWWMCombatTracker> trackers;
// the event handler, holding all sorts of stuff
SWWMHandler hnd;
// client cvars
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol, targetter, healthnums, scorenums, scorebonus, targettag, lang;
// shared stuff
Vector2 ss, hs;
int margin;
double FracTic;
int chatopen;
// shared from renderunderlay, needed for proper interpolation of some things
Vector3 viewpos, viewrot;
// libeye stuff
swwmLe__ProjScreen proj;
swwmLe__GLScreen gl_proj;
swwmLe__SWScreen sw_proj;
swwmLe__Viewport viewport;
bool can_project;
transient CVar cvar_renderer;
DynamicValueInterpolator HealthInter, ScoreInter, FuelInter, DashInter;
// returns MPlus if we're playing in Japanese, otherwise returns the requested font
Font LangFont( HUDFont req )
{
if ( !lang ) lang = CVar.GetCVar('language',players[consoleplayer]);
if ( lang.GetString() ~== "jp" ) return mMPlusFont.mFont;
return req.mFont;
}
override void FlushNotify()
{
// flush interpolators (useful since this virtual gets called
// when loading saves, too)
HealthInter.Reset(CPlayer.Health);
ScoreInter.Reset(SWWMCredits.Get(CPlayer));
FuelInter.Reset((CPlayer.mo is 'Demolitionist')?int(Demolitionist(CPlayer.mo).dashfuel):0);
DashInter.Reset((CPlayer.mo is 'Demolitionist')?int((40-Demolitionist(CPlayer.mo).dashcooldown)*3.):0);
if ( level.maptime <= 1 )
{
// flush ALL messages
MainQueue.Clear();
PickupQueue.Clear();
return;
}
// 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 ProcessMidPrint( Font fnt, String msg, bool bold )
{
// check for Korax lines
if ( msg == StringTable.Localize("$TXT_ACS_MAP02_11_AREYO") )
EventHandler.SendNetworkEvent("swwmkoraxline",0,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP13_11_MYSER") )
EventHandler.SendNetworkEvent("swwmkoraxline",1,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP22_29_ITHIN") )
EventHandler.SendNetworkEvent("swwmkoraxline",2,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP27_10_THENA") )
EventHandler.SendNetworkEvent("swwmkoraxline",3,consoleplayer);
else if ( msg == StringTable.Localize("$TXT_ACS_MAP35_14_TOFAC") )
EventHandler.SendNetworkEvent("swwmkoraxline",4,consoleplayer);
return false;
}
override bool ProcessNotify( EPrintLevel printlevel, String outline )
{
let m = new("MsgLine");
m.str = outline.Left(outline.Length()-1); // strip newline
m.type = printlevel;
m.tic = level.maptime;
m.rep = 1;
// append chat messages to full history
if ( (printlevel == PRINT_CHAT) || (printlevel == PRINT_TEAMCHAT) )
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;
}
void PrepareProjection()
{
if ( !cvar_renderer ) cvar_renderer = CVar.GetCVar("vid_rendermode",players[consoleplayer]);
if ( !cvar_renderer )
{
can_project = proj = gl_proj;
return;
}
switch ( cvar_renderer.GetInt() )
{
case 0:
case 1:
proj = sw_proj;
break;
default:
proj = gl_proj;
break;
}
can_project = proj;
}
private bool CmpTarget( SWWMCombatTracker a, SWWMCombatTracker b )
{
if ( !a || !b ) return true;
return (a.myplayer && !b.myplayer);
}
private bool CmpScore( SWWMScoreObj a, SWWMScoreObj b )
{
if ( !a || !b ) return true;
int srt[4] = { Font.CR_GOLD, Font.CR_FIRE, Font.CR_GREEN, Font.CR_RED };
int s1 = 0, s2 = 0;
for ( int i=0; i<3; i++ )
{
if ( a.tcolor == srt[i] ) s1 = i;
if ( b.tcolor == srt[i] ) s2 = i;
}
return s1 < s2;
}
private bool CmpInterest( SWWMInterest a, SWWMInterest b )
{
if ( !a || !b ) return true;
return a.type < b.type;
}
private bool CmpDist( Vector3 a, Vector3 b )
{
double dista = level.Vec3Diff(viewpos,a).length();
double distb = level.Vec3Diff(viewpos,b).length();
return (dista < distb);
}
override void Tick()
{
Super.Tick();
PrepareProjection();
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]);
if ( !targetter ) targetter = CVar.GetCVar('swwm_targeter',players[consoleplayer]);
if ( !healthnums ) healthnums = CVar.GetCVar('swwm_healthnums',players[consoleplayer]);
if ( !scorenums ) scorenums = CVar.GetCVar('swwm_scorenums',players[consoleplayer]);
// prune old messages
for ( int i=0; i<PickupQueue.Size(); i++ )
{
if ( level.maptime < (PickupQueue[i].tic+35*pickduration.GetInt()) ) continue;
PickupQueue.Delete(i);
i--;
}
for ( int i=0; i<MainQueue.Size(); i++ )
{
if ( (MainQueue[i].type <= PRINT_HIGH) && (level.maptime < (MainQueue[i].tic+35*msgduration.GetInt())) ) continue;
else if ( (MainQueue[i].type > PRINT_HIGH) && (level.maptime < (MainQueue[i].tic+35*chatduration.GetInt())) ) continue;
MainQueue.Delete(i);
i--;
}
// update interpolators
HealthInter.Update(CPlayer.health);
if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
ScoreInter.Update(SWWMCredits.Get(CPlayer));
let d = Demolitionist(CPlayer.mo);
if ( d )
{
FuelInter.Update(int(d.dashfuel));
DashInter.Update(int((40-d.dashcooldown)*3.));
}
else
{
FuelInter.Update(0);
DashInter.Update(0);
}
// let weapons update their own interpolators
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' )
SWWMWeapon(CPlayer.ReadyWeapon).HudTick();
bool thesight = CPlayer.mo.FindInventory("Omnisight");
if ( thesight )
{
// update omnisight stuff
if ( intpoints.Size() != hnd.intpoints_cnt )
intpoints.Resize(hnd.intpoints_cnt);
int i = 0;
for ( SWWMInterest poi=hnd.intpoints; poi; poi=poi.next )
intpoints[i++] = poi;
// sort by distance
for ( int i=0; i<hnd.intpoints_cnt; i++ )
{
int j = 1;
while ( j < hnd.intpoints_cnt )
{
int k = j;
while ( (k > 0) && (CmpInterest(intpoints[k-1],intpoints[k]) || CmpDist(intpoints[k-1].pos,intpoints[k].pos)) )
{
SWWMInterest tmp = intpoints[k];
intpoints[k] = intpoints[k-1];
intpoints[k-1] = tmp;
k--;
}
j++;
}
}
}
if ( targetter.GetBool() )
{
// update target stuff
if ( trackers.Size() != hnd.trackers_cnt )
trackers.Resize(hnd.trackers_cnt);
int i = 0, actual = 0;
for ( SWWMCombatTracker trk=hnd.trackers; trk; trk=trk.next )
{
actual++;
// ignore player unless chasecamming
if ( (trk.mytarget == players[consoleplayer].mo) && (players[consoleplayer].Camera == players[consoleplayer].mo) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue;
if ( trk.myplayer && deathmatch ) continue; // no players in dm
int mtime = 35;
if ( thesight && (trk.lasthealth > 0) ) mtime += 105;
if ( level.maptime > trk.updated+mtime ) continue;
trackers[i++] = trk;
}
// squeeze if some were discarded
if ( i != hnd.trackers_cnt )
trackers.Resize(i);
// sort by distance (give priority to players)
for ( int i=0; i<trackers.Size(); i++ )
{
int j = 1;
while ( j < trackers.Size() )
{
int k = j;
while ( (k > 0) && (CmpTarget(trackers[k-1],trackers[k]) || CmpDist(trackers[k-1].pos,trackers[k].pos)) )
{
SWWMCombatTracker tmp = trackers[k];
trackers[k] = trackers[k-1];
trackers[k-1] = tmp;
k--;
}
j++;
}
}
}
// update floating scores, adding the scorenums first, then the damnums
int total_sz = 0;
if ( scorenums.GetBool() ) total_sz += hnd.scorenums_cnt;
if ( healthnums.GetBool() ) total_sz += min(50,hnd.damnums_cnt);
if ( scoreobjs.Size() != total_sz )
scoreobjs.Resize(total_sz);
int i = 0;
if ( scorenums.GetBool() )
{
for ( SWWMScoreObj scr=hnd.scorenums; scr; scr=scr.next )
scoreobjs[i++] = scr;
}
if ( healthnums.GetBool() )
{
for ( SWWMScoreObj scr=hnd.damnums; scr && (i<total_sz); scr=scr.next )
scoreobjs[i++] = scr;
}
// sort by distance
for ( int i=0; i<total_sz; i++ )
{
int j = 1;
while ( j < total_sz )
{
int k = j;
while ( (k > 0) && (CmpScore(scoreobjs[k-1],scoreobjs[k]) || CmpDist(scoreobjs[k-1].pos,scoreobjs[k].pos)) )
{
SWWMScoreObj tmp = scoreobjs[k];
scoreobjs[k] = scoreobjs[k-1];
scoreobjs[k-1] = tmp;
k--;
}
j++;
}
}
}
override void Init()
{
Super.Init();
SetSize(0,640,360);
StatusTex = TexMan.CheckForTexture("graphics/HUD/StatusBox.png",TexMan.Type_Any);
DashTex = TexMan.CheckForTexture("graphics/HUD/DashBar.png",TexMan.Type_Any);
FuelTex = TexMan.CheckForTexture("graphics/HUD/FuelBar.png",TexMan.Type_Any);
HealthTex[0] = TexMan.CheckForTexture("graphics/HUD/HealthBar0.png",TexMan.Type_Any);
HealthTex[1] = TexMan.CheckForTexture("graphics/HUD/HealthBar1.png",TexMan.Type_Any);
HealthTex[2] = TexMan.CheckForTexture("graphics/HUD/HealthBar2.png",TexMan.Type_Any);
HealthTex[3] = TexMan.CheckForTexture("graphics/HUD/HealthBar3.png",TexMan.Type_Any);
HealthTex[4] = TexMan.CheckForTexture("graphics/HUD/HealthBarS.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);
ChatTex[3] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop_Smol.png",TexMan.Type_Any);
ChatTex[4] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine_Smol.png",TexMan.Type_Any);
ChatTex[5] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom_Smol.png",TexMan.Type_Any);
InventoryTex = TexMan.CheckForTexture("graphics/HUD/InventoryBox.png",TexMan.Type_Any);
EnemyBTex = TexMan.CheckForTexture("graphics/HUD/EnemyBox.png",TexMan.Type_Any);
EnemyHTex[0] = TexMan.CheckForTexture("graphics/HUD/EnemyBar0.png",TexMan.Type_Any);
EnemyHTex[1] = TexMan.CheckForTexture("graphics/HUD/EnemyBar1.png",TexMan.Type_Any);
EnemyHTex[2] = TexMan.CheckForTexture("graphics/HUD/EnemyBar2.png",TexMan.Type_Any);
EnemyHTex[3] = TexMan.CheckForTexture("graphics/HUD/EnemyBar3.png",TexMan.Type_Any);
EnemyHTex[4] = TexMan.CheckForTexture("graphics/HUD/EnemyBarS.png",TexMan.Type_Any);
mTewiFont = HUDFont.Create("TewiShaded");
mMiniwiFont = HUDFont.Create("MiniwiShaded");
mMPlusFont = HUDFont.Create("MPlusShaded");
HealthInter = DynamicValueInterpolator.Create(100,.1,1,100);
ScoreInter = DynamicValueInterpolator.Create(0,.1,1,1000);
FuelInter = DynamicValueInterpolator.Create(120,.5,1,100);
DashInter = DynamicValueInterpolator.Create(120,.5,1,40);
gl_proj = new("swwmLe__GLScreen");
sw_proj = new("swwmLe__SWScreen");
PrepareProjection();
hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
}
static private string FormatDist( double dist )
{
double meters = dist/32.;
if ( meters > 1000. ) return String.Format("\cj%d\cckm",int(meters/1000.));
return String.Format("\cj%d\ccm",int(meters));
}
private void DrawTarget()
{
// don't draw when dead or with automap open
if ( (CPlayer.health <= 0) || automapactive ) return;
if ( !targettag ) targettag = CVar.GetCVar('swwm_targettags',players[consoleplayer]);
viewport.FromHud();
proj.CacheResolution();
proj.CacheFov(players[consoleplayer].fov);
proj.Reorient(ViewPos,ViewRot);
proj.BeginProjection();
Vector3 vdir = (cos(ViewRot.x)*cos(ViewRot.y),sin(ViewRot.x)*cos(ViewRot.y),-sin(ViewRot.y));
bool thesight = !!CPlayer.mo.FindInventory("Omnisight");
// points of interest
String tag;
if ( thesight )
{
for ( int i=0; i<intpoints.Size(); i++ )
{
let poi = intpoints[i];
if ( !poi ) continue;
Vector3 tdir = Level.Vec3Diff(ViewPos,poi.pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
if ( poi.type == INT_Key ) tag = String.Format("\cf%s\c-",StringTable.Localize(poi.trackedkey.GetTag()));
else if ( poi.type == INT_Exit )
{
if ( poi.trackedline.special == Exit_Secret )
tag = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_SEXIT"));
else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT"));
}
Font fnt = LangFont(mMiniwiFont);
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hs.x*fnt.StringWidth(tag)/2.)/hs.x,(vpos.y-hs.y*fnt.GetHeight()/2.)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
Screen.DrawText(fnt,Font.CR_WHITE,(vpos.x-hs.x*fnt.StringWidth(tag)/2.)/hs.x,(vpos.y+hs.y*fnt.GetHeight()/2.)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
// targetting array
int displayed = 0;
for ( int i=0; i<trackers.Size(); i++ )
{
let targ = trackers[i];
if ( !targ ) continue;
// cap to 40, so the screen isn't too cluttered
if ( displayed++ > 40 ) break;
Vector3 tdir = Level.Vec3Diff(ViewPos,targ.prevpos*(1.-fractic)+targ.pos*fractic);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
tag = targ.mytag;
if ( targ.legged )
{
if ( StringTable.Localize("$SWWM_LEGPREFIX") == "R" ) tag = tag..StringTable.Localize("$SWWM_LEG");
else tag = StringTable.Localize("$SWWM_LEG")..tag;
}
int mtime = 35;
if ( thesight && (targ.lasthealth > 0) ) mtime += 105;
double alph = clamp(((targ.updated+mtime)-level.maptime)/35.,0.,1.);
Vector2 barsiz = TexMan.GetScaledSize(EnemyBTex);
barsiz.x *= hs.x;
barsiz.y *= hs.y;
Vector2 barpos = vpos-(barsiz/2.);
barpos.y -= 16.;
Font fnt = LangFont(mMiniwiFont);
if ( targettag.GetBool() || targ.myplayer && (tag != "") )
Screen.DrawText(fnt,Font.CR_WHITE,(barpos.x+barsiz.x/2.-(fnt.StringWidth(tag)*hs.x)/2.)/hs.x,(barpos.y-fnt.GetHeight()*hs.y)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
Screen.DrawTexture(EnemyBTex,false,barpos.x/hs.x,barpos.y/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
int ht = clamp(targ.intp.GetValue(),0,targ.maxhealth*10);
int hw = int((min(ht,targ.maxhealth)*50.)/targ.maxhealth);
if ( targ.mytarget && (targ.mytarget.bInvulnerable || (targ.myplayer && (targ.myplayer.cheats&(CF_GODMODE|CF_GODMODE2))) || targ.mytarget.FindInventory("InvinciballPower")) )
{
Screen.DrawTexture(EnemyHTex[4],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
continue;
}
Screen.DrawTexture(EnemyHTex[0],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
if ( ht > targ.maxhealth )
{
hw = int((min(ht-targ.maxhealth,targ.maxhealth)*50.)/targ.maxhealth);
Screen.DrawTexture(EnemyHTex[1],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
if ( ht > targ.maxhealth*2 )
{
hw = int((min(ht-targ.maxhealth*2,targ.maxhealth*3)*50.)/(targ.maxhealth*3));
Screen.DrawTexture(EnemyHTex[2],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
if ( ht > targ.maxhealth*5 )
{
hw = int((min(ht-targ.maxhealth*5,targ.maxhealth*5)*50.)/(targ.maxhealth*5));
Screen.DrawTexture(EnemyHTex[3],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
}
if ( !scorebonus ) scorebonus = CVar.GetCVar('swwm_scorebonus',players[consoleplayer]);
// floating kill scores and others
for ( int i=0; i<scoreobjs.Size(); i++ )
{
let snum = scoreobjs[i];
if ( !snum ) continue;
Vector3 tdir = Level.Vec3Diff(ViewPos,snum.pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
if ( snum.str != "" )
{
if ( !scorebonus.GetBool() ) continue;
tag = StringTable.Localize(snum.str);
if ( snum.score == int.max ) tag.AppendFormat(" %s",StringTable.Localize("$SWWM_MAX"));
else if ( snum.score > 0 ) tag.AppendFormat(" x%d",snum.score);
}
else tag = String.Format("%+d",snum.score);
double alph = clamp((snum.lifespan+fractic)/35.,0.,1.);
Vector2 fo = (0,0);
if ( snum.tcolor == Font.CR_RED )
{
// damage falls down
int initspd = (128-snum.seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 64+snum.seed2/2;
fo.x = (.05*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.8);
fo.y = -((snum.initialspan-(snum.lifespan-fractic))**1.5)+boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic));
}
else if ( snum.tcolor == Font.CR_GREEN )
{
// health falls up (?)
int initspd = (128-snum.seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 16+snum.seed2/4;
fo.x = (.15*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.6);
fo.y = ((snum.initialspan-(snum.lifespan-fractic))**1.2)-boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic));
}
else fo.y = snum.initialspan-(snum.lifespan-fractic); // score rises linearly
Font fnt = (snum.str!="")?LangFont(mMiniwiFont):mMiniwiFont.mFont;
fo.y += snum.ofs*fnt.GetHeight();
Screen.DrawText(fnt,snum.tcolor,(vpos.x-hs.x*(fo.x+fnt.StringWidth(tag)/2.))/hs.x,(vpos.y-hs.y*(fo.y+(fnt.GetHeight()/2.)))/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
}
private void DrawScore()
{
Screen.DrawTexture(ScoreTex,false,ss.x-(margin+73),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,ss.x-(margin+58),margin+1,String.Format("%09d",clamp(ScoreInter.GetValue(),0,999999999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// in doom/heretic (draw key icons)
if ( !(gameinfo.gametype&(GAME_DOOMCHEX|GAME_HERETIC)) ) return;
Vector2 keypos = (ss.x-(margin+2),margin+19);
int rowc = 0;
double roww = 0;
for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv )
{
if ( !(i is "Key") || !i.Icon.IsValid() ) continue;
Vector2 siz = TexMan.GetScaledSize(i.Icon);
Screen.DrawTexture(i.Icon,false,keypos.x-siz.x,keypos.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
keypos.y += siz.y+2;
roww = max(roww,siz.x);
if ( ++rowc == 3 )
{
keypos.y = margin+19;
keypos.X -= roww+2;
roww = rowc = 0;
}
}
}
private void DrawInvIcon( Inventory i, double xx, double yy, double alpha = 1., bool forceamt = false, bool aspowerup = false )
{
if ( !i || !i.Icon.IsValid() ) return;
Vector2 scl = TexMan.GetScaledSize(i.Icon);
double mscl = 30./max(scl.x,scl.y);
double dw = (ss.x/mscl), dh = (ss.y/mscl);
double dx = (xx+(30-scl.x*mscl)/2)/mscl, dy = (yy+(30-scl.y*mscl)/2)/mscl;
if ( i is 'Powerup' )
{
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0);
String nstr = String.Format("%ds",Powerup(i).EffectTics/Thinker.TICRATE);
int len = mTewiFont.mFont.StringWidth(nstr);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha);
return;
}
if ( (i is 'SWWMLamp') && aspowerup )
{
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,SWWMLamp(i).isBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0);
String nstr = String.Format("%d%%",SWWMLamp(i).Charge);
int len = mTewiFont.mFont.StringWidth(nstr);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,SWWMLamp(i).isBlinking()?alpha*.5:alpha);
return;
}
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha,DTA_TopOffset,0,DTA_LeftOffset,0);
if ( (i.Amount > 1) || forceamt )
{
String nstr;
if ( (i.Amount > 99999) && !forceamt ) nstr = "99999";
else nstr = String.Format("%d",i.Amount);
int len = mTewiFont.mFont.StringWidth(nstr);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha);
}
}
private void DrawInventory()
{
// active items (armor / powerups)
double xx = margin+2;
double yy = ss.y-(margin+60);
if ( CPlayer.mo.InvSel && !isInventoryBarVisible() ) yy -= 34;
bool drewarmor = false;
for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv )
{
if ( (i.Amount <= 0) || (!(i is 'SWWMArmor') && !(i is 'BasicArmor')) ) continue;
DrawInvIcon(i,xx,yy,forceamt:true);
yy -= 34;
drewarmor = true;
}
yy = ss.y-(margin+60);
if ( drewarmor ) xx += 40;
else if ( CPlayer.mo.InvSel && !isInventoryBarVisible() ) yy -= 34;
for ( Inventory i=CPlayer.mo.Inv; i; i=i.Inv )
{
if ( (i is 'SWWMLamp') )
{
DrawInvIcon(i,xx,yy,aspowerup:true);
yy -= 34;
continue;
}
if ( !(i is 'Powerup') || (Powerup(i).EffectTics <= 0) || !(Powerup(i).Icon) ) continue;
DrawInvIcon(i,xx,yy);
yy -= 34;
}
// inventory box / bar
if ( !CPlayer.mo.InvSel ) return;
if ( isInventoryBarVisible() )
{
Array<Inventory> bar;
bar.Clear();
for ( Inventory i=CPlayer.mo.FirstInv(); i; i=i.NextInv() ) bar.Push(i);
int ps = bar.Find(CPlayer.mo.InvSel);
Inventory prev[2], next[2];
if ( bar.Size() > 1 )
{
if ( ps+1 >= bar.Size() ) next[0] = bar[0];
else next[0] = bar[ps+1];
if ( ps-1 < 0 ) prev[0] = bar[bar.Size()-1];
else prev[0] = bar[ps-1];
}
if ( bar.Size() > 2 )
{
if ( ps+2 >= bar.Size() ) next[1] = bar[(ps+2)-bar.Size()];
else next[1] = bar[ps+2];
if ( ps-2 < 0 ) prev[1] = bar[bar.Size()+(ps-2)];
else prev[1] = bar[ps-2];
}
xx = (ss.x-34)/2;
yy = (ss.y+64)/2;
Screen.DrawTexture(InventoryTex,false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
DrawInvIcon(CPlayer.mo.InvSel,xx+2,yy+2);
DrawInvIcon(prev[0],xx-32,yy+2,2./3.);
DrawInvIcon(prev[1],xx-66,yy+2,1./3.);
DrawInvIcon(next[0],xx+36,yy+2,2./3.);
DrawInvIcon(next[1],xx+70,yy+2,1./3.);
return;
}
Screen.DrawTexture(InventoryTex,false,margin,ss.y-(margin+61),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
DrawInvIcon(CPlayer.mo.InvSel,margin+2,ss.y-(margin+59));
}
private void DrawWeapon()
{
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' ) SWWMWeapon(CPlayer.ReadyWeapon).DrawWeapon(FracTic,ss.x-margin,ss.y-(margin+28),hs,ss);
else
{
// TODO generic display
}
Screen.DrawTexture(WeaponTex,false,ss.x-(margin+61),ss.y-(margin+29),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
double xx = ss.x-(margin+58), yy = ss.y-(margin+29);
for ( int i=1; i<=10; i++ )
{
int ncolor = Font.CR_WHITE;
if ( !CPlayer.HasWeaponsInSlot(i%10) ) ncolor = Font.CR_DARKGRAY;
else if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) && (CPlayer.PendingWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
else if ( (!CPlayer.PendingWeapon || (CPlayer.PendingWeapon == WP_NOCHANGE)) && CPlayer.ReadyWeapon && (CPlayer.ReadyWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
else
{
bool hasammo = false;
for ( Inventory inv=CPlayer.mo.Inv; inv; inv=inv.Inv )
{
bool dummy;
int slot;
if ( inv is 'Weapon' ) [dummy, slot] = CPlayer.weapons.LocateWeapon(Weapon(inv).GetClass());
if ( slot != (i%10) ) continue;
// CheckAmmo can't be called from ui, so we have to improvise
// for SWWM weapons I made a function for this at least
if ( (inv is 'SWWMWeapon') && SWWMWeapon(inv).ReportHUDAmmo() )
hasammo = true;
else if ( !(inv is 'SWWMWeapon') && ((!Weapon(inv).Ammo1 || (Weapon(inv).Ammo1.Amount > 0)) || (Weapon(inv).Ammo2 && (Weapon(inv).Ammo2.Amount > 0))) )
hasammo = true;
}
if ( !hasammo ) ncolor = Font.CR_RED;
}
Screen.DrawText(mTewiFont.mFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
xx += 12;
if ( i == 5 )
{
xx = ss.x-(margin+58);
yy += 14;
}
}
}
private void DrawStatus()
{
Screen.DrawTexture(StatusTex,false,margin,ss.y-(margin+27),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
let d = Demolitionist(CPlayer.mo);
int dw = DashInter.GetValue();
double alph = .6;
if ( !d || (d.dashfuel > 20) || ((gametic%10) < 5) ) alph = 1.;
Screen.DrawTexture(DashTex,false,margin+2,ss.y-(margin+21),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,dw,DTA_Alpha,alph);
int fw = FuelInter.GetValue();
Screen.DrawTexture(FuelTex,false,margin+2,ss.y-(margin+25),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,fw);
int ht = clamp(HealthInter.GetValue(),0,10000);
int hw = min(ht,100);
if ( isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower") )
{
Screen.DrawTexture(HealthTex[4],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,margin+108,ss.y-(margin+16),String.Format("%3d",Random[HudStuff](0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return;
}
Screen.DrawTexture(HealthTex[0],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
if ( ht > 100 )
{
hw = min(ht-100,100);
Screen.DrawTexture(HealthTex[1],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
}
if ( ht > 200 )
{
hw = int(min(ht-200,300)/3.);
Screen.DrawTexture(HealthTex[2],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
}
if ( ht > 500 )
{
hw = int(min(ht-500,500)/5.);
Screen.DrawTexture(HealthTex[3],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
}
int hcolor = Font.CR_RED;
if ( ht > 500 ) hcolor = Font.CR_GOLD;
else if ( ht > 200 ) hcolor = Font.CR_PURPLE;
else if ( ht > 100 ) hcolor = Font.CR_CYAN;
Screen.DrawText(mTewiFont.mFont,hcolor,margin+108,ss.y-(margin+16),String.Format("%3d",clamp(ht,0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
private void DrawMessages()
{
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]);
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;
bool smol = (ss.x<640);
Screen.DrawTexture(ChatTex[smol?3: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);
int curtime = MainQueue[i].tic-level.maptime;
if ( MainQueue[i].type < PRINT_CHAT ) curtime += 35*msgduration.GetInt();
else curtime += 35*chatduration.GetInt();
double alph = clamp(curtime/20.,0.,1.);
Font fnt = LangFont(mTewiFont);
BrokenLines l = fnt.BreakLines(cstr,smol?211:361);
for ( int j=0; j<l.Count(); j++ )
{
Screen.DrawTexture(ChatTex[smol?4:1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(fnt,col,xx+4,yy,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
yy += 13;
}
}
Screen.DrawTexture(ChatTex[smol?5: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+50);
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);
int curtime = (PickupQueue[i].tic+35*pickduration.GetInt())-level.maptime;
double alph = clamp(curtime/20.,0.,1.);
Font fnt = LangFont(mTewiFont);
BrokenLines l = fnt.BreakLines(cstr,int(ss.x*.75));
int maxlen = 0;
for ( int j=0; j<l.Count(); j++ )
{
int len = fnt.StringWidth(l.StringAt(j));
if ( len > maxlen ) maxlen = len;
}
int h = fnt.GetHeight();
double xx = (ss.x-maxlen)/2.;
Screen.Dim("Black",.8*alph,int((xx-6)*hs.x),int((yy-h*(l.Count()-1))*hs.y),int((maxlen+12)*hs.x),int((h*l.Count()+4)*hs.y));
for ( int j=l.Count()-1; j>=0; j-- )
{
int len = fnt.StringWidth(l.StringAt(j));
xx = (ss.x-len)/2.;
Screen.DrawText(fnt,pickcol.GetInt(),xx,yy+2,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
yy -= h;
}
yy -= 6;
}
}
}
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
SWWMUtility.StripColor(pname);
String fullstr = String.Format("\cq%s\cd@\cqdemolitionist%d\cn ~ \c-wall %s_",pname,consoleplayer+1,txt);
Font fnt = LangFont(mTewiFont);
// cut out to fit
int w = fnt.StringWidth(fullstr);
if ( w > ss.x-4 )
{
// draw trailing dots
Screen.DrawText(fnt,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(fnt,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(fnt,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
return true;
}
override void DrawPowerups()
{
// don't do anything
}
private void DrawDeath()
{
// death prompt
let demo = Demolitionist(CPlayer.mo);
if ( !demo || (CPlayer.Health > 0) ) return;
String str;
double alph;
int len;
double xx, yy;
Font fnt;
if ( demo.player.viewheight <= 6 )
{
Screen.Dim("Black",min(demo.deadtimer/80.,1.),0,0,Screen.GetWidth(),Screen.GetHeight());
if ( demo.revivefail > level.maptime )
{
Screen.Dim("Red",clamp((demo.revivefail-level.maptime)/60.,0.,.2),0,0,Screen.GetWidth(),Screen.GetHeight());
str = StringTable.Localize("$SWWM_REFAIL");
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = ss.y-48;
if ( (gametic%16) < 8 )
Screen.DrawText(fnt,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
alph = clamp((demo.deadtimer-60)/60.,0.,1.);
str = String.Format(StringTable.Localize("$SWWM_URDED"),CPlayer.GetUserName());
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = (ss.y-fnt.GetHeight()*4)/2.;
Screen.DrawText(fnt,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
alph = clamp((demo.deadtimer-140)/60.,0.,1.);
str = String.Format(StringTable.Localize("$SWWM_URDED2"),CPlayer.GetUserName());
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = ss.y/2.;
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
if ( !swwm_revive )
return;
alph = clamp((demo.deadtimer-160)/60.,0.,1.);
str = String.Format(StringTable.Localize("$SWWM_URDED3"),CPlayer.GetUserName());
fnt = LangFont(mTewiFont);
len = fnt.StringWidth(str);
xx = (ss.x-len)/2.;
yy = (ss.y+fnt.GetHeight()*2)/2.;
Screen.DrawText(fnt,Font.CR_WHITE,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
}
override void Draw( int state, double TicFrac )
{
Super.Draw(state,TicFrac);
if ( (state != HUD_StatusBar) && (state != HUD_Fullscreen) ) return;
if ( !safezone ) safezone = CVar.GetCVar('swwm_hudmargin',players[consoleplayer]);
if ( !maxchat[0] ) maxchat[0] = CVar.GetCVar('swwm_maxshown',players[consoleplayer]);
if ( !maxchat[1] ) maxchat[1] = CVar.GetCVar('swwm_maxshownbig',players[consoleplayer]);
if ( !maxpick ) maxpick = CVar.GetCVar('swwm_maxpickup',players[consoleplayer]);
BeginHUD();
hs = GetHUDScale();
ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y);
margin = clamp(safezone.GetInt(),0,(ss.x<640)?10:40);
FracTic = TicFrac;
DrawTarget();
DrawScore();
DrawInventory();
DrawStatus();
DrawWeapon();
DrawMessages();
DrawDeath();
}
}