if (!scoreboard_fade_alpha) // the scoreboard too calls Scoreboard_UpdatePlayerTeams
Scoreboard_UpdatePlayerTeams();
+ /*
if (team_count)
{
// show team scores in the first line
first_pl = 1;
pos.y += fontsize.y;
tm = teams.sort_next;
- }
- i = first_pl;
-
- do
- for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
+ }*/
+
+
+ // z411 Basic team stats
+ if (team_count)
{
- if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
- continue;
-
- if (i == entries-1 && !me_printed && pl != me)
- if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
- {
- for (pl = me.sort_next; pl; pl = pl.sort_next)
- if (pl.team != NUM_SPECTATOR)
- break;
+ i = 0;
+ for(tm = teams.sort_next; tm; tm = tm.sort_next) {
+ if(tm.team == NUM_SPECTATOR)
+ continue;
+ if(!tm.team)
+ continue;
- if (pl)
- rgb = '1 1 0'; //not last but not among the leading players: yellow
- else
- rgb = '1 0 0'; //last: red
- pl = me;
+ /*if (tm.team == myteam)
+ drawfill(pos + eX * score_size * i, vec2(score_size, fontsize.y), '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores(ts_primary))), vec2(score_size, fontsize.y), Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+ ++i;*/
+
+ if (tm.team == myteam)
+ {
+ if (i == 0)
+ rgb = '0 1 0'; //first: green
+ me_printed = true;
+ drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ score_color = Team_ColorRGB(tm.team) * 0.8;
+
+ // TODO secondary scores test, remove
+ if(gametype.m_modscores)
+ {
+ string icon;
+ if(tm.team == NUM_TEAM_1)
+ icon = "gfx/hud/luma/player_red";
+ else if(tm.team == NUM_TEAM_2)
+ icon = "gfx/hud/luma/player_blue";
+ else
+ icon = "gfx/hud/luma/player_neutral";
+
+ vector icon_sz = draw_getimagesize(icon);
+ vector icon_sz_new = vec2(fontsize.y*(icon_sz.x/icon_sz.y), fontsize.y);
+
+ s = ftos(gametype.m_modscores(tm.team));
+ float s_width = stringwidth(s, false, fontsize) + icon_sz_new.x;
+
+ //drawfill(pos, eX * s_width + eY * fontsize.y, score_color, panel_fg_alpha * 0.3, DRAWFLAG_NORMAL);
+ drawpic(pos, icon, icon_sz_new, '1 1 1', panel_fg_alpha * 0.7, DRAWFLAG_NORMAL);
+ drawstring(pos + eX * icon_sz_new.x, s, fontsize, '1 1 1', panel_fg_alpha * 0.7, DRAWFLAG_NORMAL);
+
+ s = textShortenToWidth(Team_CustomName(tm.team), name_size - s_width, fontsize, stringwidth_colors);
+ } else
+ s = textShortenToWidth(Team_CustomName(tm.team), name_size, fontsize, stringwidth_colors);
+ // TODO end
+
+ drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ draw_beginBoldFont();
+ drawstring(pos + eX * (name_size + spacing_size), ftos(tm.(teamscores(ts_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+
+ pos.y += fontsize.y;
+ ++i;
}
-
- if (pl == me)
+ } else {
+ i = first_pl;
+
+ do
+ for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
{
- if (i == first_pl)
- rgb = '0 1 0'; //first: green
- me_printed = true;
- drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
+ continue;
+
+ if (i == entries-1 && !me_printed && pl != me)
+ if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
+ {
+ for (pl = me.sort_next; pl; pl = pl.sort_next)
+ if (pl.team != NUM_SPECTATOR)
+ break;
+
+ if (pl)
+ rgb = '1 1 0'; //not last but not among the leading players: yellow
+ else
+ rgb = '1 0 0'; //last: red
+ pl = me;
+ }
+
+ if (team_count)
+ score_color = Team_ColorRGB(pl.team) * 0.8;
+
+ if (pl == me)
+ {
+ if (i == first_pl)
+ rgb = '0 1 0'; //first: green
+ me_printed = true;
+ drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
+ drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ pos.y += fontsize.y;
+ ++i;
}
- if (team_count)
- score_color = Team_ColorRGB(pl.team) * 0.8;
- s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
- drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
- pos.y += fontsize.y;
- ++i;
+ while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
}
- while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
}
void HUD_Score()
string hud_fontsize_str;
float max_namesize;
+vector duel_score_fontsize;
+vector duel_name_fontsize;
+vector duel_score_size;
+vector team_score_fontsize;
+vector team_name_fontsize;
+vector team_score_size;
+
float sbt_bg_alpha;
float sbt_fg_alpha;
float sbt_fg_alpha_self;
case "bctime": if (!mode) return CTX(_("SCO^bctime")); else LOG_HELP(strcat("^3", "bctime", " ^7", _("Total amount of time holding the ball in Keepaway")));
case "caps": if (!mode) return CTX(_("SCO^caps")); else LOG_HELP(strcat("^3", "caps", " ^7", _("How often a flag (CTF) or a key (KeyHunt) was captured")));
case "captime": if (!mode) return CTX(_("SCO^captime")); else LOG_HELP(strcat("^3", "captime", " ^7", _("Time of fastest capture (CTF)")));
+ case "country": if (!mode) return CTX(_("SCO^country")); else LOG_HELP(strcat("^3", "country", " ^7", _("Player country"))); //LegendGuard adds country for Country column 05-04-2021
case "deaths": if (!mode) return CTX(_("SCO^deaths")); else LOG_HELP(strcat("^3", "deaths", " ^7", _("Number of deaths")));
case "destroyed": if (!mode) return CTX(_("SCO^destroyed")); else LOG_HELP(strcat("^3", "destroyed", " ^7", _("Number of keys destroyed by pushing them into void")));
case "dmg": if (!mode) return CTX(_("SCO^damage")); else LOG_HELP(strcat("^3", "dmg", " ^7", _("The total damage done")));
// otherwise the previous exclusive rule warns anyway
// e.g. -teams,rc,cts,lms/kills ?+rc/kills
#define SCOREBOARD_DEFAULT_COLUMNS \
-"ping pl fps name |" \
+"ping pl fps country name |" \
" -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
" -teams,lms/deaths +ft,tdm/deaths" \
" +tdm/sum" \
}
else if(argv(2) == "all" || argv(2) == "ALL")
{
- string s = "ping pl name |"; // scores without label (not really scores)
+ string s = "ping pl country name |"; // scores without label (not really scores)
if(argv(2) == "ALL")
{
// scores without label
hud_fontsize = HUD_GetFontsize("hud_fontsize");
+ duel_score_fontsize = hud_fontsize * 3;
+ duel_name_fontsize = hud_fontsize * 1.5;
+ duel_score_size = vec2(duel_score_fontsize.x * 1.5, duel_score_fontsize.y * 1.25);
+
+ team_score_fontsize = hud_fontsize * 2;
+ team_name_fontsize = hud_fontsize * 1.5;
+ team_score_size = vec2(team_score_fontsize.x * 1.5, team_score_fontsize.y * 1.25);
+
for(i = 1; i < argc - 1; ++i)
{
str = argv(i+1);
// fields without a label (not networked via the score system)
case "ping": sbt_field[sbt_num_fields] = SP_PING; break;
case "pl": sbt_field[sbt_num_fields] = SP_PL; break;
+ case "country": sbt_field[sbt_num_fields] = SP_COUNTRY; break; //LegendGuard adds country label for Country column 05-04-2021
case "name": case "nick": sbt_field[sbt_num_fields] = SP_NAME; have_name = true; break;
case "|": sbt_field[sbt_num_fields] = SP_SEPARATOR; have_separator = true; break;
case "kd": case "kdr": case "kdratio": sbt_field[sbt_num_fields] = SP_KDRATIO; break;
string sbt_field_icon0;
string sbt_field_icon1;
string sbt_field_icon2;
+string sbt_field_icon3; //LegendGuard adds for Country player flags 05-04-2021
vector sbt_field_icon0_rgb;
vector sbt_field_icon1_rgb;
vector sbt_field_icon2_rgb;
return entcs_GetName(pl.sv_entnum);
}
+//LegendGuard adds GetCountrycode function 05-04-2021
+string Scoreboard_GetCountrycode(entity pl)
+{
+ int ccode = entcs_GetCountryCode(pl.sv_entnum);
+ if(ccode)
+ sbt_field_icon3 = strcat("gfx/flags/", ftos(ccode));
+ else
+ sbt_field_icon3 = strcat("gfx/flags/", ftos(0)); //if user hasn't assigned country flag
+
+ return "";
+ //return ftos(entcs_GetCountryCode(pl.sv_entnum)); //returns a number
+}
+
string Scoreboard_GetField(entity pl, PlayerScoreField field)
{
float tmp, num, denom;
sbt_field_icon0 = "";
sbt_field_icon1 = "";
sbt_field_icon2 = "";
+ sbt_field_icon3 = ""; //LegendGuard adds for Country column 05-04-2021
sbt_field_icon0_rgb = '1 1 1';
sbt_field_icon1_rgb = '1 1 1';
sbt_field_icon2_rgb = '1 1 1';
tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl
sbt_field_rgb = '1 0.5 0.5' - '0 0.5 0.5' * tmp;
return str;
+
+ //LegendGuard adds Country REGISTER in the switch 05-04-2021
+ case SP_COUNTRY:
+ str = Scoreboard_GetCountrycode(pl);
+ return str;
+
+ //LegendGuard adds Country REGISTER in the switch 05-04-2021
+ case SP_COUNTRY:
+ str = Scoreboard_GetCountrycode(pl);
+ return str;
case SP_NAME:
str = Scoreboard_GetName(pl);
sbt_fixcolumnwidth_iconlen = f;
}
+ //LegendGuard adds conditional for Country column 05-04-2021
+ if(sbt_field_icon3 != "")
+ {
+ sz = draw_getimagesize(sbt_field_icon3);
+ f = sz.x / sz.y;
+ if(sbt_fixcolumnwidth_iconlen < f)
+ sbt_fixcolumnwidth_iconlen = f;
+ }
+
if(sbt_fixcolumnwidth_iconlen != 0)
{
sbt_fixcolumnwidth_iconlen *= hud_fontsize.y / hud_fontsize.x; // fix icon aspect
drawpic(pos - tmp, sbt_field_icon1, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
if(sbt_field_icon2 != "")
drawpic(pos - tmp, sbt_field_icon2, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon2_rgb, fg_alpha, DRAWFLAG_NORMAL);
+ if(sbt_field_icon3 != "") //LegendGuard adds conditional for Country column 05-04-2021
+ drawpic(pos - tmp, sbt_field_icon3, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
}
if(sbt_field[i] == SP_SEPARATOR)
drawpic(pos - tmp, sbt_field_icon1, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
if(sbt_field_icon2 != "")
drawpic(pos - tmp, sbt_field_icon2, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon2_rgb, fg_alpha, DRAWFLAG_NORMAL);
+ if(sbt_field_icon3 != "") //LegendGuard adds conditional for Country column 05-04-2021
+ drawpic(pos - tmp, sbt_field_icon3, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, fg_alpha, DRAWFLAG_NORMAL);
pos.x -= sbt_field_size[i] + hud_fontsize.x;
}
}
int i = 0;
vector h_pos = item_pos;
vector h_size = vec2(panel_size.x, hud_fontsize.y * 1.25);
+ vector sz;
bool complete = (this_team == NUM_SPECTATOR);
continue;
if(pl == ignored_pl)
continue;
+
+ string flag_name = "";
+ vector flag_size = '0 0 0';
+ Scoreboard_GetField(pl, SP_COUNTRY);
+
+ if(sbt_field_icon3 != "") {
+ sz = draw_getimagesize(sbt_field_icon3);
+ flag_name = sbt_field_icon3;
+ flag_size = vec2(hud_fontsize.x * (sz.x / sz.y), hud_fontsize.y);
+ }
field = "";
if(this_team == NUM_SPECTATOR)
return vec2(item_pos.x, item_pos.y + i * hud_fontsize.y * 1.25);
}
+vector Scoreboard_Duel_DrawPickup(vector pos, bool skinned, string icon, vector sz, float number, bool invert)
+{
+ vector tmp_in = pos;
+ vector tmp_sz, tmp_sz2;
+ string picpath;
+
+ // Icon
+ if(skinned) {
+ picpath = strcat(hud_skin_path, "/", icon);
+ if(precache_pic(picpath) == "")
+ picpath = strcat("gfx/hud/default/", icon);
+ } else {
+ picpath = icon;
+ }
+
+ tmp_sz = draw_getimagesize(picpath);
+ tmp_sz2 = vec2(sz.y*(tmp_sz.x/tmp_sz.y), sz.y);
+
+ tmp_in.x = pos.x + ((sz.x - tmp_sz2.x) / 2);
+ drawpic(tmp_in, picpath, tmp_sz2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ // Number
+ if(invert)
+ tmp_in.x += tmp_sz2.x + hud_fontsize.x * 0.25;
+ else
+ tmp_in.x -= hud_fontsize.x * 0.25 + hud_fontsize.x;
+
+ tmp_in.y += (tmp_sz2.y - hud_fontsize.y) / 2;
+ drawstring(tmp_in,
+ ((number == -1) ? "?" : ftos(number)),
+ hud_fontsize, ((number > 0) ? '1 1 1' : '0.5 0.5 0.5'),
+ panel_fg_alpha,
+ DRAWFLAG_NORMAL);
+
+ pos.y += sz.y * 1.1;
+ return pos;
+}
+
+int left_pl_dmg = 50;
+int right_pl_dmg = 50;
+void Scoreboard_Duel_DrawTable(vector pos, bool invert, entity pl, entity tm)
+{
+ vector tmp, tmp_in, tmp_sz, tmp_acc;
+ string tmp_str;
+ float sz;
+ float average_acc = 0;
+
+ panel_pos = pos;
+
+ HUD_Panel_DrawBg();
+
+ // Stop here if there are no scores available
+ if(!pl) return;
+ if(entcs_GetSpecState(pl.sv_entnum) == ENTCS_SPEC_PURE) return;
+
+ tmp = pos;
+ tmp.x += panel_bg_padding;
+ tmp.y += panel_bg_padding;
+ panel_size.x -= panel_bg_padding * 2;
+
+ //if (sbt_bg_alpha)
+ // drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", tmp, panel_size, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
+
+ // Score: highlight
+ if(invert) { tmp.x += panel_size.x; tmp.x -= duel_score_size.x; }
+ drawfill(tmp, duel_score_size, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+
+ // Score: text
+ tmp_str = ftos(pl.(scores(SP_SCORE)));
+ tmp_in = tmp;
+ tmp_in.x += (duel_score_size.x / 2) - (stringwidth(tmp_str, true, duel_score_fontsize) / 2);
+ tmp_in.y += (duel_score_size.y / 2) - (duel_score_fontsize.y / 2);
+
+ draw_beginBoldFont();
+ drawstring(tmp_in, tmp_str, duel_score_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+
+ // Player name
+ tmp_str = Scoreboard_GetField(pl, SP_NAME);
+ tmp_in = tmp;
+ if(invert)
+ tmp_in.x -= stringwidth_colors(tmp_str, duel_name_fontsize) + duel_name_fontsize.x * 0.5;
+ else
+ tmp_in.x += duel_score_size.x + duel_name_fontsize.x * 0.5;
+ tmp_in.y += (duel_score_size.y - duel_name_fontsize.y) / 2;
+ drawcolorcodedstring(tmp_in, tmp_str, duel_name_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ //LegendGuard adds a conditional sentence for country column 05-04-2021
+ // Player country icon/flag
+ Scoreboard_GetField(pl, SP_COUNTRY);
+ if(sbt_field_icon3 != "") {
+ vector rsz = draw_getimagesize(sbt_field_icon3);
+ sbt_fixcolumnwidth_iconlen = rsz.x / rsz.y;
+ if(invert)
+ tmp_in.x -= hud_fontsize.x * sbt_fixcolumnwidth_iconlen + duel_name_fontsize.x * 0.5;
+ else
+ tmp_in.x += stringwidth_colors(tmp_str, duel_name_fontsize) + duel_name_fontsize.x * 0.5;
+ tmp_in.y += (duel_name_fontsize.y - hud_fontsize.y) / 2;
+ drawpic(tmp_in, sbt_field_icon3, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ // Header
+ float column_width = panel_size.x / 5;
+ tmp.x = pos.x + panel_bg_padding;
+ tmp.y += hud_fontsize.y * 3 + hud_fontsize.y;
+
+ vector column_dim;
+ int i;
+
+ i = (invert ? 4 : 0);
+ column_dim = vec2(column_width * 4, hud_fontsize.y);
+
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("kills", false, hud_fontsize) / 2),
+ "kills", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("dmg", false, hud_fontsize) / 2),
+ "dmg", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("acc", false, hud_fontsize) / 2),
+ "acc", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("hits", false, hud_fontsize) / 2),
+ "hits", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("ping", false, hud_fontsize) / 2),
+ "ping", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ tmp.x = pos.x + panel_bg_padding;
+ tmp.y += hud_fontsize.y;
+
+ // Main row
+ i = (invert ? 4 : 0);
+
+ tmp_str = ftos(pl.(scores(SP_KILLS)));
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+ tmp_str, hud_fontsize * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ tmp_str = ftos(pl.(scores(SP_DMG)));
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+ tmp_str, hud_fontsize * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ tmp_acc = tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2);
+
+ if(invert)
+ i--;
+ else
+ i++;
+
+ tmp_str = Scoreboard_GetField(pl, SP_PING);
+ drawstring(tmp + eX * column_width * i + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+ tmp_str, hud_fontsize * 1.25, sbt_field_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ tmp_str = Scoreboard_GetField(pl, SP_PL);
+ drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 0.75) / 2) + eY * (hud_fontsize.y * 1.25),
+ tmp_str, hud_fontsize * 0.75, sbt_field_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ tmp.x = pos.x + panel_bg_padding;
+ tmp.y += hud_fontsize.y * 2;
+
+ tmp_in = tmp;
+
+ int total_weapons = 0;
+
+ // Accuracy rows
+ int dmg_percent;
+ vector dmg_color;
+
+ WepSet weapons_inmap = WepSet_GetFromStat_InMap();
+ FOREACH(Weapons, it != WEP_Null, {
+ WepSet set = it.m_wepset;
+ if (!(weapons_inmap & set) && it != WEP_BLASTER && it != WEP_SHOTGUN) // z411 TODO : We'll be hardcoding this for now.
+ continue;
+ if (it.spawnflags & WEP_TYPE_OTHER)
+ continue;
+
+ int weapon_cnt_fired = pl.accuracy_cnt_fired[i - WEP_FIRST];
+ int weapon_cnt_hit = pl.accuracy_cnt_hit[i - WEP_FIRST];
+ int weapon_acc = 0;
+ if(weapon_cnt_fired)
+ weapon_acc = floor((weapon_cnt_hit / weapon_cnt_fired) * 100);
+ average_acc += weapon_acc;
+
+ // draw row background
+ drawfill(tmp_in + eX * column_width * (invert ? 1 : 0), column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+
+ if(weapon_cnt_fired) {
+ if(invert) {
+ if(pl.accuracy_hit[i - WEP_FIRST] > left_pl_dmg)
+ left_pl_dmg = pl.accuracy_hit[i - WEP_FIRST];
+ dmg_percent = pl.accuracy_hit[i - WEP_FIRST] / left_pl_dmg;
+ } else {
+ if(pl.accuracy_hit[i - WEP_FIRST] > right_pl_dmg)
+ right_pl_dmg = pl.accuracy_hit[i - WEP_FIRST];
+ dmg_percent = pl.accuracy_hit[i - WEP_FIRST] / right_pl_dmg;
+ }
+
+ // convert percentage range to 0.4 - 1
+ dmg_percent = dmg_percent * (1 - 0.4) + 0.4;
+
+ dmg_color.x = dmg_percent;
+ dmg_color.y = dmg_percent;
+ dmg_color.z = dmg_percent;
+
+ string draw_str;
+
+ // weapon stats
+ int c = (invert ? 4 : 0);
+
+ draw_str = ftos(pl.accuracy_frags[i - WEP_FIRST]);
+ drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
+ draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ draw_str = ftos(pl.accuracy_hit[i - WEP_FIRST]);
+ drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
+ draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ draw_str = sprintf("%d%%", weapon_acc);
+ drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
+ draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ draw_str = strcat(ftos(weapon_cnt_hit), " / ", ftos(weapon_cnt_fired));
+ drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * (column_width / 2) - eX * stringwidth(ftos(weapon_cnt_hit), false, hud_fontsize) - eX * hud_fontsize.x * 0.5,
+ draw_str, hud_fontsize, dmg_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ total_weapons++;
+ }
+
+ // weapon icon
+ if(invert) {
+ tmp_in.x = pos.x + panel_size.x - panel_bg_padding - hud_fontsize.x / 2;
+ drawpic_aspect_skin(tmp_in, it.model2, vec2(50, hud_fontsize.y * 1.15), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ tmp_in.x = pos.x + panel_bg_padding;
+ tmp_in.y += hud_fontsize.y * 1.25;
+ });
+ if(total_weapons)
+ average_acc = floor((average_acc / total_weapons) + 0.5);
+
+ // draw total accuracy now
+ tmp_str = sprintf("%d%%", average_acc);
+ drawstring(tmp_acc - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
+ tmp_str, hud_fontsize * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ // Icon column
+ vector icon_sz = vec2(column_width, hud_fontsize.y*1.5);
+
+ if(!invert)
+ tmp.x += column_width * 4;
+
+ // Item rows
+ drawstring(tmp + eX * ((column_width - stringwidth("items", false, hud_fontsize)) / 2),
+ "items", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ tmp.y += hud_fontsize.y * 1.25;
+
+ float inv_num = -1;
+ FOREACH(Items,
+ it.m_id == ITEM_ArmorMega.m_id ||
+ it.m_id == ITEM_HealthMega.m_id ||
+ it.m_id == ITEM_ArmorBig.m_id, {
+ // If the match isn't over, Only show pickups if we're spectating or they're our own
+ /*if(intermission || warmup_stage || spectatee_status || pl.sv_entnum == current_player)
+ inv_num = inventoryslots[pl.sv_entnum].inv_items[it.m_id];*/
+ tmp = Scoreboard_Duel_DrawPickup(tmp, true, it.m_icon, icon_sz, inv_num, invert);
+
+ if(it.m_id == REGISTRY_MAX(Items))
+ break;
+ });
+}
+
+vector Scoreboard_MakeDuelTable(vector pos, entity tm, vector rgb, vector bg_size)
+{
+ vector end_pos = pos;
+ float screen_half = panel_size.x / 2;
+ float weapon_margin = hud_fontsize.x;
+
+ panel_size.x = screen_half - weapon_margin;
+ panel_size.y = (duel_score_size.y * 5.5);
+
+ entity pl_left = players.sort_next;
+ entity pl_right = pl_left.sort_next;
+
+ Scoreboard_Duel_DrawTable(pos, true, pl_left, tm);
+ Scoreboard_Duel_DrawTable(pos + eX * screen_half + eX * weapon_margin, false, pl_right, tm);
+
+ end_pos.y += panel_size.y + (panel_bg_padding * 2);
+ panel_size.x = screen_half * 2;
+ return end_pos;
+}
+
vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
{
int max_players = 999;
return pos;
}
-vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) {
+/*vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) {
float stat_secrets_found, stat_secrets_total;
float stat_monsters_killed, stat_monsters_total;
float rows = 0;
panel_size.x += panel_bg_padding * 2; // restore initial width
return end_pos;
-}
+}*/
vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector rgb, vector bg_size)
return true;
}
+.bool uninteresting;
+STATIC_INIT(default_order_items_label)
+{
+ IL_EACH(default_order_items, true, {
+ if(!(it.instanceOfPowerup
+ || it == ITEM_HealthMega || it == ITEM_HealthBig
+ || it == ITEM_ArmorMega || it == ITEM_ArmorBig
+ ))
+ {
+ it.uninteresting = true;
+ }
+ });
+}
+
bool have_item_stats;
bool Scoreboard_ItemStats_WouldDraw(float ypos)
{
if (!have_item_stats)
{
IL_EACH(default_order_items, true, {
- if (!is_item_filtered(it))
+ if (!(autocvar_hud_panel_scoreboard_itemstats_filter && it.uninteresting))
{
int q = g_inventory.inv_items[it.m_id];
//q = 1; // debug: display all items
sb_gameinfo_type_fontsize = hud_fontsize * 2.5;
sb_gameinfo_detail_fontsize = hud_fontsize * 1.3;
+ // z411 server name
+ //drawcolorcodedstring(pos, "xonotic.org", sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ //drawpic_aspect(pos + '1 0 0' * (panel_size.x - 150), "gfx/logo", vec2(150, sb_gameinfo_type_fontsize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ //pos.y += sb_gameinfo_type_fontsize.y;
+
// Game Info: Game Type
str = MapInfo_Type_ToText(gametype);
+
draw_beginBoldFont();
- drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_type_fontsize)), str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ //drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_type_fontsize)), str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawcolorcodedstring(pos, str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
draw_endBoldFont();
+
+ vector tmp_old_sz = draw_getimagesize("gfx/logo");
+ float tmp_aspect = tmp_old_sz.x/tmp_old_sz.y;
+ vector tmp_new_sz = vec2(sb_gameinfo_type_fontsize.y * tmp_aspect, sb_gameinfo_type_fontsize.y);
+
+ drawpic(pos + '1 0 0' * (panel_size.x - tmp_new_sz.x), "gfx/logo", tmp_new_sz, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ pos.y += sb_gameinfo_type_fontsize.y;
// Game Info: Game Detail
float tl = STAT(TIMELIMIT);
if(!tm.team)
continue;
- draw_beginBoldFont();
vector rgb = Team_ColorRGB(tm.team);
+ /*draw_beginBoldFont();
str = ftos(tm.(teamscores(ts_primary)));
if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
{
// team score on the left (default)
- str_pos = pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 1.5);
+ str_pos = pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 3);
}
else
{
// team score on the right
- str_pos = pos + team_score_baseoffset + eX * (panel_size.x + hud_fontsize.x * 1.5);
+ str_pos = pos + team_score_baseoffset + eX * (panel_size.x + hud_fontsize.x * 3);
}
- drawstring(str_pos, str, hud_fontsize * 1.5, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring(str_pos, str, hud_fontsize * 3, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
// team size (if set to show on the side)
if (autocvar_hud_panel_scoreboard_team_size_position != 0) // team size not off
drawstring(str_pos, str, hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
}
draw_endBoldFont();
+ */
+
+ // z411 My team header
+ // Score: highlight
+ drawfill(pos, team_score_size, rgb * 0.5, sbt_highlight_alpha, DRAWFLAG_NORMAL);
+
+ // Score: text
+ str = ftos(tm.(teamscores(ts_primary)));
+ str_pos = pos;
+ str_pos.x += (team_score_size.x / 2) - (stringwidth(str, true, team_score_fontsize) / 2);
+ str_pos.y += (team_score_size.y / 2) - (team_score_fontsize.y / 2);
+
+ draw_beginBoldFont();
+ drawstring(str_pos, str, team_score_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
+ draw_endBoldFont();
+
+ // Team name
+ str = Team_CustomName(tm.team);
+ str_pos = pos;
+ str_pos.x += team_score_size.x + team_name_fontsize.x * 0.5;
+ str_pos.y += (team_score_size.y / 2) - (team_name_fontsize.y / 2);
+ drawcolorcodedstring(str_pos, str, team_name_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ pos.y += team_score_size.y + (hud_fontsize.y * 0.5);
+
if(autocvar_hud_panel_scoreboard_bg_teams_color_team > 0)
panel_bg_color = rgb * autocvar_hud_panel_scoreboard_bg_teams_color_team;
else if(panel_bg_color_team > 0)
}
panel_bg_color = panel_bg_color_save;
}
+ else if(gametype == MAPINFO_TYPE_DUEL)
+ {
+ for(tm = teams.sort_next; tm; tm = tm.sort_next)
+ if(tm.team != NUM_SPECTATOR)
+ break;
+
+ // z411 make DUEL TABLE
+ pos = Scoreboard_MakeDuelTable(pos, tm, panel_bg_color, bg_size);
+ }
else
{
for(tm = teams.sort_next; tm; tm = tm.sort_next)
pos = Scoreboard_Spectators_Draw(pos, tm, str, hud_fontsize);
}
- pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
+ //pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
// draw scoreboard spectators after mapstats
if (autocvar_hud_panel_scoreboard_spectators_position == 3) {
-#pragma once
-
-#include "all.qh"
-
-#ifdef GAMEQC
-CLASS(Inventory, Object)
- /** Stores counts of items, the id being the index */
- ATTRIBARRAY(Inventory, inv_items, int, REGISTRY_MAX(Items));
-ENDCLASS(Inventory)
-
-/** Player inventory */
-.Inventory inventory;
-/** Player inventory storage (holds previous state) */
-.Inventory inventory_store;
-
-REGISTER_NET_LINKED(ENT_CLIENT_INVENTORY)
-
-const int Inventory_groups_minor = 8; // must be a multiple of 8 (one byte) to optimize bandwidth usage
-const int Inventory_groups_major = 4; // must be >= ceil(REGISTRY_COUNT(Items) / Inventory_groups_minor)
-#endif
-
-// no need to perform these checks on both server and client
-#ifdef CSQC
-STATIC_INIT(Inventory)
-{
- if (Inventory_groups_minor / 8 != floor(Inventory_groups_minor / 8))
- error("Inventory_groups_minor is not a multiple of 8.");
- int min_major_value = ceil(REGISTRY_COUNT(Items) / Inventory_groups_minor);
- if (Inventory_groups_major < min_major_value)
- error(sprintf("Inventory_groups_major can not be < %d.", min_major_value));
-}
-#endif
-
-#ifdef SVQC
-#define G_MAJOR(id) (floor((id) / Inventory_groups_minor))
-#define G_MINOR(id) ((id) % Inventory_groups_minor)
-#endif
-
-#ifdef CSQC
-Inventory g_inventory;
-void Inventory_remove(entity this)
-{
- if(g_inventory == this)
- g_inventory = NULL;
-}
-
-NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
-{
- make_pure(this);
- g_inventory = this;
- this.entremove = Inventory_remove;
- const int majorBits = Readbits(Inventory_groups_major);
- for (int i = 0; i < Inventory_groups_major; ++i) {
- if (!(majorBits & BIT(i))) {
- continue;
- }
- const int minorBits = Readbits(Inventory_groups_minor);
- for (int j = 0; j < Inventory_groups_minor; ++j) {
- if (!(minorBits & BIT(j))) {
- continue;
- }
- const GameItem it = REGISTRY_GET(Items, Inventory_groups_minor * i + j);
- .int fld = inv_items[it.m_id];
- int prev = this.(fld);
- int next = this.(fld) = ReadByte();
- LOG_DEBUGF("%s: %.0f -> %.0f", it.m_name, prev, next);
- }
- }
- return true;
-}
-#endif
-
-#ifdef SVQC
-int minorBitsArr[Inventory_groups_major];
-void Inventory_Write(Inventory data, Inventory store)
-{
- if (!data) {
- WriteShort(MSG_ENTITY, 0);
- return;
- }
- TC(Inventory, data);
-
- for (int i = 0; i < Inventory_groups_major; ++i)
- minorBitsArr[i] = 0;
-
- int majorBits = 0;
- FOREACH(Items, true, {
- .int fld = inv_items[it.m_id];
- const bool changed = store.(fld) != data.(fld);
- store.(fld) = data.(fld);
- if (changed) {
- int maj = G_MAJOR(it.m_id);
- majorBits = BITSET(majorBits, BIT(maj), true);
- minorBitsArr[maj] = BITSET(minorBitsArr[maj], BIT(G_MINOR(it.m_id)), true);
- }
- });
-
- Writebits(MSG_ENTITY, majorBits, Inventory_groups_major);
- for (int i = 0; i < Inventory_groups_major; ++i)
- {
- if (!(majorBits & BIT(i)))
- continue;
-
- const int minorBits = minorBitsArr[i];
- Writebits(MSG_ENTITY, minorBits, Inventory_groups_minor);
- for (int j = 0; j < Inventory_groups_minor; ++j)
- {
- if (!(minorBits & BIT(j)))
- continue;
-
- const entity it = REGISTRY_GET(Items, Inventory_groups_minor * i + j);
- WriteByte(MSG_ENTITY, data.inv_items[it.m_id]);
- }
- }
-}
-#endif
-
-#undef G_MAJOR
-#undef G_MINOR
-
-#ifdef SVQC
-bool Inventory_Send(Inventory this, Client to, int sf)
-{
- TC(Inventory, this);
- WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY);
- TC(PlayerState, this.owner);
- Inventory_Write(this, to.inventory_store);
- return true;
-}
-
-bool Inventory_customize(entity this, entity client)
-{
- // sends to spectators too!
- return (PS(client) && PS(client).inventory == this);
-}
-
-void Inventory_new(PlayerState this)
-{
- Inventory inv = NEW(Inventory);
- setcefc(inv, Inventory_customize);
- this.inventory = inv;
- inv.owner = this;
- Net_LinkEntity(inv, false, 0, Inventory_Send);
-}
-void Inventory_delete(entity e) { delete(e.inventory); }
-void Inventory_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; }
-
-void Inventory_clear(entity store)
-{
- // NOTE: you will need to perform Inventory_update after this to update the storage entity
- // (unless store is the storage entity)
- FOREACH(Items, true, {
- .int fld = inv_items[it.m_id];
- store.(fld) = 0;
- });
-}
-
-void InventoryStorage_attach(entity e) { e.inventory_store = NEW(Inventory); e.inventory_store.drawonlytoclient = e; }
-void InventoryStorage_delete(entity e) { delete(e.inventory_store); }
-#endif
+ #pragma once
+
+ #include "all.qh"
+
+ #ifdef GAMEQC
+ CLASS(Inventory, Object)
+ ATTRIBARRAY(Inventory, inv_items, int, REGISTRY_MAX(Items));
+ ENDCLASS(Inventory)
+
+
+ .Inventory inventory;
+ .Inventory inventory_store;
+
+ REGISTER_NET_LINKED(ENT_CLIENT_INVENTORY)
+
+ const int Inventory_groups_minor = 8; // must be a multiple of 8 (one byte) to optimize bandwidth usage
+ const int Inventory_groups_major = 4; // must be >= ceil(REGISTRY_COUNT(Items) / Inventory_groups_minor)
+ #endif
+
+ // no need to perform these checks on both server and client
+ #ifdef CSQC
+ STATIC_INIT(Inventory)
+ {
+ if (Inventory_groups_minor / 8 != floor(Inventory_groups_minor / 8))
+ error("Inventory_groups_minor is not a multiple of 8.");
+ int min_major_value = ceil(REGISTRY_COUNT(Items) / Inventory_groups_minor);
+ if (Inventory_groups_major < min_major_value)
+ error(sprintf("Inventory_groups_major can not be < %d.", min_major_value));
+ }
+ #endif
+
+ #ifdef SVQC
+ #define G_MAJOR(id) (floor((id) / Inventory_groups_minor))
+ #define G_MINOR(id) ((id) % Inventory_groups_minor)
+ #endif
+
+ #ifdef CSQC
+ Inventory g_inventory;
+ void Inventory_remove(entity this)
+ {
+ if(g_inventory == this)
+ g_inventory = NULL;
+ }
+
+ NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
+ {
+ make_pure(this);
+ g_inventory = this;
+ this.entremove = Inventory_remove;
+ const int majorBits = Readbits(Inventory_groups_major);
+ for (int i = 0; i < Inventory_groups_major; ++i) {
+ if (!(majorBits & BIT(i))) {
+ continue;
+ }
+ const int minorBits = Readbits(Inventory_groups_minor);
+ for (int j = 0; j < Inventory_groups_minor; ++j) {
+ if (!(minorBits & BIT(j))) {
+ continue;
+ }
+ const GameItem it = REGISTRY_GET(Items, Inventory_groups_minor * i + j);
+ .int fld = inv_items[it.m_id];
+ int prev = this.(fld);
+ int next = this.(fld) = ReadByte();
+ LOG_DEBUGF("%s: %.0f -> %.0f", it.m_name, prev, next);
+ }
+ }
+ return true;
+ }
+ #endif
+
+ #ifdef SVQC
+ int minorBitsArr[Inventory_groups_major];
+ void Inventory_Write(Inventory data, Inventory store)
+ {
+ if (!data) {
+ WriteShort(MSG_ENTITY, 0);
+ return;
+ }
+ TC(Inventory, data);
+
+ for (int i = 0; i < Inventory_groups_major; ++i)
+ minorBitsArr[i] = 0;
+
+ int majorBits = 0;
+ FOREACH(Items, true, {
+ .int fld = inv_items[it.m_id];
+ const bool changed = store.(fld) != data.(fld);
+ store.(fld) = data.(fld);
+ if (changed) {
+ int maj = G_MAJOR(it.m_id);
+ majorBits = BITSET(majorBits, BIT(maj), true);
+ minorBitsArr[maj] = BITSET(minorBitsArr[maj], BIT(G_MINOR(it.m_id)), true);
+ }
+ });
+
+ Writebits(MSG_ENTITY, majorBits, Inventory_groups_major);
+ for (int i = 0; i < Inventory_groups_major; ++i)
+ {
+ if (!(majorBits & BIT(i)))
+ continue;
+
+ const int minorBits = minorBitsArr[i];
+ Writebits(MSG_ENTITY, minorBits, Inventory_groups_minor);
+ for (int j = 0; j < Inventory_groups_minor; ++j)
+ {
+ if (!(minorBits & BIT(j)))
+ continue;
+
+ const entity it = REGISTRY_GET(Items, Inventory_groups_minor * i + j);
+ WriteByte(MSG_ENTITY, data.inv_items[it.m_id]);
+ }
+ }
+ }
+ #endif
+
+ #undef G_MAJOR
+ #undef G_MINOR
+
+ #ifdef SVQC
+ bool Inventory_Send(Inventory this, Client to, int sf)
+ {
+ TC(Inventory, this);
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY);
+ TC(PlayerState, this.owner);
+ Inventory_Write(this, to.inventory_store);
+ return true;
+ }
+
+ bool Inventory_customize(entity this, entity client)
+ {
+ // sends to spectators too!
+ return (PS(client) && PS(client).inventory == this);
+ }
+
+ void Inventory_new(PlayerState this)
+ {
+ Inventory inv = NEW(Inventory);
+ setcefc(inv, Inventory_customize);
+ this.inventory = inv;
+ inv.owner = this;
+ Net_LinkEntity(inv, false, 0, Inventory_Send);
+ }
+ void Inventory_delete(entity e) { delete(e.inventory); }
+ void Inventory_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; }
+
+ void Inventory_clear(entity store)
+ {
+ // NOTE: you will need to perform Inventory_update after this to update the storage entity
+ // (unless store is the storage entity)
+ FOREACH(Items, true, {
+ .int fld = inv_items[it.m_id];
+ store.(fld) = 0;
+ });
+ }
+
+ void InventoryStorage_attach(entity e) { e.inventory_store = NEW(Inventory); e.inventory_store.drawonlytoclient = e; }
+ void InventoryStorage_delete(entity e) { delete(e.inventory_store); }
+ #endif
\ No newline at end of file