5 #include <lib/warpzone/util_server.qh>
6 #include <server/defs.qh>
9 REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC)
10 REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC_TRIGGER)
14 void viewloc_think(entity this)
16 // we abuse this method, rather than using normal .touch, because touch isn't reliable with multiple clients inside the same trigger, and can't "untouch" entities
18 // set myself as current viewloc where possible
20 FOREACH_CLIENT(IS_PLAYER(it) && it.viewloc == this,
26 for(e = NULL; (e = findentity(e, viewloc, this)); )
31 FOREACH_CLIENT(!it.viewloc && IS_PLAYER(it),
33 vector emin = it.absmin;
34 vector emax = it.absmax;
35 if(this.solid == SOLID_BSP)
40 if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
42 if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
48 for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain)
50 if(IS_PLAYER(e)) // should we support non-player entities with this?
51 //if(!IS_DEAD(e)) // death view is handled separately, we can't override this just yet
53 vector emin = e.absmin;
54 vector emax = e.absmax;
55 if(this.solid == SOLID_BSP)
60 if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
61 if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, e)) // accurate
66 this.nextthink = time;
69 bool trigger_viewloc_send(entity this, entity to, int sf)
71 // CSQC doesn't need to know our origin (yet), as we're only available for referencing
72 WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
74 WriteByte(MSG_ENTITY, this.spawnflags);
76 WriteEntity(MSG_ENTITY, this.enemy);
77 WriteEntity(MSG_ENTITY, this.goalentity);
79 WriteVector(MSG_ENTITY, this.origin);
84 void viewloc_init(entity this)
87 for(e = NULL; (e = find(e, targetname, this.target)); )
88 if(e.classname == "target_viewlocation_start")
93 for(e = NULL; (e = find(e, targetname, this.target2)); )
94 if(e.classname == "target_viewlocation_end")
100 if(!this.enemy) { LOG_INFO("^1FAIL!"); delete(this); return; }
103 this.goalentity = this.enemy; // make them match so CSQC knows what to do
105 Net_LinkEntity(this, false, 0, trigger_viewloc_send);
107 setthink(this, viewloc_think);
108 this.nextthink = time;
111 spawnfunc(trigger_viewlocation)
113 // we won't check target2 here yet, as it may not even need to exist
114 if(this.target == "") { LOG_INFO("^1FAIL!"); delete(this); return; }
117 InitializeEntity(this, viewloc_init, INITPRIO_FINDTARGET);
120 bool viewloc_send(entity this, entity to, int sf)
122 WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
124 WriteByte(MSG_ENTITY, this.cnt);
126 WriteVector(MSG_ENTITY, this.origin);
128 WriteAngle(MSG_ENTITY, this.angles_x);
129 WriteAngle(MSG_ENTITY, this.angles_y);
130 WriteAngle(MSG_ENTITY, this.angles_z);
136 void viewloc_link(entity this)
139 this.angles_y = this.angle;
140 Net_LinkEntity(this, false, 0, viewloc_send);
143 spawnfunc(target_viewlocation_start)
145 this.classname = "target_viewlocation_start";
149 spawnfunc(target_viewlocation_end)
151 this.classname = "target_viewlocation_end";
157 spawnfunc(target_viewlocation)
159 spawnfunc_target_viewlocation_start(this);
164 void trigger_viewloc_updatelink(entity this)
166 this.enemy = findfloat(NULL, entnum, this.cnt);
167 this.goalentity = findfloat(NULL, entnum, this.count);
170 NET_HANDLE(ENT_CLIENT_VIEWLOC_TRIGGER, bool isnew)
172 this.spawnflags = ReadByte();
174 float point1 = ReadShort();
175 float point2 = ReadShort();
177 this.enemy = findfloat(NULL, entnum, point1);
178 this.goalentity = findfloat(NULL, entnum, point2);
180 this.origin = ReadVector();
184 setorigin(this, this.origin);
189 setthink(this, trigger_viewloc_updatelink);
190 this.nextthink = time + 1; // we need to delay this or else
192 this.classname = "trigger_viewlocation";
193 this.drawmask = MASK_NORMAL; // not so concerned, but better keep it alive
196 NET_HANDLE(ENT_CLIENT_VIEWLOC, bool isnew)
198 this.cnt = ReadByte();
200 this.origin = ReadVector();
201 setorigin(this, this.origin);
203 this.movedir_x = ReadAngle();
204 this.movedir_y = ReadAngle();
205 this.movedir_z = ReadAngle();
209 this.classname = ((this.cnt == 2) ? "target_viewlocation_end" : "target_viewlocation_start");
210 this.drawmask = MASK_NORMAL; // don't cull it