1#include "viewloc.qh" 2#if defined(CSQC) 3#elif defined(MENUQC) 4#elif defined(SVQC) 5 #include <lib/warpzone/util_server.qh> 6 #include <server/defs.qh> 7#endif 8 9REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC) 10REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC_TRIGGER) 11 12#ifdef SVQC 13 14void viewloc_think(entity this) 15{ 16 entity e; 17 18 // 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 19 20 // set myself as current viewloc where possible 21 for(e = NULL; (e = findentity(e, viewloc, this)); ) 22 e.viewloc = NULL; 23 24 for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain) 25 if(!e.viewloc) 26 if(IS_PLAYER(e)) // should we support non-player entities with this? 27 //if(!IS_DEAD(e)) // death view is handled separately, we can't override this just yet 28 { 29 vector emin = e.absmin; 30 vector emax = e.absmax; 31 if(this.solid == SOLID_BSP) 32 { 33 emin -= '1 1 1'; 34 emax += '1 1 1'; 35 } 36 if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick 37 if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, e)) // accurate 38 e.viewloc = this; 39 } 40 41 this.nextthink = time; 42} 43 44bool trigger_viewloc_send(entity this, entity to, int sf) 45{ 46 // CSQC doesn't need to know our origin (yet), as we're only available for referencing 47 WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER); 48 49 WriteEntity(MSG_ENTITY, this.enemy); 50 WriteEntity(MSG_ENTITY, this.goalentity); 51 52 WriteCoord(MSG_ENTITY, this.origin_x); 53 WriteCoord(MSG_ENTITY, this.origin_y); 54 WriteCoord(MSG_ENTITY, this.origin_z); 55 56 return true; 57} 58 59void viewloc_init(entity this) 60{ 61 entity e; 62 for(e = NULL; (e = find(e, targetname, this.target)); ) 63 if(e.classname == "target_viewlocation_start") 64 { 65 this.enemy = e; 66 break; 67 } 68 for(e = NULL; (e = find(e, targetname, this.target2)); ) 69 if(e.classname == "target_viewlocation_end") 70 { 71 this.goalentity = e; 72 break; 73 } 74 75 if(!this.enemy) { LOG_INFO("^1FAIL!\n"); delete(this); return; } 76 77 if(!this.goalentity) 78 this.goalentity = this.enemy; // make them match so CSQC knows what to do 79 80 Net_LinkEntity(this, false, 0, trigger_viewloc_send); 81 82 setthink(this, viewloc_think); 83 this.nextthink = time; 84} 85 86spawnfunc(trigger_viewlocation) 87{ 88 // we won't check target2 here yet, as it may not even need to exist 89 if(this.target == "") { LOG_INFO("^1FAIL!\n"); delete(this); return; } 90 91 EXACTTRIGGER_INIT; 92 InitializeEntity(this, viewloc_init, INITPRIO_FINDTARGET); 93} 94 95bool viewloc_send(entity this, entity to, int sf) 96{ 97 WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC); 98 99 WriteByte(MSG_ENTITY, this.cnt); 100 101 WriteCoord(MSG_ENTITY, this.origin_x); 102 WriteCoord(MSG_ENTITY, this.origin_y); 103 WriteCoord(MSG_ENTITY, this.origin_z); 104 105 WriteAngle(MSG_ENTITY, this.angles_x); 106 WriteAngle(MSG_ENTITY, this.angles_y); 107 WriteAngle(MSG_ENTITY, this.angles_z); 108 109 return true; 110} 111 112.float angle; 113void viewloc_link(entity this) 114{ 115 if(this.angle) 116 this.angles_y = this.angle; 117 Net_LinkEntity(this, false, 0, viewloc_send); 118} 119 120spawnfunc(target_viewlocation_start) 121{ 122 this.classname = "target_viewlocation_start"; 123 this.cnt = 1; 124 viewloc_link(this); 125} 126spawnfunc(target_viewlocation_end) 127{ 128 this.classname = "target_viewlocation_end"; 129 this.cnt = 2; 130 viewloc_link(this); 131} 132 133// compatibility 134spawnfunc(target_viewlocation) { spawnfunc_target_viewlocation_start(this); } 135 136#elif defined(CSQC) 137 138void trigger_viewloc_updatelink(entity this) 139{ 140 this.enemy = findfloat(NULL, entnum, this.cnt); 141 this.goalentity = findfloat(NULL, entnum, this.count); 142} 143 144NET_HANDLE(ENT_CLIENT_VIEWLOC_TRIGGER, bool isnew) 145{ 146 float point1 = ReadShort(); 147 float point2 = ReadShort(); 148 149 this.enemy = findfloat(NULL, entnum, point1); 150 this.goalentity = findfloat(NULL, entnum, point2); 151 152 this.origin_x = ReadCoord(); 153 this.origin_y = ReadCoord(); 154 this.origin_z = ReadCoord(); 155 156 return = true; 157 158 setorigin(this, this.origin); 159 160 this.cnt = point1; 161 this.count = point2; 162 163 setthink(this, trigger_viewloc_updatelink); 164 this.nextthink = time + 1; // we need to delay this or else 165 166 this.classname = "trigger_viewlocation"; 167 this.drawmask = MASK_NORMAL; // not so concerned, but better keep it alive 168} 169 170NET_HANDLE(ENT_CLIENT_VIEWLOC, bool isnew) 171{ 172 this.cnt = ReadByte(); 173 174 this.origin_x = ReadCoord(); 175 this.origin_y = ReadCoord(); 176 this.origin_z = ReadCoord(); 177 setorigin(this, this.origin); 178 179 this.movedir_x = ReadAngle(); 180 this.movedir_y = ReadAngle(); 181 this.movedir_z = ReadAngle(); 182 183 return = true; 184 185 this.classname = ((this.cnt == 2) ? "target_viewlocation_end" : "target_viewlocation_start"); 186 this.drawmask = MASK_NORMAL; // don't cull it 187} 188 189#endif 190