Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
porto.qc File Reference
Include dependency graph for porto.qc:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

 MUTATOR_HOOKFUNCTION (porto_ticker, SV_StartFrame)
void Porto_Draw (entity this)
 REGISTER_MUTATOR (porto_ticker, true)
 STATIC_INIT (Porto)
void W_Porto_Attack (Weapon thiswep, entity actor,.entity weaponentity, float type)
void W_Porto_Fail (entity this, bool failhard)
void W_Porto_Remove (entity p)
void W_Porto_Success (entity this)
void W_Porto_Think (entity this)
void W_Porto_Touch (entity this, entity toucher)

Variables

vector polyline [polyline_length]
const int polyline_length = 16

Function Documentation

◆ MUTATOR_HOOKFUNCTION()

MUTATOR_HOOKFUNCTION ( porto_ticker ,
SV_StartFrame  )

Definition at line 97 of file porto.qc.

98{
99 FOREACH_CLIENT(IS_PLAYER(it), it.porto_forbidden = max(0, it.porto_forbidden - 1));
100}
#define IS_PLAYER(s)
Definition player.qh:242
float max(float f,...)
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52

References FOREACH_CLIENT, IS_PLAYER, and max().

◆ Porto_Draw()

void Porto_Draw ( entity this)

Definition at line 17 of file porto.qc.

18{
19 if (spectatee_status || intermission == 1 || intermission == 2 || STAT(HEALTH) <= 0 || WEP_CVAR(WEP_PORTO, secondary))
20 return;
21
22 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
23 {
24 entity wepent = viewmodels[slot];
25
26 if (wepent.activeweapon != WEP_PORTO)
27 continue;
28
29 vector pos = view_origin;
32 pos += v_right * -wepent.movedir.y
33 + v_up * wepent.movedir.z;
34
35 if (wepent.angles_held_status)
36 {
37 makevectors(wepent.angles_held);
38 dir = v_forward;
39 }
40
41 wepent.polyline[0] = pos;
42
43 int portal_number = 0, portal1_idx = 1, portal_max = 2;
44 int n = 1 + 2; // 2 lines == 3 points
45 for (int idx = 0; idx < n && idx < polyline_length - 1; )
46 {
47 traceline(pos, pos + 65536 * dir, true, this);
49 pos = trace_endpos;
50 wepent.polyline[++idx] = pos;
52 {
53 ++n;
54 continue;
55 }
57 {
58 n = max(2, idx);
59 break;
60 }
61 // check size
62 {
63 vector ang = vectoangles2(trace_plane_normal, dir);
64 ang.x = -ang.x;
66 if (!CheckWireframeBox(this, pos - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
67 {
68 n = max(2, idx);
69 break;
70 }
71 }
72 ++portal_number;
73 if (portal_number >= portal_max)
74 break;
75 if (portal_number == 1)
76 portal1_idx = idx;
77 }
78 for (int idx = 0; idx < n - 1; ++idx)
79 {
80 vector p = wepent.polyline[idx];
81 vector q = wepent.polyline[idx + 1];
82 if (idx == 0)
83 p -= view_up * 16; // line from player
84 vector rgb = (idx < portal1_idx) ? '1 0 0' : '0 0 1';
85 Draw_CylindricLine(p, q, 4, "", 1, 0, rgb, 0.5, DRAWFLAG_NORMAL, view_origin);
86 }
87 }
88}
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
vector view_origin
Definition main.qh:109
int spectatee_status
the -1 disables HUD panels before CSQC receives necessary data
Definition main.qh:197
vector view_up
Definition main.qh:109
vector view_forward
Definition main.qh:109
float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz)
Definition util.qc:580
void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg)
Definition draw.qh:11
vector v_up
const float DRAWFLAG_NORMAL
float trace_dphitcontents
float Q3SURFACEFLAG_SLICK
vector view_angles
float DPCONTENTS_PLAYERCLIP
vector v_right
vector trace_endpos
float trace_dphitq3surfaceflags
float intermission
vector v_forward
float Q3SURFACEFLAG_NOIMPACT
vector trace_plane_normal
#define STAT(...)
Definition stats.qh:82
vector warpzone_save_view_angles
Definition client.qh:9
const int polyline_length
Definition porto.qc:15
#define makevectors
Definition post.qh:21
vector
Definition self.qh:92
vector vector ang
Definition self.qh:92
int dir
Definition impulse.qc:89
ERASEABLE vector reflect(vector dir, vector norm)
Definition vector.qh:136
int autocvar_chase_active
Definition view.qh:17
entity viewmodels[MAX_WEAPONSLOTS]
Definition view.qh:108
#define WEP_CVAR(wep, name)
Definition all.qh:337
const int MAX_WEAPONSLOTS
Definition weapon.qh:16

