]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/t_teleporters.qc
trigger_teleport: setmodel only if it is not "". Then a teleporter can be manually...
[divverent/nexuiz.git] / data / qcsrc / server / t_teleporters.qc
1 void tdeath_touch()
2 {
3         if (other == self.owner)
4                 return;
5         // so teleporting shots etc can't telefrag
6         if (!self.owner.takedamage)
7                 return;
8         if (!other.takedamage)
9                 return;
10
11         if ((self.owner.classname == "player") && (self.owner.health >= 1))
12                 Damage (other, self, self.owner, 10000, DEATH_TELEFRAG, other.origin, '0 0 0');
13         else if (other.health < 1) // corpses gib
14                 Damage (other, self, self.owner, 10000, DEATH_TELEFRAG, other.origin, '0 0 0');
15         else // dead bodies and monsters gib themselves instead of telefragging
16                 Damage (self.owner, self, self.owner, 10000, DEATH_TELEFRAG, self.owner.origin, '0 0 0');
17 };
18
19 void tdeath_remove()
20 {
21         if (self.owner)
22         {
23                 self.owner.effects = self.owner.effects - (self.owner.effects & EF_NODRAW);
24                 if (self.owner.weaponentity)
25                         self.owner.weaponentity.flags = self.owner.weaponentity.flags - (self.owner.weaponentity.flags & FL_FLY);
26         }
27         remove(self);
28 }
29
30 // org2 is where they will return to if the teleport fails
31 void spawn_tdeath(vector org, entity death_owner, vector org2)
32 {
33         local entity death;
34
35         death = spawn();
36 //      death.classname = "teledeath";
37         death.movetype = MOVETYPE_NONE;
38         death.solid = SOLID_TRIGGER;
39         death.angles = '0 0 0';
40         death.dest2 = org2;
41         setsize (death, death_owner.mins - '1 1 1', death_owner.maxs + '1 1 1');
42         setorigin (death, org);
43         death.touch = tdeath_touch;
44         death.nextthink = time + 0.2;
45         death.think = tdeath_remove;
46         death.owner = death_owner;
47
48         // hide entity to avoid "ghosts" between teleporter and destination caused by clientside interpolation
49         death.owner.effects = death.owner.effects | EF_NODRAW;
50         if (death.owner.weaponentity) // misuse FL_FLY to avoid EF_NODRAW on viewmodel
51                 death.owner.weaponentity.flags = death.owner.weaponentity.flags | FL_FLY;
52
53         force_retouch = 2;              // make sure even still objects get hit
54 };
55
56 void Teleport_Touch (void)
57 {
58         entity head;
59         entity oldself;
60
61         if (other.health < 1)
62                 return;
63         if (!other.flags & FL_CLIENT)   // FIXME: Make missiles firable through the teleport too
64                 return;
65
66         sound (other, CHAN_TRIGGER, "misc/teleport.wav", VOL_BASE, ATTN_NORM);
67         pointparticles(particleeffectnum("teleport"), other.origin, '0 0 0', 1);
68
69         /*
70         // Make teleport effect where the player left
71         sound (self, CHAN_TRIGGER, "misc/teleport.wav", VOL_BASE, ATTN_NORM);
72         pointparticles(particleeffectnum("teleport"), other.origin, '0 0 0', 1);
73
74         // Make teleport effect where the player arrived
75         sound (self.enemy, CHAN_TRIGGER, "misc/teleport.wav", VOL_BASE, ATTN_NORM);
76         */
77
78         makevectors (self.enemy.mangle);
79         pointparticles(particleeffectnum("teleport"), self.enemy.origin + v_forward * 32, '0 0 0', 1);
80
81         // Relocate the player
82         setorigin (other, self.enemy.origin + '0 0 1' * (1 - other.mins_z - 24));
83         other.angles = self.enemy.mangle;
84         other.fixangle = TRUE;
85         other.velocity = v_forward * vlen(other.velocity);
86
87         // Kill anyone else in the teleporter box (NO MORE TDEATH)
88         if(other.takedamage)
89         {
90                 vector deathmin;
91                 vector deathmax;
92                 float deathradius;
93                 deathmin = other.absmin;
94                 deathmax = other.absmax;
95                 deathradius = max(vlen(deathmin), vlen(deathmax));
96                 for(head = findradius(other.origin, deathradius); head; head = head.chain)
97                         if(head != other)
98                                 if(head.takedamage)
99                                         if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
100                                         {
101                                                 if ((other.classname == "player") && (other.health >= 1))
102                                                         Damage (head, self, other, 10000, DEATH_TELEFRAG, head.origin, '0 0 0');
103                                                 else if (other.health < 1) // corpses gib
104                                                         Damage (head, self, other, 10000, DEATH_TELEFRAG, head.origin, '0 0 0');
105                                                 else // dead bodies and monsters gib themselves instead of telefragging
106                                                         Damage (other, self, other, 10000, DEATH_TELEFRAG, other.origin, '0 0 0');
107                                         }
108         }
109
110         // hide myself a tic
111         other.effects = other.effects | EF_NODRAW;
112         if (other.weaponentity) // misuse FL_FLY to avoid EF_NODRAW on viewmodel
113                 other.weaponentity.flags = other.weaponentity.flags | FL_FLY;
114         other.teleport_time = time + cvar("sys_ticrate");
115
116         other.flags = other.flags - (other.flags & FL_ONGROUND);
117         // reset tracking of oldvelocity for impact damage (sudden velocity changes)
118         other.oldvelocity = other.velocity;
119         // reset tracking of who pushed you into a hazard (for kill credit)
120         other.pushltime = 0;
121
122         // stop player name display
123         {
124                 oldself = self;
125                 self = other;
126                 ClearSelectedPlayer();
127                 self = oldself;
128         }
129
130         if(self.enemy.target)
131         {
132                 oldself = self;
133                 activator = other;
134                 self = self.enemy;
135                 SUB_UseTargets();
136                 self = oldself;
137         }
138 }
139
140 void spawnfunc_info_teleport_destination (void)
141 {
142         self.mangle = self.angles;
143         self.angles = '0 0 0';
144
145         //setorigin (self, self.origin + '0 0 27');     // To fix a mappers' habit as old as Quake
146         setorigin (self, self.origin);
147
148         if (!self.targetname)
149                 objerror ("Teleport destination without a targetname");
150 }
151
152 void spawnfunc_misc_teleporter_dest (void)
153 {
154         spawnfunc_info_teleport_destination();
155 }
156
157 void spawnfunc_target_teleporter (void)
158 {
159         spawnfunc_info_teleport_destination();
160 }
161
162 void teleport_findtarget (void)
163 {
164         // now enable touch
165         self.touch = Teleport_Touch;
166
167         self.enemy = find (world, targetname, self.target);
168         if (!self.enemy)
169         {
170                 objerror ("Teleporter with nonexistant target");
171                 remove(self);
172                 return;
173         }
174
175         self.dest = self.enemy.origin;
176         waypoint_spawnforteleporter(self, self.dest, 0);
177 }
178
179 void spawnfunc_trigger_teleport (void)
180 {
181         self.angles = '0 0 0';
182
183         self.solid = SOLID_TRIGGER;
184         self.movetype = MOVETYPE_NONE;
185
186         if(self.model != "")
187                 setmodel (self, self.model); // no precision needed
188
189         self.model = "";
190         self.modelindex = 0;
191
192         self.think = teleport_findtarget;
193         self.nextthink = time + 0.2;
194
195         if (!self.target)
196                 objerror ("Teleporter with no target");
197 }