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