References ang, autocvar_chase_active, CheckWireframeBox(), dir, DPCONTENTS_PLAYERCLIP, Draw_CylindricLine(), DRAWFLAG_NORMAL, entity(), intermission, makevectors, max(), MAX_WEAPONSLOTS, polyline_length, Q3SURFACEFLAG_NOIMPACT, Q3SURFACEFLAG_SLICK, reflect(), spectatee_status, STAT, trace_dphitcontents, trace_dphitq3surfaceflags, trace_endpos, trace_plane_normal, v_forward, v_right, v_up, vector, view_angles, view_forward, view_origin, view_up, viewmodels, warpzone_save_view_angles, and WEP_CVAR.

Referenced by STATIC_INIT().

◆ REGISTER_MUTATOR()

REGISTER_MUTATOR ( porto_ticker ,
true  )

◆ STATIC_INIT()

STATIC_INIT ( Porto )

Definition at line 7 of file porto.qc.

8{
9 entity e = new_pure(porto);
10 e.draw = Porto_Draw;
13}
IntrusiveList g_drawables
Definition main.qh:91
float DPCONTENTS_SOLID
float DPCONTENTS_BODY
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:67
void Porto_Draw(entity this)
Definition porto.qc:17

References DPCONTENTS_BODY, DPCONTENTS_PLAYERCLIP, DPCONTENTS_SOLID, entity(), g_drawables, IL_PUSH(), new_pure, and Porto_Draw().

◆ W_Porto_Attack()

void W_Porto_Attack ( Weapon thiswep,
entity actor,
.entity weaponentity,
float type )

Definition at line 288 of file porto.qc.

289{
290 W_SetupShot(actor, weaponentity, false, 4, SND_PORTO_FIRE, CH_WEAPON_A, 0, thiswep.m_id); // TODO: does the deathtype even need to be set here? porto can't hurt people
291 // always shoot from the eye
293 w_shotorg = actor.origin + actor.view_ofs + ((w_shotorg - actor.origin - actor.view_ofs) * v_forward) * v_forward;
294
295 //Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
296
297 entity gren = new(porto);
298 gren.weaponentity_fld = weaponentity;
299 gren.cnt = type;
300 gren.owner = gren.realowner = actor;
301 gren.playerid = actor.playerid;
302 gren.bot_dodge = true;
303 gren.bot_dodgerating = 200;
306 gren.effects = EF_RED;
307 gren.scale = 4;
308 setorigin(gren, w_shotorg);
309 setsize(gren, '0 0 0', '0 0 0');
310
311 gren.nextthink = time + WEP_CVAR_BOTH(WEP_PORTO, (type <= 0), lifetime);
312 setthink(gren, W_Porto_Think);
313 settouch(gren, W_Porto_Touch);
314
315 // TODO: handle as mutator effect
316 if (StatusEffects_active(STATUSEFFECT_Strength, actor))
318 else
319 W_SetupProjVelocity_Basic(gren, WEP_CVAR_BOTH(WEP_PORTO, (type <= 0), speed), 0);
320
321 gren.angles = vectoangles(gren.velocity);
322 gren.flags = FL_PROJECTILE;
323 IL_PUSH(g_projectiles, gren);
324 IL_PUSH(g_bot_dodge, gren);
325
326 gren.portal_id = time;
327 actor.porto_current = gren;
328 gren.playerid = actor.playerid;
329 fixedmakevectors(fixedvectoangles(gren.velocity));
330 gren.right_vector = v_right;
331
332 gren.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
333
334 if (type > 0)
335 CSQCProjectile(gren, true, PROJECTILE_PORTO_BLUE, true);
336 else
337 CSQCProjectile(gren, true, PROJECTILE_PORTO_RED, true);
338
339 MUTATOR_CALLHOOK(EditProjectile, actor, gren);
340}
void fixedmakevectors(vector a)
#define fixedvectoangles
IntrusiveList g_bot_dodge
Definition api.qh:150
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
int m_id
Definition weapon.qh:43
float lifetime
Definition powerups.qc:23
const int FL_PROJECTILE
Definition constants.qh:85
const float EF_RED
float time
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
float speed
Definition dynlight.qc:9
vector vectoangles(vector v)
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_BOUNCEMISSILE
Definition movetypes.qh:140
void W_Porto_Think(entity this)
Definition porto.qc:157
void W_Porto_Touch(entity this, entity toucher)
Definition porto.qc:166
const int PROJECTILE_PORTO_BLUE
const int PROJECTILE_PORTO_RED
#define setthink(e, f)
#define settouch(e, f)
Definition self.qh:73
IntrusiveList g_projectiles
Definition common.qh:58
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:34
const int CH_WEAPON_A
Definition sound.qh:7
bool StatusEffects_active(StatusEffect this, entity actor)
float autocvar_g_balance_powerup_strength_force
Definition strength.qh:19
vector w_shotdir
Definition tracing.qh:20
vector w_shotorg
Definition tracing.qh:19
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition tracing.qh:34
#define W_SetupProjVelocity_Basic(ent, pspeed, pspread)
Definition tracing.qh:49
#define WEP_CVAR_BOTH(wep, isprimary, name)
Definition all.qh:340

