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