1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "g_local.h"
26 
27 
InitTrigger(edict_t * self)28 void InitTrigger (edict_t *self)
29 {
30 	if (!VectorCompare (self->s.angles, vec3_origin))
31 		G_SetMovedir (self->s.angles, self->movedir);
32 
33 	self->solid = SOLID_TRIGGER;
34 	self->movetype = MOVETYPE_NONE;
35 	gi.setmodel (self, self->model);
36 	self->svflags = SVF_NOCLIENT;
37 }
38 
39 
40 // the wait time has passed, so set back up for another activation
multi_wait(edict_t * ent)41 void multi_wait (edict_t *ent)
42 {
43 	ent->nextthink = 0;
44 }
45 
46 
47 // the trigger was just activated
48 // ent->activator should be set to the activator so it can be held through a delay
49 // so wait for the delay time before firing
multi_trigger(edict_t * ent)50 void multi_trigger (edict_t *ent)
51 {
52 	if (ent->nextthink)
53 		return;		// already been triggered
54 
55 	G_UseTargets (ent, ent->activator);
56 
57 	if (ent->wait > 0)
58 	{
59 		ent->think = multi_wait;
60 		ent->nextthink = level.time + ent->wait;
61 	}
62 	else
63 	{	// we can't just remove (self) here, because this is a touch function
64 		// called while looping through area links...
65 		ent->touch = NULL;
66 		ent->nextthink = level.time + FRAMETIME;
67 		ent->think = G_FreeEdict;
68 	}
69 }
70 
Use_Multi(edict_t * ent,edict_t * other,edict_t * activator)71 void Use_Multi (edict_t *ent, edict_t *other, edict_t *activator)
72 {
73 	ent->activator = activator;
74 	multi_trigger (ent);
75 }
76 
Touch_Multi(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)77 void Touch_Multi (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
78 {
79 
80 	//not during warmup
81 	if (self->spawnflags & 32) {
82 		if(level.time <= warmuptime->value)
83 			return;
84 	}
85 
86 	if(other->client)
87 	{
88 		if (self->spawnflags & 2)
89 			return;
90 	}
91 	else if (other->svflags & SVF_MONSTER)
92 	{
93 		if (!(self->spawnflags & 1))
94 			return;
95 	}
96 
97 	else
98 		return;
99 
100 	if (!VectorCompare(self->movedir, vec3_origin))
101 	{
102 		vec3_t	forward;
103 
104 		AngleVectors(other->s.angles, forward, NULL, NULL);
105 		if (_DotProduct(forward, self->movedir) < 0)
106 			return;
107 	}
108 
109 	self->activator = other;
110 	multi_trigger (self);
111 }
112 
113 /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED
114 Variable sized repeatable trigger.  Must be targeted at one or more entities.
115 If "delay" is set, the trigger waits some time after activating before firing.
116 "wait" : Seconds between triggerings. (.2 default)
117 sounds
118 1)	secret
119 2)	beep beep
120 3)	large switch
121 4)
122 set "message" to text string
123 */
trigger_enable(edict_t * self,edict_t * other,edict_t * activator)124 void trigger_enable (edict_t *self, edict_t *other, edict_t *activator)
125 {
126 	self->solid = SOLID_TRIGGER;
127 	self->use = Use_Multi;
128 	gi.linkentity (self);
129 }
130 
SP_trigger_multiple(edict_t * ent)131 void SP_trigger_multiple (edict_t *ent)
132 {
133 	if (ent->sounds == 1)
134 		ent->noise_index = gi.soundindex ("misc/secret.wav");
135 	else if (ent->sounds == 2)
136 		ent->noise_index = gi.soundindex ("misc/talk.wav");
137 	else if (ent->sounds == 3)
138 		ent->noise_index = gi.soundindex ("misc/trigger1.wav");
139 
140 	if (!ent->wait)
141 		ent->wait = 0.2;
142 	ent->touch = Touch_Multi;
143 	ent->movetype = MOVETYPE_NONE;
144 	ent->svflags |= SVF_NOCLIENT;
145 
146 
147 	if (ent->spawnflags & 4)
148 	{
149 		ent->solid = SOLID_NOT;
150 		ent->use = trigger_enable;
151 	}
152 	else
153 	{
154 		ent->solid = SOLID_TRIGGER;
155 		ent->use = Use_Multi;
156 	}
157 
158 	if (!VectorCompare(ent->s.angles, vec3_origin))
159 		G_SetMovedir (ent->s.angles, ent->movedir);
160 
161 	gi.setmodel (ent, ent->model);
162 	gi.linkentity (ent);
163 }
164 
165 
166 /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED
167 Triggers once, then removes itself.
168 You must set the key "target" to the name of another object in the level that has a matching "targetname".
169 
170 If TRIGGERED, this trigger must be triggered before it is live.
171 
172 sounds
173  1)	secret
174  2)	beep beep
175  3)	large switch
176  4)
177 
178 "message"	string to be displayed when triggered
179 */
180 
SP_trigger_once(edict_t * ent)181 void SP_trigger_once(edict_t *ent)
182 {
183 	// make old maps work because I messed up on flag assignments here
184 	// triggered was on bit 1 when it should have been on bit 4
185 	if (ent->spawnflags & 1)
186 	{
187 		vec3_t	v;
188 
189 		VectorMA (ent->mins, 0.5, ent->size, v);
190 		ent->spawnflags &= ~1;
191 		ent->spawnflags |= 4;
192 		gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
193 	}
194 
195 	ent->wait = -1;
196 	SP_trigger_multiple (ent);
197 }
198 
199 /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
200 This fixed size trigger cannot be touched, it can only be fired by other events.
201 */
trigger_relay_use(edict_t * self,edict_t * other,edict_t * activator)202 void trigger_relay_use (edict_t *self, edict_t *other, edict_t *activator)
203 {
204 	G_UseTargets (self, activator);
205 }
206 
SP_trigger_relay(edict_t * self)207 void SP_trigger_relay (edict_t *self)
208 {
209 	self->use = trigger_relay_use;
210 }
211 
212 
213 /*
214 ==============================================================================
215 
216 trigger_key
217 
218 ==============================================================================
219 */
220 
221 /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)
222 A relay trigger that only fires it's targets if player has the proper key.
223 Use "item" to specify the required key, for example "key_data_cd"
224 */
trigger_key_use(edict_t * self,edict_t * other,edict_t * activator)225 void trigger_key_use (edict_t *self, edict_t *other, edict_t *activator)
226 {
227 	int			index;
228 
229 	if (!self->item)
230 		return;
231 	if (!activator->client)
232 		return;
233 
234 	index = ITEM_INDEX(self->item);
235 	if (!activator->client->pers.inventory[index])
236 	{
237 		if (level.time < self->touch_debounce_time)
238 			return;
239 		self->touch_debounce_time = level.time + 5.0;
240 		safe_centerprintf (activator, "You need the %s", self->item->pickup_name);
241 		gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keytry.wav"), 1, ATTN_NORM, 0);
242 		return;
243 	}
244 
245 	gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/keyuse.wav"), 1, ATTN_NORM, 0);
246 
247 	activator->client->pers.inventory[index]--;
248 
249 	G_UseTargets (self, activator);
250 
251 	self->use = NULL;
252 }
253 
SP_trigger_key(edict_t * self)254 void SP_trigger_key (edict_t *self)
255 {
256 	if (!st.item)
257 	{
258 		gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
259 		return;
260 	}
261 	self->item = FindItemByClassname (st.item);
262 
263 	if (!self->item)
264 	{
265 		gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
266 		return;
267 	}
268 
269 	if (!self->target)
270 	{
271 		gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
272 		return;
273 	}
274 
275 	gi.soundindex ("misc/keytry.wav");
276 	gi.soundindex ("misc/keyuse.wav");
277 
278 	self->use = trigger_key_use;
279 }
280 
281 
282 /*
283 ==============================================================================
284 
285 trigger_counter
286 
287 ==============================================================================
288 */
289 
290 /*QUAKED trigger_counter (.5 .5 .5) ? nomessage
291 Acts as an intermediary for an action that takes multiple inputs.
292 
293 If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished.
294 
295 After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
296 */
297 
trigger_counter_use(edict_t * self,edict_t * other,edict_t * activator)298 void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator)
299 {
300 	if (self->count == 0)
301 		return;
302 
303 	self->count--;
304 
305 	if (self->count)
306 	{
307 		if (! (self->spawnflags & 1))
308 		{
309 			safe_centerprintf(activator, "%i more to go...", self->count);
310 			gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
311 		}
312 		return;
313 	}
314 
315 	if (! (self->spawnflags & 1))
316 	{
317 		safe_centerprintf(activator, "Sequence completed!");
318 		gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
319 	}
320 	self->activator = activator;
321 	multi_trigger (self);
322 }
323 
SP_trigger_counter(edict_t * self)324 void SP_trigger_counter (edict_t *self)
325 {
326 	self->wait = -1;
327 	if (!self->count)
328 		self->count = 2;
329 
330 	self->use = trigger_counter_use;
331 }
332 
333 
334 /*
335 ==============================================================================
336 
337 trigger_always
338 
339 ==============================================================================
340 */
341 
342 /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
343 This trigger will always fire.  It is activated by the world.
344 */
SP_trigger_always(edict_t * ent)345 void SP_trigger_always (edict_t *ent)
346 {
347 	// we must have some delay to make sure our use targets are present
348 	if (ent->delay < 0.2)
349 		ent->delay = 0.2;
350 	G_UseTargets(ent, ent);
351 }
352 
353 
354 /*
355 ==============================================================================
356 
357 trigger_push
358 
359 ==============================================================================
360 */
361 
362 #define PUSH_ONCE		1
363 
364 static int windsound;
365 
trigger_push_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)366 void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
367 {
368 	if (strcmp(other->classname, "grenade") == 0)
369 	{
370 		VectorScale (self->movedir, self->speed * 10, other->velocity);
371 	}
372 	else if (other->health > 0)
373 	{
374 		VectorScale (self->movedir, self->speed * 10, other->velocity);
375 
376 		if (other->client)
377 		{
378 			// don't take falling damage immediately from this
379 			VectorCopy (other->velocity, other->client->oldvelocity);
380 			if (other->fly_sound_debounce_time < level.time)
381 			{
382 				other->fly_sound_debounce_time = level.time + 1.5;
383 				gi.sound (other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
384 			}
385 		}
386 	}
387 	if (self->spawnflags & PUSH_ONCE)
388 		G_FreeEdict (self);
389 }
390 
391 
392 /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE
393 Pushes the player
394 "speed"		defaults to 1000
395 */
SP_trigger_push(edict_t * self)396 void SP_trigger_push (edict_t *self)
397 {
398 	InitTrigger (self);
399 	windsound = gi.soundindex ("misc/windfly.wav");
400 	self->touch = trigger_push_touch;
401 	if (!self->speed)
402 		self->speed = 1000;
403 	gi.linkentity (self);
404 }
405 
406 
407 /*
408 ==============================================================================
409 
410 trigger_hurt
411 
412 ==============================================================================
413 */
414 
415 /*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF TOGGLE SILENT NO_PROTECTION SLOW
416 Any entity that touches this will be hurt.
417 
418 It does dmg points of damage each server frame
419 
420 SILENT			supresses playing the sound
421 SLOW			changes the damage rate to once per second
422 NO_PROTECTION	*nothing* stops the damage
423 
424 "dmg"			default 5 (whole numbers only)
425 
426 */
hurt_use(edict_t * self,edict_t * other,edict_t * activator)427 void hurt_use (edict_t *self, edict_t *other, edict_t *activator)
428 {
429 	if (self->solid == SOLID_NOT)
430 		self->solid = SOLID_TRIGGER;
431 	else
432 		self->solid = SOLID_NOT;
433 	gi.linkentity (self);
434 
435 	if (!(self->spawnflags & 2))
436 		self->use = NULL;
437 }
438 
439 
hurt_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)440 void hurt_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
441 {
442 	int		dflags;
443 
444 	if (!other->takedamage)
445 		return;
446 
447 	if (self->timestamp > level.time)
448 		return;
449 
450 	if (self->spawnflags & 16)
451 		self->timestamp = level.time + 1;
452 	else
453 		self->timestamp = level.time + FRAMETIME;
454 
455 	if (!(self->spawnflags & 4))
456 	{
457 		if ((level.framenum % 10) == 0)
458 			gi.sound (other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
459 	}
460 
461 	if (self->spawnflags & 8)
462 		dflags = DAMAGE_NO_PROTECTION;
463 	else
464 		dflags = 0;
465 	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags, MOD_TRIGGER_HURT);
466 }
467 
SP_trigger_hurt(edict_t * self)468 void SP_trigger_hurt (edict_t *self)
469 {
470 	InitTrigger (self);
471 
472 	self->touch = hurt_touch;
473 
474 	if (!self->dmg)
475 		self->dmg = 5;
476 
477 	if (self->spawnflags & 1)
478 		self->solid = SOLID_NOT;
479 	else
480 		self->solid = SOLID_TRIGGER;
481 
482 	if (self->spawnflags & 2)
483 		self->use = hurt_use;
484 
485 	gi.linkentity (self);
486 }
487 
488 
489 /*
490 ==============================================================================
491 
492 trigger_gravity
493 
494 ==============================================================================
495 */
496 
497 /*QUAKED trigger_gravity (.5 .5 .5) ?
498 Changes the touching entites gravity to
499 the value of "gravity".  1.0 is standard
500 gravity for the level.
501 */
502 
trigger_gravity_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)503 void trigger_gravity_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
504 {
505 	other->gravity = self->gravity;
506 }
507 
SP_trigger_gravity(edict_t * self)508 void SP_trigger_gravity (edict_t *self)
509 {
510 	if (st.gravity == 0)
511 	{
512 		gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
513 		G_FreeEdict  (self);
514 		return;
515 	}
516 
517 	InitTrigger (self);
518 	self->gravity = atoi(st.gravity);
519 	self->touch = trigger_gravity_touch;
520 }
521 
522 
523 /*
524 ==============================================================================
525 
526 trigger_monsterjump
527 
528 ==============================================================================
529 */
530 
531 /*QUAKED trigger_monsterjump (.5 .5 .5) ?
532 Walking monsters that touch this will jump in the direction of the trigger's angle
533 "speed" default to 200, the speed thrown forward
534 "height" default to 200, the speed thrown upwards
535 */
536 
trigger_monsterjump_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)537 void trigger_monsterjump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
538 {
539 
540 	if (self->nextthink)
541 		return;		// already been triggered
542 
543 	if (other->flags & (FL_FLY | FL_SWIM) )
544 		return;
545 	if (other->svflags & SVF_DEADMONSTER)
546 		return;
547 
548 // set XY even if not on ground, so the jump will clear lips
549 	other->velocity[0] = self->movedir[0] * self->speed;
550 	other->velocity[1] = self->movedir[1] * self->speed;
551 
552 	other->groundentity = NULL;
553 	other->velocity[2] = self->movedir[2];
554 
555 	//play a sound
556 	gi.sound (other, CHAN_AUTO, gi.soundindex("world/button2.wav"), 1, ATTN_NORM, 0);
557 	self->nextthink = level.time + .1;
558 }
559 
SP_trigger_monsterjump(edict_t * self)560 void SP_trigger_monsterjump (edict_t *self)
561 {
562 	if (!self->speed)
563 		self->speed = 200;
564 	if (!st.height)
565 		st.height = 200;
566 	if (self->s.angles[YAW] == 0)
567 		self->s.angles[YAW] = 360;
568 	InitTrigger (self);
569 	self->touch = trigger_monsterjump_touch;
570 	self->movedir[2] = st.height;
571 	self->think = multi_wait;
572 }
573 
574 //trigger_deathballtarget - a "goal" used for scoring in deathball
deathballtarget_use(edict_t * self,edict_t * other,edict_t * activator)575 void deathballtarget_use (edict_t *self, edict_t *other, edict_t *activator)
576 {
577 	if (self->solid == SOLID_NOT)
578 		self->solid = SOLID_TRIGGER;
579 	else
580 		self->solid = SOLID_NOT;
581 	gi.linkentity (self);
582 
583 	if (!(self->spawnflags & 2))
584 		self->use = NULL;
585 }
586 
587 
deathballtarget_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)588 void deathballtarget_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
589 {
590 
591 	if (self->timestamp > level.time)
592 		return;
593 
594 	self->timestamp = level.time + FRAMETIME;
595 
596 	if(strcmp(other->classname, "item_deathball") == 0) {
597 
598 		if (!(dmflags->integer & DF_SKINTEAMS))
599 			other->owner->client->resp.score += 10;
600 
601 		if ((dmflags->integer & DF_SKINTEAMS)) {
602 			if(other->owner->dmteam == RED_TEAM && strcmp(self->classname, "trigger_bluedeathballtarget") == 0) {
603 				red_team_score+=10;
604 				other->owner->client->resp.score += 10;
605 			}
606 			else if(other->owner->dmteam == BLUE_TEAM && strcmp(self->classname, "trigger_reddeathballtarget") == 0) {
607 				blue_team_score+=10;
608 				other->owner->client->resp.score += 10;
609 			}
610 			else
611 				return; //shot at wrong goal in a team game, loser!
612 		}
613 
614 		//send an effect
615 		gi.WriteByte (svc_temp_entity);
616 		gi.WriteByte (TE_BFG_BIGEXPLOSION);
617 		gi.WritePosition (other->s.origin);
618 		gi.multicast (other->s.origin, MULTICAST_PHS);
619 		gi.sound (other, CHAN_AUTO, gi.soundindex("misc/db_score.wav"), 1, ATTN_NONE, 0);
620 		ResetDeathball();
621 	}
622 }
623 
SP_trigger_deathballtarget(edict_t * self)624 void SP_trigger_deathballtarget (edict_t *self)
625 {
626 	InitTrigger (self);
627 
628 	self->touch = deathballtarget_touch;
629 
630 	if (self->spawnflags & 1)
631 		self->solid = SOLID_NOT;
632 	else
633 		self->solid = SOLID_TRIGGER;
634 
635 	if (self->spawnflags & 2)
636 		self->use = deathballtarget_use;
637 
638 	gi.linkentity (self);
639 }
640 
SP_trigger_reddeathballtarget(edict_t * self)641 void SP_trigger_reddeathballtarget (edict_t *self)
642 {
643 	InitTrigger (self);
644 
645 	self->touch = deathballtarget_touch;
646 
647 	if (self->spawnflags & 1)
648 		self->solid = SOLID_NOT;
649 	else
650 		self->solid = SOLID_TRIGGER;
651 
652 	if (self->spawnflags & 2)
653 		self->use = deathballtarget_use;
654 
655 	gi.linkentity (self);
656 }
657 
SP_trigger_bluedeathballtarget(edict_t * self)658 void SP_trigger_bluedeathballtarget (edict_t *self)
659 {
660 	InitTrigger (self);
661 
662 	self->touch = deathballtarget_touch;
663 
664 	if (self->spawnflags & 1)
665 		self->solid = SOLID_NOT;
666 	else
667 		self->solid = SOLID_TRIGGER;
668 
669 	if (self->spawnflags & 2)
670 		self->use = deathballtarget_use;
671 
672 	gi.linkentity (self);
673 }
674 
cowtarget_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)675 void cowtarget_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
676 {
677 
678 	if (self->timestamp > level.time)
679 		return;
680 
681 	self->timestamp = level.time + FRAMETIME;
682 
683 	if(strcmp(other->classname, "cow") == 0) {
684 
685 
686 		if(strcmp(self->classname, "trigger_bluecowtarget") == 0)
687 			blue_team_score++;
688 		if(strcmp(self->classname, "trigger_redcowtarget") == 0)
689 			red_team_score++;
690 
691 		//send an effect
692 		gi.WriteByte (svc_temp_entity);
693 		gi.WriteByte (TE_BFG_BIGEXPLOSION);
694 		gi.WritePosition (other->s.origin);
695 		gi.multicast (other->s.origin, MULTICAST_PHS);
696 		gi.sound (other, CHAN_AUTO, gi.soundindex("misc/db_score.wav"), 1, ATTN_NONE, 0);
697 
698 		//get rid of the cow, it's been beamed into the void....(back to pasture)
699 		other->health = other->max_health;
700 		other->s.event = EV_PLAYER_TELEPORT;
701 		VectorCopy(other->s.spawn_pos, other->s.origin);
702 
703 		//reward the player who was controlling the cow
704 		if(other->enemy)
705 			other->enemy->client->resp.score += 10;
706 	}
707 }
708 
SP_trigger_redcowtarget(edict_t * self)709 void SP_trigger_redcowtarget (edict_t *self)
710 {
711 	InitTrigger(self);
712 
713 	self->solid = SOLID_TRIGGER;
714 
715 	self->touch = cowtarget_touch;
716 
717 	gi.linkentity (self);
718 }
719 
SP_trigger_bluecowtarget(edict_t * self)720 void SP_trigger_bluecowtarget (edict_t *self)
721 {
722 	InitTrigger(self);
723 
724 	self->solid = SOLID_TRIGGER;
725 
726 	self->touch = cowtarget_touch;
727 
728 	gi.linkentity (self);
729 }
730