References autocvar_g_balance_powerup_strength_force, CH_WEAPON_A, CSQCProjectile(), DPCONTENTS_BODY, DPCONTENTS_PLAYERCLIP, DPCONTENTS_SOLID, EF_RED, entity(), fixedmakevectors(), fixedvectoangles, FL_PROJECTILE, g_bot_dodge, g_projectiles, IL_PUSH(), lifetime, Weapon::m_id, MOVETYPE_BOUNCEMISSILE, MUTATOR_CALLHOOK, PROJECTILE_MAKETRIGGER, PROJECTILE_PORTO_BLUE, PROJECTILE_PORTO_RED, set_movetype(), setthink, settouch, speed, StatusEffects_active(), time, v_forward, v_right, vectoangles(), W_Porto_Think(), W_Porto_Touch(), W_SetupProjVelocity_Basic, W_SetupShot, w_shotdir, w_shotorg, and WEP_CVAR_BOTH.

◆ W_Porto_Fail()

void W_Porto_Fail ( entity this,
bool failhard )

Definition at line 114 of file porto.qc.

115{
116 if (this.realowner == NULL)
117 {
118 objerror(this, "Cannot fail successfully: no owner\n");
119 return;
120 }
121
122 // no portals here!
123 if (this.cnt < 0)
125
126 this.realowner.porto_current = NULL;
127
128 if (this.cnt < 0 && !failhard && this.realowner.playerid == this.playerid
129 && !IS_DEAD(this.realowner) && !(STAT(WEAPONS, this.realowner) & WEPSET(PORTO)))
130 {
131 // FIXME: item properties should be obtained from the registry
132 setsize(this, ITEM_D_MINS, ITEM_D_MAXS);
133 setorigin(this, this.origin + trace_plane_normal);
134 if (nudgeoutofsolid_OrFallback(this))
135 {
136 this.flags = FL_ITEM;
137 IL_PUSH(g_items, this);
138 this.velocity = trigger_push_calculatevelocity(this.origin, this.realowner, 128, this);
139 tracetoss(this, this);
140 if (vdist(trace_endpos - this.realowner.origin, <, 128))
141 {
142 .entity weaponentity = this.weaponentity_fld;
143 W_ThrowNewWeapon(this.realowner, WEP_PORTO.m_id, 0, this.origin, this.velocity, weaponentity);
144 Send_Notification(NOTIF_ONE, this.realowner, MSG_CENTER, CENTER_PORTO_FAILED);
145 }
146 }
147 }
148 delete(this);
149}
float cnt
Definition powerups.qc:24
const vector ITEM_D_MAXS
Definition item.qh:83
const vector ITEM_D_MINS
Definition item.qh:82
#define IS_DEAD(s)
Definition player.qh:244
const int FL_ITEM
Definition constants.qh:77
float flags
vector velocity
vector origin
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1573
void Portal_ClearWithID(entity own, float id)
Definition portals.qc:614
float portal_id
Definition portals.qh:6
#define NULL
Definition post.qh:14
#define objerror
Definition pre.qh:8
IntrusiveList g_items
Definition items.qh:119
vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity pushed_entity)
Definition jumppads.qc:32
entity realowner
float W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo,.entity weaponentity)
Returns amount of ammo used, or -1 for failure, or 0 for no ammo count.
Definition throwing.qc:22
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition vector.qh:8
#define WEPSET(id)
Definition all.qh:47
entity weaponentity_fld

