#include "waypointsprites.qh"
-#ifdef IMPLEMENTATION
-
REGISTER_MUTATOR(waypointsprites, true);
REGISTER_NET_LINKED(waypointsprites)
sendflags |= 0x80;
int f = 0;
- if(this.currentammo)
+ if(this.currentammo == 1)
f |= 1; // hideable
if(this.exteriormodeltoclient == to)
f |= 2; // my own
+ if(this.currentammo == 2)
+ f |= 2; // radar only
MUTATOR_CALLHOOK(SendWaypoint, this, to, sendflags, f);
sendflags = M_ARGV(2, int);
{
if (this.max_health)
{
- WriteByte(MSG_ENTITY, (this.health / this.max_health) * 191.0);
+ WriteByte(MSG_ENTITY, (GetResource(this, RES_HEALTH) / this.max_health) * 191.0);
}
else
{
if (sendflags & 64)
{
- WriteCoord(MSG_ENTITY, this.origin.x);
- WriteCoord(MSG_ENTITY, this.origin.y);
- WriteCoord(MSG_ENTITY, this.origin.z);
+ WriteVector(MSG_ENTITY, this.origin);
}
if (sendflags & 1)
if (WaypointSprite_isteammate(this.owner, WaypointSprite_getviewentity(to)))
{
- float dt = (this.waypointsprite_helpmetime - time) / 0.1;
- if (dt < 0)
- dt = 0;
- if (dt > 255)
- dt = 255;
+ float dt = bound(0, (this.waypointsprite_helpmetime - time) / 0.1, 255);
WriteByte(MSG_ENTITY, dt);
}
else
void Ent_RemoveWaypointSprite(entity this)
{
- if (this.netname) strunzone(this.netname);
- if (this.netname2) strunzone(this.netname2);
- if (this.netname3) strunzone(this.netname3);
+ strfree(this.netname);
+ strfree(this.netname2);
+ strfree(this.netname3);
}
/** flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] */
int t = ReadByte();
if (t < 192)
{
- this.health = t / 191.0;
+ SetResourceExplicit(this, RES_HEALTH, t / 191.0);
this.build_finished = 0;
}
else
t = (t - 192) * 256 + ReadByte();
this.build_started = servertime;
if (this.build_finished)
- this.build_starthealth = bound(0, this.health, 1);
+ this.build_starthealth = bound(0, GetResource(this, RES_HEALTH), 1);
else
this.build_starthealth = 0;
this.build_finished = servertime + t / 32;
}
else
{
- this.health = -1;
+ SetResourceExplicit(this, RES_HEALTH, -1);
this.build_finished = 0;
}
if (sendflags & 64)
{
// unfortunately, this needs to be exact (for the 3D display)
- this.origin_x = ReadCoord();
- this.origin_y = ReadCoord();
- this.origin_z = ReadCoord();
+ this.origin = ReadVector();
setorigin(this, this.origin);
}
if (sendflags & 2)
{
- if (this.netname)
- strunzone(this.netname);
- this.netname = strzone(ReadString());
+ strcpy(this.netname, ReadString());
}
if (sendflags & 4)
{
- if (this.netname2)
- strunzone(this.netname2);
- this.netname2 = strzone(ReadString());
+ strcpy(this.netname2, ReadString());
}
if (sendflags & 8)
{
- if (this.netname3)
- strunzone(this.netname3);
- this.netname3 = strzone(ReadString());
+ strcpy(this.netname3, ReadString());
}
if (sendflags & 16)
string spritelookuptext(entity this, string s)
{
+ if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
+ return "Spam"; // no need to translate this debug string
if (s == WP_RaceStartFinish.netname) return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
if (s == WP_Weapon.netname) return Weapons_from(this.wp_extra).m_name;
if (s == WP_Item.netname) return Items_from(this.wp_extra).m_waypoint;
}
// need to loop, as our netname could be one of three
- FOREACH(Waypoints, it.netname == s, LAMBDA(
+ FOREACH(Waypoints, it.netname == s, {
return it.m_name;
- ));
+ });
+
+ return s;
+}
+
+string spritelookupicon(entity this, string s)
+{
+ // TODO: needs icons! //if (s == WP_RaceStartFinish.netname) return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
+ if (s == WP_Weapon.netname) return Weapons_from(this.wp_extra).model2;
+ if (s == WP_Item.netname) return Items_from(this.wp_extra).m_icon;
+ if (s == WP_Vehicle.netname) return Vehicles_from(this.wp_extra).m_icon;
+ //if (s == WP_Monster.netname) return get_monsterinfo(this.wp_extra).m_icon;
+ if (MUTATOR_CALLHOOK(WP_Format, this, s))
+ {
+ return M_ARGV(4, string);
+ }
+
+ // need to loop, as our netname could be one of three
+ FOREACH(Waypoints, it.netname == s, {
+ return it.m_icon;
+ });
return s;
}
// rotate them, and make them absolute
rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
- v1 = rotate(v1, rot) + org;
- v2 = rotate(v2, rot) + org;
- v3 = rotate(v3, rot) + org;
- v4 = rotate(v4, rot) + org;
+ v1 = Rotate(v1, rot) + org;
+ v2 = Rotate(v2, rot) + org;
+ v3 = Rotate(v3, rot) + org;
+ v4 = Rotate(v4, rot) + org;
// draw them
R_BeginPolygon(pic, f);
up = '0 1 0';
rot = -rot; // rotate by the opposite angle, as our coordinate system is reversed
- o = rotate(o, rot) + org;
- ri = rotate(ri, rot);
- up = rotate(up, rot);
+ o = Rotate(o, rot) + org;
+ ri = Rotate(ri, rot);
+ up = Rotate(up, rot);
owidth = width + 2 * border;
o = o - up * (margin + border + theheight) + ri * (sz.x - owidth) * 0.5;
float border = 1.5 * t;
float margin = 4.0 * t;
- float borderDiag = border * 1.414;
+ float borderDiag = border * M_SQRT2;
vector arrowX = eX * size;
vector arrowY = eY * (size+borderDiag);
vector borderX = eX * (size+borderDiag);
R_BeginPolygon("", DRAWFLAG_NORMAL);
R_PolygonVertex(o, '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(arrowY - borderX, ang), '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(borderY - borderX, ang), '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(borderY + borderX, ang), '0 0 0', '0 0 0', a);
- R_PolygonVertex(o + rotate(arrowY + borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(arrowY - borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(borderY - borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(borderY + borderX, ang), '0 0 0', '0 0 0', a);
+ R_PolygonVertex(o + Rotate(arrowY + borderX, ang), '0 0 0', '0 0 0', a);
R_EndPolygon();
R_BeginPolygon("", DRAWFLAG_ADDITIVE);
- R_PolygonVertex(o + rotate(eY * borderDiag, ang), '0 0 0', rgb, a);
- R_PolygonVertex(o + rotate(arrowY - arrowX, ang), '0 0 0', rgb, a);
- R_PolygonVertex(o + rotate(arrowY + arrowX, ang), '0 0 0', rgb, a);
+ R_PolygonVertex(o + Rotate(eY * borderDiag, ang), '0 0 0', rgb, a);
+ R_PolygonVertex(o + Rotate(arrowY - arrowX, ang), '0 0 0', rgb, a);
+ R_PolygonVertex(o + Rotate(arrowY + arrowX, ang), '0 0 0', rgb, a);
R_EndPolygon();
- return o + rotate(eY * (borderDiag+size+margin), ang);
+ return o + Rotate(eY * (borderDiag+size+margin), ang);
}
// returns location of sprite healthbar
-vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a, vector fontsize, string s)
+vector drawsprite_TextOrIcon(bool is_text, vector o, float ang, float minwidth, vector rgb, float a, vector sz, string str)
{
float algnx, algny;
float sw, w, h;
float aspect, sa, ca;
- sw = stringwidth(s, false, fontsize);
+ if (is_text)
+ sw = stringwidth(str, false, sz);
+ else
+ sw = sz.x;
+
if (sw > minwidth)
w = sw;
else
w = minwidth;
- h = fontsize.y;
+ h = sz.y;
// how do corners work?
aspect = vid_conwidth / vid_conheight;
if (o.x > vid_conwidth - w)
o.x = vid_conwidth - w;
if (o.y > vid_conheight - h)
- o.x = vid_conheight - h;
+ o.y = vid_conheight - h;
o.x += 0.5 * (w - sw);
- drawstring(o, s, fontsize, rgb, a, DRAWFLAG_NORMAL);
+ if (is_text)
+ drawstring(o, str, sz, rgb, a, DRAWFLAG_NORMAL);
+ else
+ drawpic(o, str, sz, rgb, a, DRAWFLAG_NORMAL);
o.x += 0.5 * sw;
o.y += 0.5 * h;
void Draw_WaypointSprite(entity this)
{
if (this.lifetime > 0)
- this.alpha = pow(bound(0, (this.fadetime - time) / this.lifetime, 1), waypointsprite_timealphaexponent);
- else if (this.lifetime < 0)
- this.alpha = (time < this.fadetime) ? 1 : 0; // no fading out effect
+ this.alpha = (bound(0, (this.fadetime - time) / this.lifetime, 1) ** waypointsprite_timealphaexponent);
else
this.alpha = 1;
if (autocvar_cl_hidewaypoints >= 2)
return;
- if (this.hideflags & 1)
- if (autocvar_cl_hidewaypoints)
- return; // fixed waypoint
+ if (this.hideflags & 1 && autocvar_cl_hidewaypoints)
+ return; // fixed waypoint
InterpolateOrigin_Do(this);
float t = entcs_GetTeam(player_localnum) + 1;
-
string spriteimage = "";
// choose the sprite
++waypointsprite_newcount;
- float dist;
- dist = vlen(this.origin - view_origin);
-
- float a;
- a = this.alpha * autocvar_hud_panel_fg_alpha;
+ float dist = vlen(this.origin - view_origin);
+ float a = this.alpha * autocvar_hud_panel_fg_alpha;
if (this.maxdistance > waypointsprite_normdistance)
- a *= pow(bound(0, (this.maxdistance - dist) / (this.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
+ a *= (bound(0, (this.maxdistance - dist) / (this.maxdistance - waypointsprite_normdistance), 1) ** waypointsprite_distancealphaexponent);
else if (this.maxdistance > 0)
- a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
+ a *= (bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1) ** waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
vector rgb = spritelookupcolor(this, spriteimage, this.teamradar_color);
if (rgb == '0 0 0')
{
this.teamradar_color = '1 0 1';
- LOG_INFOF("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage);
+ LOG_INFOF("WARNING: sprite of name %s has no color, using pink so you notice it", spriteimage);
}
- if (time - floor(time) > 0.5)
+ float health_val = GetResource(this, RES_HEALTH);
+ float blink_time = (health_val >= 0) ? (health_val * 10) : time;
+ if (blink_time - floor(blink_time) > 0.5)
{
if (this.helpme && time < this.helpme)
a *= SPRITE_HELPME_BLINK;
- else if (this.lifetime > 0) // fading out waypoints don't blink
+ else if (!this.lifetime) // fading out waypoints don't blink
a *= spritelookupblinkvalue(this, spriteimage);
}
{
// scale it to be just in view
vector d;
- float f1, f2;
d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
ang = atan2(-d.x, -d.y);
if (o.z < 0)
ang += M_PI;
- f1 = d.x / vid_conwidth;
- f2 = d.y / vid_conheight;
+ float f1 = d.x / vid_conwidth;
+ float f2 = d.y / vid_conheight;
+ if (f1 == 0) { f1 = 0.000001; }
+ if (f2 == 0) { f2 = 0.000001; }
if (max(f1, -f1) > max(f2, -f2)) {
if (d.z * f1 > 0) {
(vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o.x,
(vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o.y);
- float vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
+ float crosshairdistance = sqrt( ((o.x - vid_conwidth/2) ** 2) + ((o.y - vid_conheight/2) ** 2) );
- float crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
-
- t = waypointsprite_scale * vidscale;
+ t = waypointsprite_scale;
a *= waypointsprite_alpha;
{
if (time < this.build_finished + 0.25)
{
if (time < this.build_started)
- this.health = this.build_starthealth;
+ SetResourceExplicit(this, RES_HEALTH, this.build_starthealth);
else if (time < this.build_finished)
- this.health = (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth;
+ SetResourceExplicit(this, RES_HEALTH, (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth);
else
- this.health = 1;
+ SetResourceExplicit(this, RES_HEALTH, 1);
}
else
- this.health = -1;
+ SetResourceExplicit(this, RES_HEALTH, -1);
}
o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
- string txt;
- if (autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
- txt = _("Spam");
- else
+ string pic = "";
+ bool is_text = true;
+ if (!autocvar_g_waypointsprite_text)
+ {
+ string spr_icon = spritelookupicon(this, spriteimage);
+ pic = spr_icon;
+ bool icon_found = !(!spr_icon || spr_icon == "");
+ if (icon_found) // it's valid, but let's make sure it exists!
+ {
+ pic = strcat(hud_skin_path, "/", spr_icon);
+ if(precache_pic(pic) == "")
+ {
+ pic = strcat("gfx/hud/default/", spr_icon);
+ if(!precache_pic(pic))
+ icon_found = false;
+ }
+ }
+ if (icon_found)
+ is_text = false;
+ }
+
+ vector sz;
+ vector txt_color;
+ string txt = string_null;
+ if (is_text)
+ {
txt = spritelookuptext(this, spriteimage);
- if (this.helpme && time < this.helpme)
- txt = sprintf(_("%s needing help!"), txt);
- if (autocvar_g_waypointsprite_uppercase)
- txt = strtoupper(txt);
+ if (this.helpme && time < this.helpme)
+ txt = sprintf(_("%s needing help!"), txt);
+ if (autocvar_g_waypointsprite_uppercase)
+ txt = strtoupper(txt);
+ txt_color = rgb;
+ sz = waypointsprite_fontsize * '1 1 0';
+ }
+ else
+ {
+ // for convenience icon path and color are saved to txt and txt_color
+ txt = pic;
+ txt_color = ((autocvar_g_waypointsprite_iconcolor) ? '1 1 1' : rgb);
+ sz = autocvar_g_waypointsprite_iconsize * '1 1 0';
+ }
draw_beginBoldFont();
- if (this.health >= 0)
+ if (GetResource(this, RES_HEALTH) >= 0)
{
- o = drawspritetext(o, ang, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
-
- float align, marg;
+ float align = 0, marg;
if (this.build_finished)
align = 0.5;
else
align = 0;
if (cos(ang) > 0)
- marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * waypointsprite_fontsize;
+ marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * sz.y;
else
- marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize;
+ marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * sz.y;
+
+ float minwidth = (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t;
+ o = drawsprite_TextOrIcon(is_text, o, ang, minwidth, txt_color, a, sz, txt);
drawhealthbar(
o,
0,
- this.health,
+ GetResource(this, RES_HEALTH),
'0 0 0',
'0 0 0',
SPRITE_HEALTHBAR_WIDTH * t,
}
else
{
- o = drawspritetext(o, ang, 0, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
+ drawsprite_TextOrIcon(is_text, o, ang, 0, txt_color, a, sz, txt);
}
+
draw_endBoldFont();
}
void WaypointSprite_UpdateHealth(entity e, float f)
{
f = bound(0, f, e.max_health);
- if (f != e.health || e.pain_finished)
+ float step = e.max_health / 40;
+ if ((floor(f / step) != floor(GetResource(e, RES_HEALTH) / step)) || e.pain_finished)
{
- e.health = f;
+ SetResourceExplicit(e, RES_HEALTH, f);
e.pain_finished = 0;
e.SendFlags |= 0x80;
}
// ensure:
// (e.teleport_time - time) / wp.fade_time stays
// e.teleport_time = time + fadetime
- float current_fadetime;
- current_fadetime = e.teleport_time - time;
+ float current_fadetime = e.teleport_time - time;
e.teleport_time = time + t;
if (e.fade_time < 0)
e.fade_time = -e.fade_time;
entity WaypointSprite_DeployFixed(
entity spr,
- float limited_range,
+ bool limited_range,
entity player,
vector ofs,
entity icon // initial icon
entity WaypointSprite_Attach(
entity spr,
entity player,
- float limited_range,
+ bool limited_range,
entity icon // initial icon
)
{
{
WaypointSprite_Kill(carrier.waypointsprite_attached); // FC overrides attached
entity e = WaypointSprite_Spawn(spr, 0, 0, carrier, '0 0 64', NULL, carrier.team, carrier, waypointsprite_attachedforcarrier, false, icon);
- if (carrier.health)
+ if (GetResource(carrier, RES_HEALTH))
{
- WaypointSprite_UpdateMaxHealth(e, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
- WaypointSprite_UpdateHealth(e, '1 0 0' * healtharmor_maxdamage(carrier.health, carrier.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+ WaypointSprite_UpdateMaxHealth(e, 2 * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id).x);
+ WaypointSprite_UpdateHealth(e, healtharmor_maxdamage(GetResource(carrier, RES_HEALTH), GetResource(carrier, RES_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id).x);
}
return e;
}
WaypointSprite_DetachCarrier(this);
}
#endif
-#endif