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