References cnt, entity(), FL_ITEM, flags, g_items, IL_PUSH(), IS_DEAD, ITEM_D_MAXS, ITEM_D_MINS, NULL, objerror, origin, Portal_ClearWithID(), portal_id, realowner, Send_Notification(), STAT, trace_endpos, trace_plane_normal, trigger_push_calculatevelocity(), vdist, velocity, W_ThrowNewWeapon(), weaponentity_fld, and WEPSET.

Referenced by checkpoint_passed(), W_Porto_Remove(), W_Porto_Think(), and W_Porto_Touch().

◆ W_Porto_Remove()

void W_Porto_Remove ( entity p)

Definition at line 151 of file porto.qc.

152{
153 if (p.porto_current.realowner == p && p.porto_current.classname == "porto")
154 W_Porto_Fail(p.porto_current, true);
155}
void W_Porto_Fail(entity this, bool failhard)
Definition porto.qc:114

References entity(), and W_Porto_Fail().

Referenced by Portal_ClearAll(), and Portal_ClearAllLater().

◆ W_Porto_Success()

void W_Porto_Success ( entity this)

Definition at line 102 of file porto.qc.

103{
104 if (this.realowner == NULL)
105 {
106 objerror(this, "Cannot succeed successfully: no owner\n");
107 return;
108 }
109
110 this.realowner.porto_current = NULL;
111 delete(this);
112}

References entity(), NULL, objerror, and realowner.

Referenced by W_Porto_Touch().

◆ W_Porto_Think()

void W_Porto_Think ( entity this)

Definition at line 157 of file porto.qc.

158{
159 trace_plane_normal = '0 0 0';
160 if (this.realowner.playerid != this.playerid)
161 delete(this);
162 else
163 W_Porto_Fail(this, false);
164}

References entity(), realowner, trace_plane_normal, and W_Porto_Fail().

Referenced by W_Porto_Attack().

◆ W_Porto_Touch()

void W_Porto_Touch ( entity this,
entity toucher )

Definition at line 166 of file porto.qc.

