fteqw/plugins/hud/ui_sbar.c

2349 lines
49 KiB
C
Raw Normal View History

#include "../plugin.h"
#ifdef _MSC_VER
#pragma warning(4: 4244)
#pragma warning(4: 4305)
#endif
#define DEFAULTHUDNAME "ftehud.hud"
#define MAX_ELEMENTS 128
int K_UPARROW;
int K_DOWNARROW;
int K_LEFTARROW;
int K_RIGHTARROW;
int K_ESCAPE;
int K_MOUSE1;
int K_MOUSE2;
int K_HOME;
int K_SHIFT;
int K_MWHEELDOWN;
int K_MWHEELUP;
int K_PAGEUP;
int K_PAGEDOWN;
#define MAX_CL_STATS 32
#define STAT_HEALTH 0
#define STAT_WEAPON 2
#define STAT_AMMO 3
#define STAT_ARMOR 4
#define STAT_WEAPONFRAME 5
#define STAT_SHELLS 6
#define STAT_NAILS 7
#define STAT_ROCKETS 8
#define STAT_CELLS 9
#define STAT_ACTIVEWEAPON 10
#define STAT_TOTALSECRETS 11
#define STAT_TOTALMONSTERS 12
#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
#define STAT_MONSTERS 14 // bumped by svc_killedmonster
#define STAT_ITEMS 15
// context menus
#define CONTEXT_NONE 0
#define CONTEXT_MAIN 1
#define CONTEXT_NEW_ITEM 2
#define CONTEXT_NEW_ITEM_SUB 3
//some engines can use more.
//any mod specific ones should be 31 and downwards rather than upwards.
#define IT_GUN1 (1<<0)
#define IT_GUN2 (1<<1) //the code assumes these are linear.
#define IT_GUN3 (1<<2) //be careful with strange mods.
#define IT_GUN4 (1<<3)
#define IT_GUN5 (1<<4)
#define IT_GUN6 (1<<5)
#define IT_GUN7 (1<<6)
#define IT_GUN8 (1<<7) //quake doesn't normally use this.
#define IT_AMMO1 (1<<8)
#define IT_AMMO2 (1<<9)
#define IT_AMMO3 (1<<10)
#define IT_AMMO4 (1<<11)
#define IT_GUN0 (1<<12)
#define IT_ARMOR1 (1<<13)
#define IT_ARMOR2 (1<<14)
#define IT_ARMOR3 (1<<15)
#define IT_SUPERHEALTH (1<<16)
#define IT_PUP1 (1<<17)
#define IT_PUP2 (1<<18)
#define IT_PUP3 (1<<19)
#define IT_PUP4 (1<<20)
#define IT_PUP5 (1<<21)
#define IT_PUP6 (1<<22)
#define IT_RUNE1 (1<<23)
#define IT_RUNE2 (1<<24)
#define IT_RUNE3 (1<<25)
#define IT_RUNE4 (1<<26)
//these are linear and treated the same
#define numpups 6
//the names of the cvars, as they will appear on the console
#define UI_NOSBAR "ui_defaultsbar"
#define UI_NOIBAR "ui_noibar"
#define UI_NOFLASH "ui_nosbarflash"
static char *weaponabbreviation[] = { //the postfix for the weapon anims
"shotgun", // shotgun
"sshotgun", // super shotgun
"nailgun", // nailgun
"snailgun", // super nailgun
"rlaunch", // grenade launcher
"srlaunch", // rocket launcher
"lightng" // thunderbolt
};
#define numweaps (sizeof(weaponabbreviation) / sizeof(char *))
static char *pupabbr[] = { //the postfix for the powerup anims
"key1",
"key2",
"invis",
"invul",
"suit",
"quad"
};
static char *pupabbr2[] = { //the postfix for the powerup anims
"key1",
"key2",
"invis",
"invuln",
"suit",
"quad"
};
//0 = owned, 1 selected, 2-7 flashing
static qhandle_t pic_cursor;
static qhandle_t con_chars;
static qhandle_t pic_weapon[8][numweaps];
static qhandle_t sbarback, ibarback;
//0 = owned, 1-6 flashing
static qhandle_t pic_pup[7][numpups];
static qhandle_t pic_armour[3];
static qhandle_t pic_ammo[4];
static qhandle_t pic_rune[4];
static qhandle_t pic_num[13];
static qhandle_t pic_anum[11];
//faces
static qhandle_t pic_face[5];
static qhandle_t pic_facep[5];
static qhandle_t pic_facequad;
static qhandle_t pic_faceinvis;
static qhandle_t pic_faceinvisinvuln;
static qhandle_t pic_faceinvuln;
//static qhandle_t pic_faceinvulnquad;
static int currenttime;
static int gotweapontime[numweaps];
static int gotpuptime[numpups];
float sbarminx;
float sbarminy;
float sbarscalex;
float sbarscaley;
float sbaralpha;
int sbartype;
int sbarindex;
static int hudedit;
static int typetoinsert;
enum {
DZ_BOTTOMLEFT,
DZ_BOTTOMRIGHT
};
typedef void drawelementfnc_t(void);
typedef struct {
float defaultx; //used if couldn't load a config
float defaulty;
int defaultzone;
float defaultalpha;
drawelementfnc_t *DrawElement;
int subtype;
} huddefaultelement_t;
drawelementfnc_t Hud_SBar;
drawelementfnc_t Hud_StatSmall;
drawelementfnc_t Hud_StatBig;
drawelementfnc_t Hud_ArmourPic;
drawelementfnc_t Hud_HealthPic;
drawelementfnc_t Hud_CurrentAmmoPic;
drawelementfnc_t Hud_IBar;
drawelementfnc_t Hud_Weapon;
drawelementfnc_t Hud_W_Lightning;
drawelementfnc_t Hud_Powerup;
drawelementfnc_t Hud_Rune;
drawelementfnc_t Hud_Ammo;
drawelementfnc_t Hud_ScoreCard;
drawelementfnc_t Hud_ScoreName;
drawelementfnc_t Hud_Blackness;
drawelementfnc_t Hud_TeamScore;
drawelementfnc_t Hud_TeamName;
drawelementfnc_t Hud_Tracking;
drawelementfnc_t Hud_TeamOverlay;
// TODO: more elements
// - generalized graphic elements
// - cvar controlled small and big numbers
// - alias controlled graphic elements (both +/-showscores like and alias calling?)
// - Q2-style current weapon icon
int statsremap[] =
{
STAT_HEALTH,
STAT_ARMOR,
STAT_AMMO,
STAT_SHELLS,
STAT_NAILS,
STAT_ROCKETS,
STAT_CELLS
};
struct subtypenames {
char *name;
};
typedef struct {
drawelementfnc_t *draw;
char *name;
int width, height;
int maxsubtype;
struct subtypenames subtypename[20];
} drawelement_t;
drawelement_t drawelement[] =
{
{Hud_SBar, "Status bar", 320, 24, 0},
{Hud_StatSmall, "Stat (small)", 8*3, 8, 6, {"Health", "Armour", "Ammo", "Shells", "Nails", "Rockets", "Cells"}}, // equal to sizeof(statsremap)/sizeof(statsremap[0])-1
{Hud_StatBig, "Stat (big)", 24*3, 24, 6, {"Health", "Armour", "Ammo", "Shells", "Nails", "Rockets", "Cells"}}, // equal to sizeof(statsremap)/sizeof(statsremap[0])-1
{Hud_ArmourPic, "Armor pic", 24, 24, 0},
{Hud_HealthPic, "Health pic", 24, 24, 0},
{Hud_CurrentAmmoPic, "Ammo pic", 24, 24, 0},
{Hud_IBar, "Info bar", 320, 24, 0},
{Hud_Weapon, "Weapon pic", 24, 16, 6, {"Shotgun", "Super Shotgun", "Nailgun", "Super Nailgun", "Grenade Launcher", "Rocket Launcher", "Thunderbolt"}},
{Hud_W_Lightning, "Shaft pic", 24, 16, 0},
{Hud_Powerup, "Powerup pic", 16, 16, 5, {"Key 1", "Key 2", "Ring of Invis", "Pentagram", "Biosuit", "Quad"}},
{Hud_Rune, "Rune pic", 8, 16, 3, {"Rune 1", "Rune 2", "Rune 3", "Rune 4"}},
{Hud_Ammo, "Ammo display", 42, 11, 3, {"Shells", "Spikes", "Rockets", "Cells"}},
{Hud_Blackness, "Blackness", 16, 16, 9, {"10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"}},
{Hud_ScoreCard, "Scorecard", 32, 8, 15, {"Player 0", "Player 1", "Player 2", "Player 3", "Player 4", "Player 5", "Player 6", "Player 7", "Player 8", "Player 9", "Player 10", "Player 11", "Player 12", "Player 13", "Player 14", "Player 15"}},
{Hud_ScoreName, "Scorename", 128, 8, 7, {"Player 0", "Player 1", "Player 2", "Player 3", "Player 4", "Player 5", "Player 6", "Player 7"}},
{Hud_TeamScore, "TeamScore", 32, 8, 7, {"Team 0", "Team 1", "Team 2", "Team 3", "Team 4", "Team 5", "Team 6", "Team 7"}},
{Hud_TeamName, "TeamName", 128, 8, 7, {"Team 0", "Team 1", "Team 2", "Team 3", "Team 4", "Team 5", "Team 6", "Team 7"}},
{Hud_Tracking, "Tracking", 128, 8, 0},
{Hud_TeamOverlay, "Team overlay", 256, 64, 0}
};
huddefaultelement_t hedefaulttype[] = {
{
0, -24, DZ_BOTTOMLEFT,
0.3f,
Hud_SBar
},
{
0, -24, DZ_BOTTOMLEFT,
1,
Hud_ArmourPic
},
{
24, -24, DZ_BOTTOMLEFT,
1,
Hud_StatBig,
1
},
{
112, -24, DZ_BOTTOMLEFT,
1,
Hud_HealthPic
},
{
24*6, -24, DZ_BOTTOMLEFT,
1,
Hud_StatBig,
0
},
{
224, -24, DZ_BOTTOMLEFT,
1,
Hud_CurrentAmmoPic
},
{
248, -24, DZ_BOTTOMLEFT,
1,
Hud_StatBig,
2
},
{
0, -48, DZ_BOTTOMLEFT,
0.3f,
Hud_IBar
},
{
0, -40, DZ_BOTTOMLEFT,
1,
Hud_Weapon,
0
},
{
24, -40, DZ_BOTTOMLEFT,
1,
Hud_Weapon,
1
},
{
48, -40, DZ_BOTTOMLEFT,
1,
Hud_Weapon,
2
},
{
72, -40, DZ_BOTTOMLEFT,
1,
Hud_Weapon,
3
},
{
96, -40, DZ_BOTTOMLEFT,
1,
Hud_Weapon,
4
},
{
120, -40, DZ_BOTTOMLEFT,
1,
Hud_Weapon,
5
},
{
146, -40, DZ_BOTTOMLEFT,
1,
Hud_W_Lightning
},
{
194, -40, DZ_BOTTOMLEFT,
0.3f,
Hud_Powerup,
0
},
{
208, -40, DZ_BOTTOMLEFT,
0.3f,
Hud_Powerup,
1
},
{
224, -40, DZ_BOTTOMLEFT,
1,
Hud_Powerup,
2
},
{
240, -40, DZ_BOTTOMLEFT,
1,
Hud_Powerup,
3
},
{
256, -40, DZ_BOTTOMLEFT,
1,
Hud_Powerup,
4
},
{
272, -40, DZ_BOTTOMLEFT,
1,
Hud_Powerup,
5
},
{
288, -40, DZ_BOTTOMLEFT,
0.3f,
Hud_Rune,
0
},
{
296, -40, DZ_BOTTOMLEFT,
0.3f,
Hud_Rune,
1
},
{
304, -40, DZ_BOTTOMLEFT,
0.3f,
Hud_Rune,
2
},
{
312, -40, DZ_BOTTOMLEFT,
0.3f,
Hud_Rune,
3
},
{
48*0+3, -48, DZ_BOTTOMLEFT,
1,
Hud_Ammo,
0
},
{
48*1+3, -48, DZ_BOTTOMLEFT,
1,
Hud_Ammo,
1
},
{
48*2+3, -48, DZ_BOTTOMLEFT,
1,
Hud_Ammo,
2
},
{
48*3+3, -48, DZ_BOTTOMLEFT,
1,
Hud_Ammo,
3
},
{
42*3, -48, DZ_BOTTOMLEFT,
1,
Hud_ScoreCard
}
};
typedef struct {
int type;
int subtype;
float x, y;
float scalex;
float scaley;
float alpha;
} hudelement_t;
hudelement_t element[MAX_ELEMENTS]; //look - Spike used a constant - that's a turn up for the books!
int numelements;
int currentitem;
int hoveritem;
qboolean mousedown, shiftdown;
float mouseofsx, mouseofsy;
qboolean context;
vec3_t player_location[32];
int player_armor[32];
int player_health[32];
unsigned int player_items[32];
char *player_nick[32] =
{
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", ""
};
unsigned int player_nicklength;
void Hud_TeamOverlayUpdate(void);
/*
==================
COM_DefaultExtension
==================
*/
void COM_DefaultExtension (char *path, char *extension, int maxlen)
{
char *src;
//
// if path doesn't have a .EXT, append extension
// (extension should include the .)
//
src = path + strlen(path) - 1;
while (*src != '/' && src != path)
{
if (*src == '.')
return; // it has an extension
src--;
}
strlcpy (path+strlen(path), extension, maxlen);
}
void UI_DrawPic(qhandle_t pic, int x, int y, int width, int height)
{
Draw_Image((float)x*sbarscalex+sbarminx, (float)y*sbarscaley+sbarminy, (float)width*sbarscalex, (float)height*sbarscaley, 0, 0, 1, 1, pic);
}
void UI_DrawChar(unsigned int c, int x, int y)
{
static float size = 1.0f/16.0f;
float s1 = size * (c&15);
float t1 = size * ((c>>4)&15);
Draw_Image((float)x*sbarscalex+sbarminx, (float)y*sbarscaley+sbarminy, 8*sbarscalex, 8*sbarscaley, s1, t1, s1+size, t1+size, con_chars);
}
void UI_DrawString(char *s, int x, int y)
{
while(*s)
{
UI_DrawChar((unsigned int)*s++, x, y);
x+=8;
}
}
void UI_DrawAltString(char *s, int x, int y, qboolean shouldmask)
{
int mask = shouldmask?128:0;
while(*s)
{
UI_DrawChar((unsigned int)*s++ | mask, x, y);
x+=8;
}
}
void UI_DrawBigNumber(int num, int x, int y, qboolean red)
{
char *s;
int len;
s = va("%i", num);
len = strlen(s);
if (len < 3)
x += 24*(3-len);
else
s += len-3;
if (red)
{
while(*s)
{
if (*s == '-')
UI_DrawPic (pic_anum[10], x, y, 24, 24);
else
UI_DrawPic (pic_anum[*s-'0'], x, y, 24, 24);
s++;
x+=24;
}
}
else
{
while(*s)
{
if (*s == '-')
UI_DrawPic (pic_num[10], x, y, 24, 24);
else
UI_DrawPic (pic_num[*s-'0'], x, y, 24, 24);
s++;
x+=24;
}
}
}
void SBar_FlushAll(void)
{
numelements = 0;
}
static int idxforfunc(drawelementfnc_t *fnc)
{
int i;
for (i = 0; i < sizeof(drawelement)/sizeof(drawelement[0]); i++)
{
if (drawelement[i].draw == fnc)
return i;
}
return -10000; //try and crash
}
void SBar_ReloadDefaults(void)
{
int i;
for (i = 0; i < sizeof(hedefaulttype)/sizeof(hedefaulttype[0]); i++)
{
if (hedefaulttype[i].defaultalpha)
{
if (numelements >= MAX_ELEMENTS)
break;
element[numelements].type = idxforfunc(hedefaulttype[i].DrawElement);
element[numelements].alpha = hedefaulttype[i].defaultalpha;
element[numelements].scalex = 1;
element[numelements].scaley = 1;
element[numelements].subtype = hedefaulttype[i].subtype;
switch(hedefaulttype[i].defaultzone)
{
case DZ_BOTTOMLEFT:
element[numelements].x = hedefaulttype[i].defaultx;
element[numelements].y = 480+hedefaulttype[i].defaulty;
break;
case DZ_BOTTOMRIGHT:
element[numelements].x = 640+hedefaulttype[i].defaultx;
element[numelements].y = 480+hedefaulttype[i].defaulty;
break;
}
numelements++;
}
}
}
void UI_SbarInit(void)
{
int i;
int j;
//main bar (add cvars later)
ibarback = Draw_LoadImage("ibar", true);
sbarback = Draw_LoadImage("sbar", true);
con_chars = Draw_LoadImage("conchars", true);
//load images.
for (i = 0; i < 10; i++)
{
pic_num[i] = Draw_LoadImage(va("num_%i", i), true);
pic_anum[i] = Draw_LoadImage(va("anum_%i", i), true);
}
pic_num[10] = Draw_LoadImage("num_minus", true);
pic_anum[10] = Draw_LoadImage("anum_minus", true);
pic_num[11] = Draw_LoadImage("num_colon", true);
pic_num[12] = Draw_LoadImage("num_slash", true);
for (i = 0; i < numweaps; i++)
{
gotweapontime[i] = 0;
pic_weapon[0][i] = Draw_LoadImage(va("inv_%s", weaponabbreviation[i]), true);
pic_weapon[1][i] = Draw_LoadImage(va("inv2_%s", weaponabbreviation[i]), true);
for (j = 0; j < 5; j++)
{
pic_weapon[2+j][i] = Draw_LoadImage(va("inva%i_%s", j+1, weaponabbreviation[i]), true);
}
}
for (i = 0; i < numpups; i++)
{
gotpuptime[i] = 0;
pic_pup[0][i] = Draw_LoadImage(va("sb_%s", pupabbr2[i]), true);
for (j = 0; j < 5; j++)
{
pic_pup[1+j][i] = Draw_LoadImage(va("sba%i_%s", j+1, pupabbr[i]), true);
}
}
pic_cursor = Draw_LoadImage("gfx/cursor", false);
pic_armour[0] = Draw_LoadImage("sb_armor1", true);
pic_armour[1] = Draw_LoadImage("sb_armor2", true);
pic_armour[2] = Draw_LoadImage("sb_armor3", true);
pic_ammo[0] = Draw_LoadImage("sb_shells", true);
pic_ammo[1] = Draw_LoadImage("sb_nails", true);
pic_ammo[2] = Draw_LoadImage("sb_rocket", true);
pic_ammo[3] = Draw_LoadImage("sb_cells", true);
pic_rune[0] = Draw_LoadImage("sb_sigil1", true);
pic_rune[1] = Draw_LoadImage("sb_sigil2", true);
pic_rune[2] = Draw_LoadImage("sb_sigil3", true);
pic_rune[3] = Draw_LoadImage("sb_sigil4", true);
pic_face[0] = Draw_LoadImage("face1", true);
pic_face[1] = Draw_LoadImage("face2", true);
pic_face[2] = Draw_LoadImage("face3", true);
pic_face[3] = Draw_LoadImage("face4", true);
pic_face[4] = Draw_LoadImage("face5", true);
pic_facep[0] = Draw_LoadImage("face_p1", true);
pic_facep[1] = Draw_LoadImage("face_p2", true);
pic_facep[2] = Draw_LoadImage("face_p3", true);
pic_facep[3] = Draw_LoadImage("face_p4", true);
pic_facep[4] = Draw_LoadImage("face_p5", true);
pic_facequad = Draw_LoadImage("face_quad", true);
pic_faceinvis = Draw_LoadImage("face_invis", true);
pic_faceinvisinvuln = Draw_LoadImage("face_inv2", true);
pic_faceinvuln = Draw_LoadImage("face_invul2", true);
// pic_faceinvulnquad = Draw_LoadImage("face_invul1", true);
SBar_FlushAll();
SBar_ReloadDefaults();
}
unsigned int stats[MAX_CL_STATS];
void Hud_SBar(void)
{
UI_DrawPic(sbarback, 0, 0, 320, 24);
}
void Hud_ArmourPic(void)
{
if (stats[STAT_ITEMS] & IT_ARMOR3)
UI_DrawPic(pic_armour[2], 0, 0, 24, 24);
else if (stats[STAT_ITEMS] & IT_ARMOR2)
UI_DrawPic(pic_armour[1], 0, 0, 24, 24);
else if (stats[STAT_ITEMS] & IT_ARMOR1 || hudedit)
UI_DrawPic(pic_armour[0], 0, 0, 24, 24);
}
void Hud_HealthPic(void)
{
int hl;
if (stats[STAT_ITEMS] & IT_PUP3)
{ //invisability
if (stats[STAT_ITEMS] & IT_PUP4)
UI_DrawPic(pic_faceinvisinvuln, 0, 0, 24, 24);
else
UI_DrawPic(pic_faceinvis, 0, 0, 24, 24);
return;
}
if (stats[STAT_ITEMS] & IT_PUP4)
{ //invuln
// if (stats[STAT_ITEMS] & IT_PUP6)
// UI_DrawPic(pic_faceinvulnquad, 0, 0, 24, 24);
// else
UI_DrawPic(pic_faceinvuln, 0, 0, 24, 24);
return;
}
if (stats[STAT_ITEMS] & IT_PUP6)
{
UI_DrawPic(pic_facequad, 0, 0, 24, 24);
return;
}
hl = stats[STAT_HEALTH]/20;
if (hl > 4)
hl = 4;
if (hl < 0)
hl = 0;
//FIXME
// if (innpain)
// UI_DrawPic(pic_facep[4-hl], 0, 0, 24, 24);
// else
UI_DrawPic(pic_face[4-hl], 0, 0, 24, 24);
}
void Hud_StatBig(void)
{
int i = stats[statsremap[sbartype]];
UI_DrawBigNumber(i, 0, 0, i < 25);
}
void Hud_StatSmall(void)
{
int i = stats[statsremap[sbartype]];
// TODO: need some sort of options thing to change between brown/white/gold text
UI_DrawChar(i%10+18, 19, 0);
i/=10;
if (i)
UI_DrawChar(i%10+18, 11, 0);
i/=10;
if (i)
UI_DrawChar(i%10+18, 3, 0);
}
void Hud_CurrentAmmoPic(void)
{
if ((stats[STAT_ITEMS] & IT_AMMO1))
UI_DrawPic(pic_ammo[0], 0, 0, 24, 24);
else if (stats[STAT_ITEMS] & IT_AMMO2)
UI_DrawPic(pic_ammo[1], 0, 0, 24, 24);
else if (stats[STAT_ITEMS] & IT_AMMO3)
UI_DrawPic(pic_ammo[2], 0, 0, 24, 24);
else if (stats[STAT_ITEMS] & IT_AMMO4 || hudedit)
UI_DrawPic(pic_ammo[3], 0, 0, 24, 24);
}
void Hud_IBar(void)
{
UI_DrawPic(ibarback, 0, 0, 320, 24);
}
void Hud_Weapon(void)
{
int flash;
if (!(stats[STAT_ITEMS] & (IT_GUN1 << sbartype)) && !hudedit)
{
gotweapontime[sbartype] = 0;
return;
}
if (!gotweapontime[sbartype])
gotweapontime[sbartype] = currenttime;
flash = (currenttime - gotweapontime[sbartype])/100;
if (flash < 0) //errr... whoops...
flash = 0;
if (flash > 10)
{
if (stats[STAT_ACTIVEWEAPON] & (IT_GUN1 << sbartype))
flash = 1; //selected.
else
flash = 0;
}
else
flash = (flash%5) + 2;
UI_DrawPic(pic_weapon[flash][sbartype], 0, 0, 24, 16);
}
void Hud_W_HalfLightning(void) //left half only (needed due to LG icon being twice as wide)
{
int flash;
int wnum = 6;
if (!(stats[STAT_ITEMS] & (IT_GUN1 << wnum)) && !hudedit)
{
gotweapontime[wnum] = 0;
return;
}
if (!gotweapontime[wnum])
gotweapontime[wnum] = currenttime;
flash = (currenttime - gotweapontime[wnum])/100;
if (flash < 0) //errr... whoops...
flash = 0;
if (flash > 10)
{
if (stats[STAT_ACTIVEWEAPON] & (IT_GUN1 << wnum))
flash = 1; //selected.
else
flash = 0;
}
else
flash = (flash%5) + 2;
Draw_Image(sbarminx, sbarminy, (float)24*sbarscalex, (float)16*sbarscaley, 0, 0, 0.5, 1, pic_weapon[flash][wnum]);
}
void Hud_W_Lightning(void)
{
int flash;
int wnum = 6;
if (!(stats[STAT_ITEMS] & (IT_GUN1 << wnum)) && !hudedit)
{
gotweapontime[wnum] = 0;
return;
}
if (!gotweapontime[wnum])
gotweapontime[wnum] = currenttime;
flash = (currenttime - gotweapontime[wnum])/100;
if (flash < 0) //errr... whoops...
flash = 0;
if (flash > 10)
{
if (stats[STAT_ACTIVEWEAPON] & (IT_GUN1 << wnum))
flash = 1; //selected.
else
flash = 0;
}
else
flash = (flash%5) + 2;
UI_DrawPic(pic_weapon[flash][wnum], 0, 0, 48, 16);
}
void Hud_Powerup(void)
{
int flash;
if (!(stats[STAT_ITEMS] & (IT_PUP1 << sbartype)) && !hudedit)
return;
if (!gotpuptime[sbartype])
gotpuptime[sbartype] = currenttime;
flash = (currenttime - gotpuptime[sbartype])/100;
if (flash < 0) //errr... whoops...
flash = 0;
if (flash > 10)
{
flash = 0;
}
else
flash = (flash%5) + 2;
UI_DrawPic(pic_pup[flash][sbartype], 0, 0, 16, 16);
}
void Hud_Rune(void)
{
if (!(stats[STAT_ITEMS] & (IT_RUNE1 << sbartype)) && !hudedit)
return;
UI_DrawPic(pic_rune[sbartype], 0, 0, 8, 16);
}
void Hud_Ammo(void)
{
int num;
Draw_Image(sbarminx, sbarminy, (float)42*sbarscalex, (float)11*sbarscaley, (3+(sbartype*48))/320.0f, 0, (3+(sbartype*48)+42)/320.0f, 11/24.0f, ibarback);
num = stats[STAT_SHELLS+sbartype];
if (hudedit)
num = 999;
UI_DrawChar(num%10+18, 19, 0);
num/=10;
if (num)
UI_DrawChar(num%10+18, 11, 0);
num/=10;
if (num)
UI_DrawChar(num%10+18, 3, 0);
}
float pc[16][3] =
{
/*
{235, 235, 235},
{143, 111, 035},
{139, 139, 203},
{107, 107, 015},
{127, 000, 000},
{175, 103, 035},
{255, 243, 027},
{227, 179, 151},
{171, 139, 163},
{187, 115, 159},
{219, 195, 187},
{111, 131, 123},
{255, 243, 027},
{000, 000, 255},
{247, 211, 139}
*/
{0.922, 0.922, 0.922},
{0.560, 0.436, 0.137},
{0.545, 0.545, 0.796},
{0.420, 0.420, 0.059},
{0.498, 0.000, 0.000},
{0.686, 0.404, 0.137},
{1.000, 0.953, 0.106},
{0.890, 0.702, 0.592},
{0.671, 0.545, 0.639},
{0.733, 0.451, 0.624},
{0.859, 0.765, 0.733},
{0.436, 0.514, 0.482},
{1.000, 0.953, 0.106},
{0.000, 0.000, 1.000},
{0.969, 0.827, 0.545}
};
int numsortedplayers;
int trackedplayer;
int sortedplayers[32];
plugclientinfo_t players[32];
void SortPlayers(void)
{
int i, j;
int temp;
numsortedplayers = 0;
trackedplayer = -1;
for (i = 0; i < 32; i++)
{
if (GetPlayerInfo(i, &players[i])>0)
trackedplayer = i;
if (players[i].spectator)
continue;
if (*players[i].name != 0)
sortedplayers[numsortedplayers++] = i;
}
for (i = 0; i < numsortedplayers; i++)
{
for (j = i+1; j < numsortedplayers; j++)
{
if (players[sortedplayers[i]].frags < players[sortedplayers[j]].frags)
{
temp = sortedplayers[j];
sortedplayers[j] = sortedplayers[i];
sortedplayers[i] = temp;
}
}
}
}
typedef struct {
char name[8];
int frags;
int tc;
int bc;
} teams_t;
teams_t team[32];
int numsortedteams;
void SortTeams(void)
{
teams_t temp;
int i, j;
numsortedplayers = 0;
trackedplayer = -1;
for (i = 0; i < 32; i++)
{
if (GetPlayerInfo(i, &players[i])>0)
trackedplayer = i;
if (players[i].spectator)
continue;
if (*players[i].name != 0)
sortedplayers[numsortedplayers++] = i;
for (j = 0; j < numsortedteams; j++)
{
if (!strcmp(team[j].name, players[i].name))
{
team[j].frags += players[i].frags;
while(j > 0)
{
if (team[j-1].frags < team[j].frags)
{
memcpy(&temp, &team[j], sizeof(teams_t));
memcpy(&team[j], &team[j-1], sizeof(teams_t));
memcpy(&team[j-1], &temp, sizeof(teams_t));
j--;
}
else
break;
}
}
}
if (j == numsortedteams)
{
strlcpy(team[j].name, players[i].name, sizeof(team[j].name));
team[j].frags = players[i].frags;
team[j].tc = players[i].topcolour;
team[j].bc = players[i].bottomcolour;
numsortedteams++;
}
}
}
void Hud_ScoreCard(void)
{
int frags, tc, bc, p;
int brackets;
char number[6];
if (hudedit)
{
frags = sbartype;
tc = 0;
bc = 0;
brackets = 1;
}
else
{
SortPlayers();
if (sbartype>=numsortedplayers)
return;
p = sortedplayers[sbartype];
bc = players[p].bottomcolour;
tc = players[p].topcolour;
frags = players[p].frags;
brackets = p==trackedplayer;
}
Draw_Colour4f(pc[tc][0], pc[tc][1], pc[tc][2], sbaralpha);
Draw_Fill(sbarminx, sbarminy, (float)32*sbarscalex, (float)4*sbarscaley);
Draw_Colour4f(pc[bc][0], pc[bc][1], pc[bc][2], sbaralpha);
Draw_Fill(sbarminx, sbarminy+4*sbarscaley, (float)32*sbarscalex, (float)4*sbarscaley);
Draw_Colour4f(1, 1, 1, sbaralpha);
if (brackets)
{
UI_DrawChar(16, 0, 0);
UI_DrawChar(17, 24, 0);
}
snprintf(number, sizeof(number), "%-3i", frags);
UI_DrawChar(number[0], 4, 0);
UI_DrawChar(number[1], 12, 0);
UI_DrawChar(number[2], 20, 0);
Draw_Colour4f(1,1,1,1);
}
void Hud_ScoreName(void)
{
int p;
char *name;
if (hudedit)
{
name = va("Player %i", sbartype);
}
else
{
SortPlayers();
if (sbartype>=numsortedplayers)
return;
p = sortedplayers[sbartype];
name = players[p].name;
}
UI_DrawString(name, 0, 0);
}
void Hud_TeamScore(void)
{
int frags, tc, bc, p;
int brackets;
char number[6];
if (hudedit)
{
frags = sbartype;
tc = 0;
bc = 0;
brackets = 1;
}
else
{
SortPlayers();
if (sbartype>=numsortedteams)
return;
p = sbartype;
bc = team[p].bc;
tc = team[p].tc;
frags = team[p].frags;
brackets = p==trackedplayer;
}
Draw_Colour4f(pc[tc][0], pc[tc][1], pc[tc][2], sbaralpha);
Draw_Fill(sbarminx, sbarminy, (float)32*sbarscalex, (float)4*sbarscaley);
Draw_Colour4f(pc[bc][0], pc[bc][1], pc[bc][2], sbaralpha);
Draw_Fill(sbarminx, sbarminy+4*sbarscaley, (float)32*sbarscalex, (float)4*sbarscaley);
Draw_Colour4f(1, 1, 1, sbaralpha);
if (brackets)
{
UI_DrawChar(16, 0, 0);
UI_DrawChar(17, 24, 0);
}
snprintf(number, sizeof(number), "%-3i", frags);
UI_DrawChar(number[0], 4, 0);
UI_DrawChar(number[1], 12, 0);
UI_DrawChar(number[2], 20, 0);
Draw_Colour4f(1,1,1,1);
}
void Hud_TeamName(void)
{
int p;
char *tname;
if (hudedit)
{
tname = va("T%-3i", sbartype);
}
else
{
SortTeams();
if (sbartype>=numsortedteams)
return;
p = sbartype;
tname = team[p].name;
}
Draw_Colour4f(1, 1, 1, sbaralpha);
if (tname[0])
{
UI_DrawChar(tname[0], 0, 0);
if (tname[1])
{
UI_DrawChar(tname[1], 8, 0);
if (tname[2])
{
UI_DrawChar(tname[2], 8, 0);
if (tname[3])
{
UI_DrawChar(tname[3], 8, 0);
}
}
}
}
Draw_Colour4f(1,1,1,1);
}
void Hud_TeamOverlay(void)
{
static int current_player = -1;
int offset = 0;
if (hudedit)
{
UI_DrawString("UnnamedPlayer1: r999/999 rlg ra-mega", 0, 0);
UI_DrawString("UnnamedPlayer2: r999/999 rlg ra-mega", 0, 16);
UI_DrawString("UnnamedPlayer3: r999/999 rlg ra-mega", 0, 32);
}
else
{
unsigned int i;
// If the tracking has changed, flush the old teaminfo
if (current_player != players[trackedplayer].userid)
{
int j;
for (j = 0; j < 32; j++)
player_nick[j] = "";
player_nicklength = 0;
current_player = players[trackedplayer].userid;
return;
}
for (i = 0; i < 32; i++)
{
// Empty nicknames are defined as not being printed
if (player_nick[i] != "")
{
char armortype = ' ';
char* bestweap = " ";
char loc[256], str[256], spacing[64], spacing_a[64], spacing_h[64];
unsigned int j;
// More info about armortype
if (player_items[i] & IT_ARMOR3)
armortype = 'r';
else if (player_items[i] & IT_ARMOR2)
armortype = 'y';
else if (player_items[i] & IT_ARMOR1)
armortype = 'g';
// Only care about reporting weapons that have some meaning
if ((player_items[i] & (IT_GUN6 | IT_GUN7)) == (IT_GUN6 | IT_GUN7))
bestweap = "rlg ";
else if ((player_items[i] & IT_GUN7) == IT_GUN7)
bestweap = "lg ";
else if ((player_items[i] & IT_GUN6) == IT_GUN6)
bestweap = "rl ";
else if ((player_items[i] & IT_GUN5) == IT_GUN5)
bestweap = "gl ";
else if ((player_items[i] & IT_GUN4) == IT_GUN4)
bestweap = "sng ";
else if ((player_items[i] & IT_GUN2) == IT_GUN2)
bestweap = "ssg ";
GetLocationName(player_location[i], loc, sizeof(loc));
// Format spacing
// Nicknames
for (j = 0; j < (player_nicklength - strlen(player_nick[i]) + 1) && j < sizeof(spacing); j++)
spacing[j] = ' ';
spacing[j] = '\0';
// Armor
if (player_armor[i] % 10 == player_armor[i])
strlcpy(spacing_a, " ", sizeof(spacing_a)); // 0 - 9
else if (player_armor[i] % 100 == player_armor[i])
strlcpy(spacing_a, " ", sizeof(spacing_a)); // 10 - 99
else
strlcpy(spacing_a, "", sizeof(spacing_a));
// Health
if (player_health[i] % 10 == player_health[i])
strlcpy(spacing_h, " ", sizeof(spacing_h)); // 0 - 9
else if (player_health[i] % 100 == player_health[i])
strlcpy(spacing_h, " ", sizeof(spacing_h)); // 10 - 99
else
strlcpy(spacing_h, "", sizeof(spacing_h));
// TODO: Translate $5 and similar macros in loc names.
snprintf(str, sizeof(str), "%s%c%s%s%c%d%c%d %s%s%c%s%c",
player_nick[i], // player netname
':'+128, // colored colon
spacing, // spacing
spacing_a, // armor spacing
armortype, // armor type: r, y, g or none
player_armor[i], // current armor
'/'+128, // colored slash
player_health[i], // current health
spacing_h, // health spacing
bestweap, // best weapon
'\x10', // left bracket
loc, // player location
'\x11' // right bracket
);
UI_DrawString(str, 0, offset);
offset += 16;
}
}
}
}
void Hud_TeamOverlayUpdate(void)
{
int user;
char str[256];
// Number in the players[] array
Cmd_Argv(1, str, sizeof(str));
user = atoi(str);
// Position in the x-axis
Cmd_Argv(2, str, sizeof(str));
player_location[user][0] = atoi(str);
// Position in the y-axis
Cmd_Argv(3, str, sizeof(str));
player_location[user][1] = atoi(str);
// Position in the z-axis
Cmd_Argv(4, str, sizeof(str));
player_location[user][2] = atoi(str);
// Player health
Cmd_Argv(5, str, sizeof(str));
player_health[user] = atoi(str);
// Player armor
Cmd_Argv(6, str, sizeof(str));
player_armor[user] = atoi(str);
// Player item bitmask
Cmd_Argv(7, str, sizeof(str));
player_items[user] = atoi(str);
// Setting this nick will make this info print
player_nick[user] = players[user].name;
// Check who has the longest nick for a better overlay format
if (strlen(player_nick[user]) > player_nicklength)
player_nicklength = strlen(player_nick[user]);
return;
}
//fixme: draw dark blobs
void Hud_Blackness(void)
{
Draw_Colour4f(0, 0, 0, (sbartype+1)/10.0f);
if (hudedit)
{
if (sbarindex == currentitem)
{
float j = ((currenttime % 1000) - 500) / 500.0f;
if (j < 0)
j = -j;
j/=3;
Draw_Colour4f(j, 0, 0, (sbartype+1)/10.0f);
}
else if (sbarindex == hoveritem)
{
Draw_Colour4f(0.0, 0.2, 0.0, (sbartype+1)/10.0f);
}
}
Draw_Fill(sbarminx, sbarminy, (float)16*sbarscalex, (float)16*sbarscaley);
Draw_Colour4f(1,1,1,1);
}
void Hud_Tracking(void)
{
qboolean flag = false;
char str[256];
if (hudedit)
{
UI_DrawString("Tracking ...", 0, 0);
return;
}
// FIXME: Need a check here to return if we are not spectating
// Print it
snprintf(str, sizeof(str), "Tracking %s", players[trackedplayer].name);
UI_DrawString(str, 0, 0);
}
void UI_DrawHandles(int *arg, int i)
{
int mt;
float vsx, vsy;
vsx = arg[3]/640.0f;
vsy = arg[4]/480.0f;
sbarminx = arg[1] + element[i].x*vsx;
sbarminy = arg[2] + element[i].y*vsy;
sbarscalex = element[i].scalex*vsx;
sbarscaley = element[i].scaley*vsy;
mt = element[i].type;
sbartype = element[i].subtype;
sbaralpha = element[i].alpha;
Draw_Colour4f(1, 0, 0, 1);
Draw_Fill(sbarminx+drawelement[mt].width*sbarscalex-((sbarscalex<0)?0:(vsx*4)), sbarminy-((sbarscaley>=0)?0:(vsy*4)), (float)4*vsx, (float)4*vsy);
Draw_Colour4f(0, 1, 0, 1);
Draw_Fill(sbarminx+drawelement[mt].width*sbarscalex-((sbarscalex<0)?0:(vsx*4)), sbarminy+drawelement[mt].height*sbarscaley-((sbarscaley<0)?0:(vsy*4)), (float)4*vsx, (float)4*vsy);
}
//draw body of sbar
//arg[0] is playernum
//arg[1]/arg[2] is x/y start of subwindow
//arg[3]/arg[4] is width/height of subwindow
int UI_StatusBar(int *arg)
{
int i;
float vsx, vsy;
if (hudedit) // don't redraw twice
return 1;
if (arg[5])
return 1;
CL_GetStats(arg[0], stats, sizeof(stats)/sizeof(int));
if (stats[STAT_HEALTH] <= 0)
return 1;
vsx = arg[3]/640.0f;
vsy = arg[4]/480.0f;
for (i = 0; i < numelements; i++)
{
sbarminx = arg[1] + element[i].x*vsx;
sbarminy = arg[2] + element[i].y*vsy;
sbarscalex = element[i].scalex*vsx;
sbarscaley = element[i].scaley*vsy;
sbartype = element[i].subtype;
sbaralpha = element[i].alpha;
drawelement[element[i].type].draw();
}
return 1;
}
int UI_StatusBarEdit(int *arg) // seperated so further improvements to editor view can be done
{
int i;
float vsx, vsy;
qboolean clrset = false;
CL_GetStats(arg[0], stats, sizeof(stats)/sizeof(int));
vsx = arg[3]/640.0f;
vsy = arg[4]/480.0f;
for (i = 0; i < numelements; i++)
{
if (i == currentitem)
{
float j = ((currenttime % 1000) - 500) / 500.0f;
if (j < 0)
j = -j;
Draw_Colour3f(1.0, j, j);
clrset = true;
}
else if (i == hoveritem)
{
Draw_Colour3f(0.0, 1.0, 0.0);
clrset = true;
}
sbarminx = arg[1] + element[i].x*vsx;
sbarminy = arg[2] + element[i].y*vsy;
sbarscalex = element[i].scalex*vsx;
sbarscaley = element[i].scaley*vsy;
sbartype = element[i].subtype;
sbaralpha = element[i].alpha;
sbarindex = i;
drawelement[element[i].type].draw();
if (clrset)
{
Draw_Colour3f(1.0, 1.0, 1.0);
clrset = false;
}
}
return true;
}
/*
int UI_ScoreBoard(int *arg)
{
int i;
if (!arg[5])
return false;
sbarminx = 320;
sbarminy = 48;
sbarscalex = 1;
sbarscaley = 1;
sbaralpha = 1;
SortPlayers();
for (i = 0; i < numsortedplayers; i++)
{
sbartype = i;
Hud_ScoreCard();
UI_DrawString(players[sortedplayers[i]].name, 40, 0);
sbarminy += 16;
}
return true;
}
*/
#define HUD_VERSION 52345
void PutFloat(float f, char sep, qhandle_t handle)
{
char *buffer;
buffer = va("%f%c", f, sep);
FS_Write(handle, buffer, strlen(buffer));
}
void PutInteger(int i, char sep, qhandle_t handle)
{
char *buffer;
buffer = va("%i%c", i, sep);
FS_Write(handle, buffer, strlen(buffer));
}
void Hud_Save(char *fname)
{
char name[256];
int i;
qhandle_t handle;
if (!fname || !*fname)
fname = DEFAULTHUDNAME;
snprintf(name, sizeof(name)-5, "huds/%s", fname);
COM_DefaultExtension(name, ".hud", sizeof(name));
if (FS_Open(name, &handle, 2)<0)
{
Con_Printf("Couldn't open %s\n", name);
return;
}
PutInteger(HUD_VERSION, '\n', handle);
PutInteger(numelements, '\n', handle);
for (i = 0; i < numelements; i++)
{
PutFloat(element[i].x, ' ', handle);
PutFloat(element[i].y, ' ', handle);
PutFloat(element[i].scalex, ' ', handle);
PutFloat(element[i].scaley, ' ', handle);
PutInteger(element[i].type, ' ', handle);
PutInteger(element[i].subtype, ' ', handle);
PutFloat(element[i].alpha, '\n', handle);
}
FS_Close(handle);
}
float GetFloat(char **f, qhandle_t handle)
{
char *ts;
while(**f <= ' ' && **f != 0)
(*f)++;
while(*f[0] == '/' && *f[1] == '/')
{
while(**f != '\n' && **f != 0)
(*f)++;
while(**f <= ' ' && **f != 0)
(*f)++;
}
ts = *f;
while (**f>' ')
(*f)++;
return (float)atof(ts);
}
int GetInteger(char **f, qhandle_t handle)
{
char *ts;
while(**f <= ' ' && **f != 0)
(*f)++;
while(*f[0] == '/' && *f[1] == '/')
{
while(**f != '\n' && **f != 0)
(*f)++;
while(**f <= ' ' && **f != 0)
(*f)++;
}
ts = *f;
while (**f>' ')
(*f)++;
return atoi(ts);
}
void Hud_Load(char *fname)
{
char file[16384];
char name[256];
char *p;
int len;
int i;
qhandle_t handle;
int ver;
float x, y, sx, sy, a;
int type, subtype;
if (!fname || !*fname)
fname = DEFAULTHUDNAME;
snprintf(name, sizeof(name)-5, "huds/%s", fname);
COM_DefaultExtension(name, ".hud", sizeof(name));
len = FS_Open(name, &handle, 1);
if (len < 0)
{
Con_Printf("Couldn't load file\n");
return;
}
if (len > 16383)
len = 16383;
FS_Read(handle, file, len);
file[len] = 0;
FS_Close(handle);
p = file;
ver = GetInteger(&p, handle);
if (ver != HUD_VERSION)
{
Con_Printf("Hud version doesn't match (%i != %i)\n", ver, HUD_VERSION);
return;
}
numelements = GetInteger(&p, handle);
if (numelements > MAX_ELEMENTS)
{
numelements = 0;
Con_Printf("Hud has too many elements\n");
return;
}
for (i = 0; i < numelements; i++)
{
x = GetFloat(&p, handle);
y = GetFloat(&p, handle);
sx = GetFloat(&p, handle);
sy = GetFloat(&p, handle);
type = GetInteger(&p, handle);
subtype = GetInteger(&p, handle);
a = GetFloat(&p, handle);
if (type<0 || type>=sizeof(drawelement)/sizeof(drawelement[0]))
{
numelements--;
i--;
continue;
}
element[i].x = x;
element[i].y = y;
element[i].scalex = sx;
element[i].scaley = sy;
element[i].alpha = a;
element[i].type = type;
element[i].subtype = subtype;
}
currentitem = -1;
}
// FindItemUnderMouse: given mouse coordinates, finds element number under mouse
// returns -1 if no element found
int FindItemUnderMouse(int mx, int my)
{
int i;
int rv;
rv = -1;
for (i = 0; i < numelements; i++)
{
if (element[i].scalex < 0)
{
if (element[i].x < mx)
continue;
if (element[i].x + element[i].scalex*drawelement[element[i].type].width > mx)
continue;
}
else
{
if (element[i].x > mx)
continue;
if (element[i].x + element[i].scalex*drawelement[element[i].type].width < mx)
continue;
}
if (element[i].scaley < 0)
{
if (element[i].y < my)
continue;
if (element[i].y + element[i].scaley*drawelement[element[i].type].height > my)
continue;
}
else
{
if (element[i].y > my)
continue;
if (element[i].y + element[i].scaley*drawelement[element[i].type].height < my)
continue;
}
rv = i;
}
return rv; // no element found
}
void DrawContextMenu(int mx, int my)
{
int y;
Draw_Colour4f(0, 0, 0, 0.4);
Draw_Fill((mouseofsx-8)*sbarscalex, (mouseofsy-8)*sbarscaley, (float)112*sbarscalex, (float)(9*8)*sbarscaley);
Draw_Colour4f(1,1,1,1);
sbarminx = mouseofsx*sbarscalex;
sbarminy = mouseofsy*sbarscaley;
my -= mouseofsy;
my/=8;
my--;
mx -= mouseofsx;
if (mx < 0)
my = -10;
if (mx > 12*8)
my = -10;
y = 0;
UI_DrawAltString("CONTEXT MENU", 0, y, 1);
y+=8;
UI_DrawAltString("------------", 0, y, 0);
y+=8;
UI_DrawAltString("New", 0, y, (my--)==1);
y+=8;
UI_DrawAltString("Snap To Grid", 0, y, (my--)==1);
if (shiftdown)
UI_DrawAltString("X", -8, y, (my)==1);
y+=8;
UI_DrawAltString("Save", 0, y, (my--)==1);
y+=8;
UI_DrawAltString("Reload", 0, y, (my--)==1);
y+=8;
UI_DrawAltString("Defaults", 0, y, (my--)==1);
y+=8;
}
void DrawPrimaryCreationMenu(int mx, int my)
{
int i;
int y;
int numopts;
numopts = sizeof(drawelement)/sizeof(drawelement[0]);
numopts += 2;
Draw_Colour4f(0, 0, 0, 0.4);
Draw_Fill((mouseofsx-8)*sbarscalex, (mouseofsy-8)*sbarscaley, (float)(17*8)*sbarscalex, (float)((numopts+2)*8)*sbarscaley);
Draw_Colour4f(1,1,1,1);
sbarminx = mouseofsx*sbarscalex;
sbarminy = mouseofsy*sbarscaley;
my -= mouseofsy;
my/=8;
my--;
mx -= mouseofsx;
if (mx < 0)
my = -10;
if (mx > 12*8)
my = -10;
y = 0;
UI_DrawAltString("CREATE NEW ITEM", 0, y, 1);
y+=8;
UI_DrawAltString("------------", 0, y, 0);
y+=8;
for (i = 0; i < sizeof(drawelement)/sizeof(drawelement[0]); i++)
{
UI_DrawAltString(drawelement[i].name, 0, y, (my--)==1);
y+=8;
}
}
void DrawSecondaryCreationMenu(int mx, int my)
{
int i;
int y;
int numopts;
numopts = drawelement[typetoinsert].maxsubtype+1;
numopts += 2;
Draw_Colour4f(0, 0, 0, 0.4);
Draw_Fill((mouseofsx-8)*sbarscalex, (mouseofsy-8)*sbarscaley, (float)(17*8)*sbarscalex, (float)((numopts+2)*8)*sbarscaley);
Draw_Colour4f(1,1,1,1);
sbarminx = mouseofsx*sbarscalex;
sbarminy = mouseofsy*sbarscaley;
my -= mouseofsy;
my/=8;
my--;
mx -= mouseofsx;
if (mx < 0)
my = -10;
if (mx > 12*8)
my = -10;
y = 0;
UI_DrawAltString("CREATE NEW ITEM", 0, y, 1);
y+=8;
UI_DrawAltString("------------", 0, y, 0);
y+=8;
for (i = 0; i <= drawelement[typetoinsert].maxsubtype; i++)
{
UI_DrawAltString(drawelement[typetoinsert].subtypename[i].name, 0, y, (my--)==1);
y+=8;
}
}
void UI_KeyPress(int key, int mx, int my)
{
int i;
if (key == K_ESCAPE)
{
Menu_Control(0);
return;
}
if (context)
{
if (key != K_MOUSE1)
{
context = false;
return;
}
mx -= mouseofsx;
if (mx < 0)
my = -10;
if (mx > 12*8)
my = -10;
i = my - mouseofsy;
i /= 8;
if (context == 3)
{
context = false;
if ((unsigned)(i-2) > (unsigned)drawelement[typetoinsert].maxsubtype)
return;
currentitem = numelements;
numelements++;
if (typetoinsert == 12)
{
int j;
// Blackness should be sent to the back
for (j = currentitem; j > 0; j--)
{
element[j] = element[j-1];
}
currentitem = 0;
}
element[currentitem].type = typetoinsert;
element[currentitem].alpha = 1;
element[currentitem].scalex = 1;
element[currentitem].scaley = 1;
element[currentitem].x = 320;
element[currentitem].y = 240;
element[currentitem].subtype = i-2;
}
else if (context == 2)
{
typetoinsert = i-2;
if ((unsigned)typetoinsert >= sizeof(drawelement)/sizeof(drawelement[0]))
{
context = false;
return;
}
if (drawelement[typetoinsert].maxsubtype != 0)
context = 3;
else
{
context = false;
currentitem = numelements;
numelements++;
element[currentitem].type = i-2;
element[currentitem].alpha = 1;
element[currentitem].scalex = 1;
element[currentitem].scaley = 1;
element[currentitem].x = 320;
element[currentitem].y = 240;
element[currentitem].subtype = 0;
}
}
else
{
context = false;
switch(i)
{
case 2: //clone
if (numelements==MAX_ELEMENTS)
return; //too many
/*
memcpy(element+numelements, element+currentitem, sizeof(hudelement_t));
currentitem = numelements;
numelements++;
*/
context = 2;
break;
case 3: //snap
shiftdown ^= 1;
break;
case 4: //save
Hud_Save(NULL);
break;
case 5: //reload
Hud_Load(NULL);
break;
case 6: //defaults
SBar_FlushAll();
SBar_ReloadDefaults();
break;
}
}
return;
}
if (key == K_MOUSE1)
{ //figure out which one our cursor is over...
mousedown = false;
i = FindItemUnderMouse(mx, my);
if (i != -1)
{
int oldcurrent;
float big;
oldcurrent = currentitem;
currentitem = i;
mouseofsx = mx - element[i].x;
mouseofsy = my - element[i].y;
mousedown |= 1;
if (element[i].scalex < 0)
{
if (mx > element[i].x+4)
return;
}
else
{
big = element[i].scalex*drawelement[element[i].type].width;
if (mx-element[i].x+4 < big)
return;
}
if (my < element[i].y+4)
{
if (currentitem == oldcurrent)
UI_KeyPress('d', 0, 0);
return;
}
if (element[i].scaley < 0)
{
if (my > element[i].y+4)
return;
}
else
{
big = element[i].scaley*drawelement[element[i].type].height;
if (my-element[i].y+4 < big)
return;
}
mouseofsx = mx - element[i].scalex*drawelement[element[i].type].width;
mouseofsy = my - element[i].scaley*drawelement[element[i].type].height;
mousedown |= 2;
}
else
currentitem = -1;
}
// TODO: extra buttons
// - toggle clip to edges and clip to other controls
// - maybe toggle snap to grid instead of holding shift with mouse?
else if (key == K_MOUSE2)
{
mousedown = false; //perhaps not logically true, but it's safest this way.
context = true;
mouseofsx = mx;
mouseofsy = my;
}
else if (key == 'n')
{
currentitem++;
if (currentitem >= numelements)
currentitem = 0;
}
else if (key == 'm')
{
currentitem--;
if (currentitem < 0)
currentitem = numelements ? numelements - 1 : 0;
}
else if (key == 'i')
{
if (numelements==MAX_ELEMENTS)
return; //too many
element[numelements].scalex = 1;
element[numelements].scaley = 1;
element[numelements].alpha = 1;
numelements++;
}
else if (key == K_SHIFT)
shiftdown = true;
else if (currentitem < numelements && currentitem != -1)
{
if (key == 'd')
{
mousedown = false;
memcpy(element+currentitem, element+currentitem+1, sizeof(element[0]) * (numelements - currentitem-1));
numelements--;
currentitem = -1;
}
else if (key == 'c' || key == 'C')
{
if (numelements==MAX_ELEMENTS)
return; //too many
memcpy(element+numelements, element+currentitem, sizeof(hudelement_t));
currentitem = numelements;
numelements++;
}
else if (key == K_PAGEUP)
{ //send to back
hudelement_t temp;
memcpy(&temp, element+currentitem, sizeof(temp));
memmove(element+1, element, sizeof(hudelement_t) * (currentitem));
memcpy(element, &temp, sizeof(hudelement_t));
currentitem = 0;
}
else if (key == K_PAGEDOWN)
{ //bring to front
hudelement_t temp;
memcpy(&temp, element+currentitem, sizeof(temp));
memcpy(element+currentitem, element+currentitem+1, sizeof(element[0]) * (numelements - currentitem-1));
currentitem = numelements - 1;
memcpy(element+currentitem , &temp, sizeof(hudelement_t));
}
else if (key == 'q')
{
element[currentitem].type--;
if (element[currentitem].type < 0)
element[currentitem].type = sizeof(drawelement)/sizeof(drawelement[0])-1;
}
else if (key == 'w')
{
element[currentitem].type++;
if (element[currentitem].type >= sizeof(drawelement)/sizeof(drawelement[0]))
element[currentitem].type = 0;
}
else if (key == ',' || key == K_MWHEELUP)
{
element[currentitem].subtype--;
if (element[currentitem].subtype < 0)
element[currentitem].subtype = drawelement[element[currentitem].type].maxsubtype;
}
else if (key == '.' || key == K_MWHEELDOWN)
{
element[currentitem].subtype++;
if (element[currentitem].subtype > drawelement[element[currentitem].type].maxsubtype)
element[currentitem].subtype = 0;
}
else if (key == K_UPARROW)
{
element[currentitem].y-=shiftdown?8:1;
}
else if (key == K_DOWNARROW)
{
element[currentitem].y+=shiftdown?8:1;
}
else if (key == K_LEFTARROW)
{
element[currentitem].x-=shiftdown?8:1;
}
else if (key == K_RIGHTARROW)
{
element[currentitem].x+=shiftdown?8:1;
}
else if (key == K_HOME)
{
element[currentitem].scalex=1.0f;
element[currentitem].scaley=1.0f;
element[currentitem].alpha=1.0f;
}
else if (key == '+')
{
element[currentitem].scalex*=1.1f;
element[currentitem].scaley*=1.1f;
}
else if (key == '-')
{
element[currentitem].scalex/=1.1f;
element[currentitem].scaley/=1.1f;
}
}
}
int Plug_MenuEvent(int *args)
{
int altargs[5];
float cursorbias;
float cursorsize;
args[2]=(int)(args[2]*640.0f/vid.width);
args[3]=(int)(args[3]*480.0f/vid.height);
switch(args[0])
{
case 0: //draw
// TODO: some sort of element property display
if (context)
{
}
else if (mousedown)
{
if (mousedown & 2) //2 is 'on the scaler'
{
float w = args[2] - mouseofsx;
float h = args[3] - mouseofsy;
if (shiftdown || (mousedown & 4)) //4 is mouse2
{
w -= (int)w & 7;
h -= (int)h & 7;
}
if (w < 8 && w > -8)
w = 8;
if (h < 8 && h > -8)
h = 8;
element[currentitem].scalex = w/drawelement[element[currentitem].type].width;
element[currentitem].scaley = h/drawelement[element[currentitem].type].height;
}
else
{
element[currentitem].x = args[2] - mouseofsx;
element[currentitem].y = args[3] - mouseofsy;
if (shiftdown || (mousedown & 4)) //4 is mouse2
{
element[currentitem].x -= (int)element[currentitem].x & 7;
element[currentitem].y -= (int)element[currentitem].y & 7;
}
}
}
else
hoveritem = FindItemUnderMouse(args[2], args[3]); // this could possibly slow some things down...
altargs[0] = 0;
altargs[1] = 0;
altargs[2] = 0;
altargs[3] = vid.width;
altargs[4] = vid.height;
if (hudedit)
UI_StatusBarEdit(altargs);
// else
// UI_StatusBar(altargs); //draw it using the same function (we're lazy)
if (currentitem >= 0)
UI_DrawHandles(altargs, currentitem);
sbarscalex = vid.width/640.0f;
sbarscaley = vid.height/480.0f;
switch (context)
{
case 1:
DrawContextMenu(args[2], args[3]);
break;
case 2:
DrawPrimaryCreationMenu(args[2], args[3]);
break;
case 3:
DrawSecondaryCreationMenu(args[2], args[3]);
break;
default:
break;
}
sbarminx = args[2];
sbarminy = args[3];
cursorbias = Cvar_GetFloat("cl_cursorbias");
cursorsize = Cvar_GetFloat("cl_cursorsize");
Draw_Colour4f(1,1,1,1);
Draw_Image(((float)args[2]*sbarscalex)-cursorbias, ((float)args[3]*sbarscaley)-cursorbias, (float)cursorsize*sbarscalex, (float)cursorsize*sbarscaley, 0, 0, 1, 1, pic_cursor);
break;
case 1: //keydown
UI_KeyPress(args[1], args[2], args[3]);
break;
case 2: //keyup
if (args[1] == K_MOUSE1)
mousedown = false;
else if (args[1] == K_SHIFT)
shiftdown = false;
break;
case 3: //menu closed (this is called even if we change it).
hudedit = false;
break;
case 4: //mousemove
break;
}
return 0;
}
int Plug_Tick(int *args)
{
currenttime = args[0];
return true;
}
int Plug_ExecuteCommand(int *args)
{
char cmd[256];
Cmd_Argv(0, cmd, sizeof(cmd));
if (!strcmp("sbar_edit", cmd) || !strcmp("hud_edit", cmd))
{
Menu_Control(1);
mousedown=false;
hudedit=true;
return 1;
}
if (!strcmp("sbar_save", cmd) || !strcmp("hud_save", cmd))
{
Cmd_Argv(1, cmd, sizeof(cmd));
Hud_Save(cmd);
mousedown=false;
return 1;
}
if (!strcmp("sbar_load", cmd) || !strcmp("hud_load", cmd))
{
Cmd_Argv(1, cmd, sizeof(cmd));
Hud_Load(cmd);
mousedown=false;
return 1;
}
if (!strcmp("sbar_defaults", cmd) || !strcmp("hud_defaults", cmd))
{
Cmd_Argv(1, cmd, sizeof(cmd));
SBar_FlushAll();
SBar_ReloadDefaults();
mousedown=false;
return 1;
}
// Modify a HUD element
if (!strcmp("sbar", cmd) || !strcmp("hud", cmd))
{
// FIXME: add this command
return 1;
}
// Support for KTX team overlay
if (!strcmp("tinfo", cmd))
{
Hud_TeamOverlayUpdate();
return 1;
}
return 0;
}
int Plug_Init(int *args)
{
if (Plug_Export("Tick", Plug_Tick) &&
Plug_Export("SbarBase", UI_StatusBar) &&
// Plug_Export("SbarOverlay", UI_ScoreBoard) &&
Plug_Export("ExecuteCommand", Plug_ExecuteCommand) &&
Plug_Export("MenuEvent", Plug_MenuEvent))
{
K_UPARROW = Key_GetKeyCode("uparrow");
K_DOWNARROW = Key_GetKeyCode("downarrow");
K_LEFTARROW = Key_GetKeyCode("leftarrow");
K_RIGHTARROW = Key_GetKeyCode("rightarrow");
K_ESCAPE = Key_GetKeyCode("escape");
K_HOME = Key_GetKeyCode("home");
K_MOUSE1 = Key_GetKeyCode("mouse1");
K_MOUSE2 = Key_GetKeyCode("mouse2");
K_MWHEELDOWN = Key_GetKeyCode("mwheeldown");
K_MWHEELUP = Key_GetKeyCode("mwheelup");
K_SHIFT = Key_GetKeyCode("shift");
K_PAGEUP = Key_GetKeyCode("pgup");
K_PAGEDOWN = Key_GetKeyCode("pgdn");
Cmd_AddCommand("hud_edit");
Cmd_AddCommand("sbar_edit");
if (BUILTINISVALID(FS_Write))
{
Cmd_AddCommand("hud_save");
Cmd_AddCommand("sbar_save");
}
if (BUILTINISVALID(FS_Read))
{
Cmd_AddCommand("hud_load");
Cmd_AddCommand("sbar_load");
}
Cmd_AddCommand("hud_defaults");
Cmd_AddCommand("sbar_defaults");
// For modifying hud elements
Cmd_AddCommand("hud");
Cmd_AddCommand("sbar");
// Teamoverlay support
Cmd_AddCommand("tinfo");
Cmd_AddText("newalias ktx_infoset \"cmd info ti 1\"\n", false);
UI_SbarInit();
if (BUILTINISVALID(FS_Read))
Hud_Load("");
return 1;
}
return 0;
}