viewmodel = new(viewmodel);
}
-entity porto;
-vector polyline[16];
-void Porto_Draw(entity this)
+void Porto_Draw(entity this);
+STATIC_INIT(Porto)
{
- vector p, dir, ang, q, nextdir;
- float portal_number, portal1_idx;
-
- if(activeweapon != WEP_PORTO || spectatee_status || gametype == MAPINFO_TYPE_NEXBALL)
- return;
- if(WEP_CVAR(porto, secondary))
- return;
- if(intermission == 1)
- return;
- if(intermission == 2)
- return;
- if (STAT(HEALTH) <= 0)
- return;
+ entity e = new_pure(porto);
+ e.draw = Porto_Draw;
+ e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
+}
- dir = view_forward;
+const int polyline_length = 16;
+vector polyline[polyline_length];
+void Porto_Draw(entity this)
+{
+ if (activeweapon != WEP_PORTO) return;
+ if (spectatee_status) return;
+ if (WEP_CVAR(porto, secondary)) return;
+ if (intermission == 1) return;
+ if (intermission == 2) return;
+ if (STAT(HEALTH) <= 0) return;
- if(angles_held_status)
+ vector pos = view_origin;
+ vector dir = view_forward;
+ if (angles_held_status)
{
makevectors(angles_held);
dir = v_forward;
}
- p = view_origin;
-
- polyline[0] = p;
- int idx = 1;
- portal_number = 0;
- nextdir = dir;
+ polyline[0] = pos;
- for (;;)
+ int portal_number = 0, portal1_idx = 1, portal_max = 2;
+ int n = 1 + 2; // 2 lines == 3 points
+ for (int idx = 0; idx < n && idx < polyline_length - 1; )
{
- dir = nextdir;
- traceline(p, p + 65536 * dir, true, porto);
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
- return;
- nextdir = dir - 2 * (dir * trace_plane_normal) * trace_plane_normal; // mirror dir at trace_plane_normal
- p = trace_endpos;
- polyline[idx] = p;
- ++idx;
- if(idx >= 16)
- return;
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
- continue;
- ++portal_number;
- ang = vectoangles2(trace_plane_normal, dir);
- ang.x = -ang.x;
- makevectors(ang);
- if(!CheckWireframeBox(porto, p - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
- return;
- if(portal_number == 1)
+ traceline(pos, pos + 65536 * dir, true, this);
+ dir = reflect(dir, trace_plane_normal);
+ pos = trace_endpos;
+ polyline[++idx] = pos;
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
{
- portal1_idx = idx;
- if(portal_number >= 2)
- break;
+ n += 1;
+ continue;
}
- }
-
- while(idx >= 2)
- {
- p = polyline[idx-2];
- q = polyline[idx-1];
- if(idx == 2)
- p = p - view_up * 16;
- if(idx-1 >= portal1_idx)
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
{
- Draw_CylindricLine(p, q, 4, "", 1, 0, '0 0 1', 0.5, DRAWFLAG_NORMAL, view_origin);
+ n = max(2, idx);
+ break;
}
- else
+ // check size
{
- Draw_CylindricLine(p, q, 4, "", 1, 0, '1 0 0', 0.5, DRAWFLAG_NORMAL, view_origin);
+ vector ang = vectoangles2(trace_plane_normal, dir);
+ ang.x = -ang.x;
+ makevectors(ang);
+ if (!CheckWireframeBox(this, pos - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
+ {
+ n = max(2, idx);
+ break;
+ }
}
- --idx;
+ portal_number += 1;
+ if (portal_number >= portal_max) break;
+ if (portal_number == 1) portal1_idx = idx;
+ }
+ for (int idx = 0; idx < n - 1; ++idx)
+ {
+ vector p = polyline[idx], q = polyline[idx + 1];
+ if (idx == 0) p -= view_up * 16; // line from player
+ vector rgb = (idx < portal1_idx) ? '1 0 0' : '0 0 1';
+ Draw_CylindricLine(p, q, 4, "", 1, 0, rgb, 0.5, DRAWFLAG_NORMAL, view_origin);
}
-}
-
-void Porto_Init()
-{
- porto = new_pure(porto);
- porto.draw = Porto_Draw;
- porto.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
}
float drawtime;
} MACRO_END
noref vector _vec2;
-#define vec2(v) (_vec2 = (v), _vec2.z = 0, _vec2)
+#define vec2(...) EVAL(OVERLOAD(vec2, __VA_ARGS__))
+#define vec2_1(v) (_vec2 = (v), _vec2.z = 0, _vec2)
+#define vec2_2(x, y) (_vec2_x = (x), _vec2_y = (y), _vec2)
noref vector _vec3;
#define vec3(_x, _y, _z) (_vec3.x = (_x), _vec3.y = (_y), _vec3.z = (_z), _vec3)
noref vector _yinvert;
#define yinvert(v) (_yinvert = (v), _yinvert.y = 1 - _yinvert.y, _yinvert)
+/**
+ * @param dir the directional vector
+ * @param norm the normalized normal
+ * @returns dir reflected by norm
+ */
+vector reflect(vector dir, vector norm)
+{
+ return dir - 2 * (dir * norm) * norm;
+}
+
#ifndef MENUQC
vector get_corner_position(entity box, int corner)
{