167{
168 // do not use PROJECTILE_TOUCH here
169 // FIXME but DO handle warpzones!
170
171 if (toucher.classname == "portal")
172 return; // handled by the portal
173
175 if (trace_ent.iscreature)
176 {
177 // TODO: why not use entity size?
178 traceline(trace_ent.origin, trace_ent.origin + '0 0 2' * PL_MIN_CONST.z, MOVE_WORLDONLY, this);
179 if (trace_fraction >= 1)
180 return;
182 return;
184 return;
185 }
186
187 if (this.realowner.playerid != this.playerid)
188 {
189 sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
190 delete(this);
191 }
193 {
194 spamsound(this, CH_SHOTS, SND_PORTO_BOUNCE, VOL_BASE, ATTEN_NORM);
195 // just reflect
198 }
200 {
201 sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
202 W_Porto_Fail(this, false);
203 if (this.cnt < 0)
205 }
206 else if (this.cnt == 0)
207 {
208 // in-portal only
210 {
211 sound(this, CH_SHOTS, SND_PORTO_CREATE, VOL_BASE, ATTEN_NORM);
212 trace_plane_normal = norm;
213 Send_Notification(NOTIF_ONE, this.realowner, MSG_CENTER, CENTER_PORTO_CREATED_IN);
214 W_Porto_Success(this);
215 }
216 else
217 {
218 sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
219 trace_plane_normal = norm;
220 W_Porto_Fail(this, false);
221 }
222 }
223 else if (this.cnt == 1)
224 {
225 // out-portal only
227 {
228 sound(this, CH_SHOTS, SND_PORTO_CREATE, VOL_BASE, ATTEN_NORM);
229 trace_plane_normal = norm;
230 Send_Notification(NOTIF_ONE, this.realowner, MSG_CENTER, CENTER_PORTO_CREATED_OUT);
231 W_Porto_Success(this);
232 }
233 else
234 {
235 sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
236 trace_plane_normal = norm;
237 W_Porto_Fail(this, false);
238 }
239 }
240 else if (this.effects & EF_RED)
241 {
242 this.effects &= ~EF_RED;
243 this.effects |= EF_BLUE;
245 {
246 sound(this, CH_SHOTS, SND_PORTO_CREATE, VOL_BASE, ATTEN_NORM);
247 trace_plane_normal = norm;
248 Send_Notification(NOTIF_ONE, this.realowner, MSG_CENTER, CENTER_PORTO_CREATED_IN);
249 this.right_vector -= 2 * trace_plane_normal * (this.right_vector * norm);
250 this.angles = vectoangles(this.velocity - 2 * trace_plane_normal * (this.velocity * norm));
251 CSQCProjectile(this, true, PROJECTILE_PORTO_BLUE, true); // change type
252 }
253 else
254 {
255 sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
256 trace_plane_normal = norm;
258 W_Porto_Fail(this, false);
259 }
260 }
261 else
262 {
263 if (this.realowner.portal_in.portal_id == this.portal_id)
264 {
266 {
267 sound(this, CH_SHOTS, SND_PORTO_CREATE, VOL_BASE, ATTEN_NORM);
268 trace_plane_normal = norm;
269 Send_Notification(NOTIF_ONE, this.realowner, MSG_CENTER, CENTER_PORTO_CREATED_OUT);
270 W_Porto_Success(this);
271 }
272 else
273 {
274 sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
276 W_Porto_Fail(this, false);
277 }
278 }
279 else
280 {
281 sound(this, CH_SHOTS, SND_PORTO_UNSUPPORTED, VOL_BASE, ATTEN_NORM);
283 W_Porto_Fail(this, false);
284 }
285 }
286}
const vector PL_MIN_CONST
Definition constants.qh:56
entity trace_ent
float effects
float MOVE_WORLDONLY
const float EF_BLUE
float trace_fraction
ent angles
Definition ent_cs.qc:121
float Portal_SpawnOutPortalAtTrace(entity own, vector dir, float portal_id_val)
Definition portals.qc:683
void Portal_ClearAll_PortalsOnly(entity own)
Definition portals.qc:579
float Portal_SpawnInPortalAtTrace(entity own, vector dir, float portal_id_val)
Definition portals.qc:667
void W_Porto_Success(entity this)
Definition porto.qc:102
vector right_vector
Definition porto.qh:68
entity entity toucher
Definition self.qh:72
const float VOL_BASE
Definition sound.qh:36
const int CH_SHOTS
Definition sound.qh:14
const float ATTEN_NORM
Definition sound.qh:30
#define sound(e, c, s, v, a)
Definition sound.qh:52
float spamsound(entity e, int chan, Sound samp, float vol, float _atten)
use this one if you might be causing spam (e.g.
Definition all.qc:124

References angles, ATTEN_NORM, CH_SHOTS, cnt, CSQCProjectile(), DPCONTENTS_PLAYERCLIP, EF_BLUE, EF_RED, effects, entity(), MOVE_WORLDONLY, PL_MIN_CONST, Portal_ClearAll_PortalsOnly(), portal_id, Portal_SpawnInPortalAtTrace(), Portal_SpawnOutPortalAtTrace(), PROJECTILE_PORTO_BLUE, Q3SURFACEFLAG_NOIMPACT, Q3SURFACEFLAG_SLICK, realowner, right_vector, Send_Notification(), sound, spamsound(), toucher, trace_dphitcontents, trace_dphitq3surfaceflags, trace_ent, trace_fraction, trace_plane_normal, vectoangles(), vector, velocity, VOL_BASE, W_Porto_Fail(), and W_Porto_Success().

Referenced by W_Porto_Attack().

Variable Documentation

◆ polyline

Definition at line 16 of file porto.qc.

◆ polyline_length

const int polyline_length = 16

Definition at line 15 of file porto.qc.

Referenced by Porto_Draw().