|
|
1.1 root 1: void() W_SetCurrentAmmo;
2: /* ALL LIGHTS SHOULD BE 0 1 0 IN COLOR ALL OTHER ITEMS SHOULD
3: BE .8 .3 .4 IN COLOR */
4:
5:
6: void() SUB_regen =
7: {
8: self.model = self.mdl; // restore original model
9: self.solid = SOLID_TRIGGER; // allow it to be touched again
10: sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM); // play respawn sound
11: setorigin (self, self.origin);
12: };
13:
14:
15:
16: /*QUAKED noclass (0 0 0) (-8 -8 -8) (8 8 8)
17: prints a warning message when spawned
18: */
19: void() noclass =
20: {
21: dprint ("noclass spawned at");
22: dprint (vtos(self.origin));
23: dprint ("\n");
24: remove (self);
25: };
26:
27: void() q_touch;
28:
29: void() q_touch =
30: {
31: local entity stemp;
32: local float best;
33: local string s;
34:
35: if (other.classname != "player")
36: return;
37: if (other.health <= 0)
38: return;
39:
40: self.mdl = self.model;
41:
42: sound (other, CHAN_VOICE, self.noise, 1, ATTN_NORM);
43: stuffcmd (other, "bf\n");
44: self.solid = SOLID_NOT;
45: other.items = other.items | IT_QUAD;
46: self.model = string_null;
47: if (deathmatch == 4)
48: {
49: other.armortype = 0;
50: other.armorvalue = 0 * 0.01;
51: other.ammo_cells = 0;
52: }
53:
54: // do the apropriate action
55: other.super_time = 1;
56: other.super_damage_finished = self.cnt;
57:
58: s=ftos(rint(other.super_damage_finished - time));
59:
60: bprint (PRINT_LOW, other.netname);
61: if (deathmatch == 4)
62: bprint (PRINT_LOW, " recovered an OctaPower with ");
63: else
64: bprint (PRINT_LOW, " recovered a Quad with ");
65: bprint (PRINT_LOW, s);
66: bprint (PRINT_LOW, " seconds remaining!\n");
67:
68: activator = other;
69: SUB_UseTargets(); // fire all targets / killtargets
70: };
71:
72:
73: void(float timeleft) DropQuad =
74: {
75: local entity item;
76:
77: item = spawn();
78: item.origin = self.origin;
79:
80: item.velocity_z = 300;
81: item.velocity_x = -100 + (random() * 200);
82: item.velocity_y = -100 + (random() * 200);
83:
84: item.flags = FL_ITEM;
85: item.solid = SOLID_TRIGGER;
86: item.movetype = MOVETYPE_TOSS;
87: item.noise = "items/damage.wav";
88: setmodel (item, "progs/quaddama.mdl");
89: setsize (item, '-16 -16 -24', '16 16 32');
90: item.cnt = time + timeleft;
91: item.touch = q_touch;
92: item.nextthink = time + timeleft; // remove it with the time left on it
93: item.think = SUB_Remove;
94: };
95:
96:
97: void() r_touch;
98:
99: void() r_touch =
100: {
101: local entity stemp;
102: local float best;
103: local string s;
104:
105: if (other.classname != "player")
106: return;
107: if (other.health <= 0)
108: return;
109:
110: self.mdl = self.model;
111:
112: sound (other, CHAN_VOICE, self.noise, 1, ATTN_NORM);
113: stuffcmd (other, "bf\n");
114: self.solid = SOLID_NOT;
115: other.items = other.items | IT_INVISIBILITY;
116: self.model = string_null;
117:
118: // do the apropriate action
119: other.invisible_time = 1;
120: other.invisible_finished = self.cnt;
121: s=ftos(rint(other.invisible_finished - time));
122: bprint (PRINT_LOW, other.netname);
123: bprint (PRINT_LOW, " recovered a Ring with ");
124: bprint (PRINT_LOW, s);
125: bprint (PRINT_LOW, " seconds remaining!\n");
126:
127:
128: activator = other;
129: SUB_UseTargets(); // fire all targets / killtargets
130: };
131:
132:
133: void(float timeleft) DropRing =
134: {
135: local entity item;
136:
137: item = spawn();
138: item.origin = self.origin;
139:
140: item.velocity_z = 300;
141: item.velocity_x = -100 + (random() * 200);
142: item.velocity_y = -100 + (random() * 200);
143:
144: item.flags = FL_ITEM;
145: item.solid = SOLID_TRIGGER;
146: item.movetype = MOVETYPE_TOSS;
147: item.noise = "items/inv1.wav";
148: setmodel (item, "progs/invisibl.mdl");
149: setsize (item, '-16 -16 -24', '16 16 32');
150: item.cnt = time + timeleft;
151: item.touch = r_touch;
152: item.nextthink = time + timeleft; // remove after 30 seconds
153: item.think = SUB_Remove;
154: };
155:
156: /*
157: ============
158: PlaceItem
159:
160: plants the object on the floor
161: ============
162: */
163: void() PlaceItem =
164: {
165: local float oldz;
166:
167: self.mdl = self.model; // so it can be restored on respawn
168: self.flags = FL_ITEM; // make extra wide
169: self.solid = SOLID_TRIGGER;
170: self.movetype = MOVETYPE_TOSS;
171: self.velocity = '0 0 0';
172: self.origin_z = self.origin_z + 6;
173: oldz = self.origin_z;
174: if (!droptofloor())
175: {
176: dprint ("Bonus item fell out of level at ");
177: dprint (vtos(self.origin));
178: dprint ("\n");
179: remove(self);
180: return;
181: }
182: };
183:
184: /*
185: ============
186: StartItem
187:
188: Sets the clipping size and plants the object on the floor
189: ============
190: */
191: void() StartItem =
192: {
193: self.nextthink = time + 0.2; // items start after other solids
194: self.think = PlaceItem;
195: };
196:
197: /*
198: =========================================================================
199:
200: HEALTH BOX
201:
202: =========================================================================
203: */
204: //
205: // T_Heal: add health to an entity, limiting health to max_health
206: // "ignore" will ignore max_health limit
207: //
208: float (entity e, float healamount, float ignore) T_Heal =
209: {
210: if (e.health <= 0)
211: return 0;
212: if ((!ignore) && (e.health >= other.max_health))
213: return 0;
214: healamount = ceil(healamount);
215:
216: e.health = e.health + healamount;
217: if ((!ignore) && (e.health >= other.max_health))
218: e.health = other.max_health;
219:
220: if (e.health > 250)
221: e.health = 250;
222: return 1;
223: };
224:
225: /*QUAKED item_health (.3 .3 1) (0 0 0) (32 32 32) rotten megahealth
226: Health box. Normally gives 25 points.
227: Rotten box heals 5-10 points,
228: megahealth will add 100 health, then
229: rot you down to your maximum health limit,
230: one point per second.
231: */
232:
233: float H_ROTTEN = 1;
234: float H_MEGA = 2;
235: .float healamount, healtype;
236: void() health_touch;
237: void() item_megahealth_rot;
238:
239: void() item_health =
240: {
241: self.touch = health_touch;
242:
243: if (self.spawnflags & H_ROTTEN)
244: {
245: precache_model("maps/b_bh10.bsp");
246:
247: precache_sound("items/r_item1.wav");
248: setmodel(self, "maps/b_bh10.bsp");
249: self.noise = "items/r_item1.wav";
250: self.healamount = 15;
251: self.healtype = 0;
252: }
253: else
254: if (self.spawnflags & H_MEGA)
255: {
256: precache_model("maps/b_bh100.bsp");
257: precache_sound("items/r_item2.wav");
258: setmodel(self, "maps/b_bh100.bsp");
259: self.noise = "items/r_item2.wav";
260: self.healamount = 100;
261: self.healtype = 2;
262: }
263: else
264: {
265: precache_model("maps/b_bh25.bsp");
266: precache_sound("items/health1.wav");
267: setmodel(self, "maps/b_bh25.bsp");
268: self.noise = "items/health1.wav";
269: self.healamount = 25;
270: self.healtype = 1;
271: }
272: setsize (self, '0 0 0', '32 32 56');
273: StartItem ();
274: };
275:
276:
277: void() health_touch =
278: {
279: local float amount;
280: local string s;
281:
282: if (deathmatch == 4)
283: if (other.invincible_time > 0)
284: return;
285:
286: if (other.classname != "player")
287: return;
288:
289: if (self.healtype == 2) // Megahealth? Ignore max_health...
290: {
291: if (other.health >= 250)
292: return;
293: if (!T_Heal(other, self.healamount, 1))
294: return;
295: }
296: else
297: {
298: if (!T_Heal(other, self.healamount, 0))
299: return;
300: }
301:
302: sprint(other, PRINT_LOW, "You receive ");
303: s = ftos(self.healamount);
304: sprint(other, PRINT_LOW, s);
305: sprint(other, PRINT_LOW, " health\n");
306:
307: // health touch sound
308: sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
309:
310: stuffcmd (other, "bf\n");
311:
312: self.model = string_null;
313: self.solid = SOLID_NOT;
314:
315: // Megahealth = rot down the player's super health
316: if (self.healtype == 2)
317: {
318: other.items = other.items | IT_SUPERHEALTH;
319: if (deathmatch != 4)
320: {
321: self.nextthink = time + 5;
322: self.think = item_megahealth_rot;
323: }
324: self.owner = other;
325: }
326: else
327: {
328: if (deathmatch != 2) // deathmatch 2 is the silly old rules
329: {
330: self.nextthink = time + 20;
331: self.think = SUB_regen;
332: }
333: }
334:
335: activator = other;
336: SUB_UseTargets(); // fire all targets / killtargets
337: };
338:
339: void() item_megahealth_rot =
340: {
341: other = self.owner;
342:
343: if (other.health > other.max_health)
344: {
345: other.health = other.health - 1;
346: self.nextthink = time + 1;
347: return;
348: }
349:
350: // it is possible for a player to die and respawn between rots, so don't
351: // just blindly subtract the flag off
352: other.items = other.items - (other.items & IT_SUPERHEALTH);
353:
354: if (deathmatch != 2) // deathmatch 2 is silly old rules
355: {
356: self.nextthink = time + 20;
357: self.think = SUB_regen;
358: }
359: };
360:
361: /*
362: ===============================================================================
363:
364: ARMOR
365:
366: ===============================================================================
367: */
368:
369: void() armor_touch;
370:
371: void() armor_touch =
372: {
373: local float type, value, bit;
374:
375: if (other.health <= 0)
376: return;
377: if (other.classname != "player")
378: return;
379:
380: if (deathmatch == 4)
381: if (other.invincible_time > 0)
382: return;
383:
384: if (self.classname == "item_armor1")
385: {
386: type = 0.3;
387: value = 100;
388: bit = IT_ARMOR1;
389: }
390: if (self.classname == "item_armor2")
391: {
392: type = 0.6;
393: value = 150;
394: bit = IT_ARMOR2;
395: }
396: if (self.classname == "item_armorInv")
397: {
398: type = 0.8;
399: value = 200;
400: bit = IT_ARMOR3;
401: }
402: if (other.armortype*other.armorvalue >= type*value)
403: return;
404:
405: other.armortype = type;
406: other.armorvalue = value;
407: other.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + bit;
408:
409: self.solid = SOLID_NOT;
410: self.model = string_null;
411: if (deathmatch != 2)
412: self.nextthink = time + 20;
413: self.think = SUB_regen;
414:
415: sprint(other, PRINT_LOW, "You got armor\n");
416: // armor touch sound
417: sound(other, CHAN_ITEM, "items/armor1.wav", 1, ATTN_NORM);
418: stuffcmd (other, "bf\n");
419:
420: activator = other;
421: SUB_UseTargets(); // fire all targets / killtargets
422: };
423:
424:
425: /*QUAKED item_armor1 (0 .5 .8) (-16 -16 0) (16 16 32)
426: */
427:
428: void() item_armor1 =
429: {
430: self.touch = armor_touch;
431: precache_model ("progs/armor.mdl");
432: setmodel (self, "progs/armor.mdl");
433: self.skin = 0;
434: setsize (self, '-16 -16 0', '16 16 56');
435: StartItem ();
436: };
437:
438: /*QUAKED item_armor2 (0 .5 .8) (-16 -16 0) (16 16 32)
439: */
440:
441: void() item_armor2 =
442: {
443: self.touch = armor_touch;
444: precache_model ("progs/armor.mdl");
445: setmodel (self, "progs/armor.mdl");
446: self.skin = 1;
447: setsize (self, '-16 -16 0', '16 16 56');
448: StartItem ();
449: };
450:
451: /*QUAKED item_armorInv (0 .5 .8) (-16 -16 0) (16 16 32)
452: */
453:
454: void() item_armorInv =
455: {
456: self.touch = armor_touch;
457: precache_model ("progs/armor.mdl");
458: setmodel (self, "progs/armor.mdl");
459: self.skin = 2;
460: setsize (self, '-16 -16 0', '16 16 56');
461: StartItem ();
462: };
463:
464: /*
465: ===============================================================================
466:
467: WEAPONS
468:
469: ===============================================================================
470: */
471:
472: void() bound_other_ammo =
473: {
474: if (other.ammo_shells > 100)
475: other.ammo_shells = 100;
476: if (other.ammo_nails > 200)
477: other.ammo_nails = 200;
478: if (other.ammo_rockets > 100)
479: other.ammo_rockets = 100;
480: if (other.ammo_cells > 100)
481: other.ammo_cells = 100;
482: };
483:
484:
485: float(float w) RankForWeapon =
486: {
487: if (w == IT_LIGHTNING)
488: return 1;
489: if (w == IT_ROCKET_LAUNCHER)
490: return 2;
491: if (w == IT_SUPER_NAILGUN)
492: return 3;
493: if (w == IT_GRENADE_LAUNCHER)
494: return 4;
495: if (w == IT_SUPER_SHOTGUN)
496: return 5;
497: if (w == IT_NAILGUN)
498: return 6;
499: return 7;
500: };
501:
502: float (float w) WeaponCode =
503: {
504: if (w == IT_SUPER_SHOTGUN)
505: return 3;
506: if (w == IT_NAILGUN)
507: return 4;
508: if (w == IT_SUPER_NAILGUN)
509: return 5;
510: if (w == IT_GRENADE_LAUNCHER)
511: return 6;
512: if (w == IT_ROCKET_LAUNCHER)
513: return 7;
514: if (w == IT_LIGHTNING)
515: return 8;
516: return 1;
517: };
518:
519: /*
520: =============
521: Deathmatch_Weapon
522:
523: Deathmatch weapon change rules for picking up a weapon
524:
525: .float ammo_shells, ammo_nails, ammo_rockets, ammo_cells;
526: =============
527: */
528: void(float old, float new) Deathmatch_Weapon =
529: {
530: local float or, nr;
531:
532: // change self.weapon if desired
533: or = RankForWeapon (self.weapon);
534: nr = RankForWeapon (new);
535: if ( nr < or )
536: self.weapon = new;
537: };
538:
539: /*
540: =============
541: weapon_touch
542: =============
543: */
544: float() W_BestWeapon;
545:
546: void() weapon_touch =
547: {
548: local float hadammo, best, new, old;
549: local entity stemp;
550: local float leave;
551:
552: // For client weapon_switch
553: local float w_switch;
554:
555: if (!(other.flags & FL_CLIENT))
556: return;
557:
558: if ((stof(infokey(other,"w_switch"))) == 0)
559: w_switch = 8;
560: else
561: w_switch = stof(infokey(other,"w_switch"));
562:
563: // if the player was using his best weapon, change up to the new one if better
564: stemp = self;
565: self = other;
566: best = W_BestWeapon();
567: self = stemp;
568:
569: if (deathmatch == 2 || deathmatch == 3 || deathmatch == 5)
570: leave = 1;
571: else
572: leave = 0;
573:
574: if (self.classname == "weapon_nailgun")
575: {
576: if (leave && (other.items & IT_NAILGUN) )
577: return;
578: hadammo = other.ammo_nails;
579: new = IT_NAILGUN;
580: other.ammo_nails = other.ammo_nails + 30;
581: }
582: else if (self.classname == "weapon_supernailgun")
583: {
584: if (leave && (other.items & IT_SUPER_NAILGUN) )
585: return;
586: hadammo = other.ammo_rockets;
587: new = IT_SUPER_NAILGUN;
588: other.ammo_nails = other.ammo_nails + 30;
589: }
590: else if (self.classname == "weapon_supershotgun")
591: {
592: if (leave && (other.items & IT_SUPER_SHOTGUN) )
593: return;
594: hadammo = other.ammo_rockets;
595: new = IT_SUPER_SHOTGUN;
596: other.ammo_shells = other.ammo_shells + 5;
597: }
598: else if (self.classname == "weapon_rocketlauncher")
599: {
600: if (leave && (other.items & IT_ROCKET_LAUNCHER) )
601: return;
602: hadammo = other.ammo_rockets;
603: new = IT_ROCKET_LAUNCHER;
604: other.ammo_rockets = other.ammo_rockets + 5;
605: }
606: else if (self.classname == "weapon_grenadelauncher")
607: {
608: if (leave && (other.items & IT_GRENADE_LAUNCHER) )
609: return;
610: hadammo = other.ammo_rockets;
611: new = IT_GRENADE_LAUNCHER;
612: other.ammo_rockets = other.ammo_rockets + 5;
613: }
614: else if (self.classname == "weapon_lightning")
615: {
616: if (leave && (other.items & IT_LIGHTNING))
617: return;
618: hadammo = other.ammo_rockets;
619: new = IT_LIGHTNING;
620: other.ammo_cells = other.ammo_cells + 15;
621: }
622: else
623: objerror ("weapon_touch: unknown classname");
624:
625: sprint (other, PRINT_LOW, "You got the ");
626: sprint (other, PRINT_LOW, self.netname);
627: sprint (other, PRINT_LOW, "\n");
628: // weapon touch sound
629: sound (other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM);
630: stuffcmd (other, "bf\n");
631:
632: bound_other_ammo ();
633:
634: // change to the weapon
635: old = other.items;
636: other.items = other.items | new;
637:
638: stemp = self;
639: self = other;
640:
641: if ( WeaponCode(new) <= w_switch )
642: {
643: if (self.flags & FL_INWATER)
644: {
645: if (new != IT_LIGHTNING)
646: {
647: Deathmatch_Weapon (old, new);
648: }
649: }
650: else
651: {
652: Deathmatch_Weapon (old, new);
653: }
654: }
655:
656: W_SetCurrentAmmo();
657:
658: self = stemp;
659:
660: if (leave)
661: return;
662:
663: if (deathmatch!=3 || deathmatch !=5)
664: {
665: // remove it in single player, or setup for respawning in deathmatch
666: self.model = string_null;
667: self.solid = SOLID_NOT;
668: if (deathmatch != 2)
669: self.nextthink = time + 30;
670: self.think = SUB_regen;
671: }
672: activator = other;
673: SUB_UseTargets(); // fire all targets / killtargets
674: };
675:
676:
677: /*QUAKED weapon_supershotgun (0 .5 .8) (-16 -16 0) (16 16 32)
678: */
679:
680: void() weapon_supershotgun =
681: {
682: if (deathmatch <= 3)
683: {
684: precache_model ("progs/g_shot.mdl");
685: setmodel (self, "progs/g_shot.mdl");
686: self.weapon = IT_SUPER_SHOTGUN;
687: self.netname = "Double-barrelled Shotgun";
688: self.touch = weapon_touch;
689: setsize (self, '-16 -16 0', '16 16 56');
690: StartItem ();
691: }
692: };
693:
694: /*QUAKED weapon_nailgun (0 .5 .8) (-16 -16 0) (16 16 32)
695: */
696:
697: void() weapon_nailgun =
698: {
699: if (deathmatch <= 3)
700: {
701: precache_model ("progs/g_nail.mdl");
702: setmodel (self, "progs/g_nail.mdl");
703: self.weapon = IT_NAILGUN;
704: self.netname = "nailgun";
705: self.touch = weapon_touch;
706: setsize (self, '-16 -16 0', '16 16 56');
707: StartItem ();
708: }
709: };
710:
711: /*QUAKED weapon_supernailgun (0 .5 .8) (-16 -16 0) (16 16 32)
712: */
713:
714: void() weapon_supernailgun =
715: {
716: if (deathmatch <= 3)
717: {
718: precache_model ("progs/g_nail2.mdl");
719: setmodel (self, "progs/g_nail2.mdl");
720: self.weapon = IT_SUPER_NAILGUN;
721: self.netname = "Super Nailgun";
722: self.touch = weapon_touch;
723: setsize (self, '-16 -16 0', '16 16 56');
724: StartItem ();
725: }
726: };
727:
728: /*QUAKED weapon_grenadelauncher (0 .5 .8) (-16 -16 0) (16 16 32)
729: */
730:
731: void() weapon_grenadelauncher =
732: {
733: if (deathmatch <= 3)
734: {
735: precache_model ("progs/g_rock.mdl");
736: setmodel (self, "progs/g_rock.mdl");
737: self.weapon = 3;
738: self.netname = "Grenade Launcher";
739: self.touch = weapon_touch;
740: setsize (self, '-16 -16 0', '16 16 56');
741: StartItem ();
742: }
743: };
744:
745: /*QUAKED weapon_rocketlauncher (0 .5 .8) (-16 -16 0) (16 16 32)
746: */
747:
748: void() weapon_rocketlauncher =
749: {
750: if (deathmatch <= 3)
751: {
752: precache_model ("progs/g_rock2.mdl");
753: setmodel (self, "progs/g_rock2.mdl");
754: self.weapon = 3;
755: self.netname = "Rocket Launcher";
756: self.touch = weapon_touch;
757: setsize (self, '-16 -16 0', '16 16 56');
758: StartItem ();
759: }
760: };
761:
762:
763: /*QUAKED weapon_lightning (0 .5 .8) (-16 -16 0) (16 16 32)
764: */
765:
766: void() weapon_lightning =
767: {
768: if (deathmatch <= 3)
769: {
770: precache_model ("progs/g_light.mdl");
771: setmodel (self, "progs/g_light.mdl");
772: self.weapon = 3;
773: self.netname = "Thunderbolt";
774: self.touch = weapon_touch;
775: setsize (self, '-16 -16 0', '16 16 56');
776: StartItem ();
777: }
778: };
779:
780:
781: /*
782: ===============================================================================
783:
784: AMMO
785:
786: ===============================================================================
787: */
788:
789: void() ammo_touch =
790: {
791: local entity stemp;
792: local float best;
793:
794: if (other.classname != "player")
795: return;
796: if (other.health <= 0)
797: return;
798:
799: // if the player was using his best weapon, change up to the new one if better
800: stemp = self;
801: self = other;
802: best = W_BestWeapon();
803: self = stemp;
804:
805:
806: // shotgun
807: if (self.weapon == 1)
808: {
809: if (other.ammo_shells >= 100)
810: return;
811: other.ammo_shells = other.ammo_shells + self.aflag;
812: }
813:
814: // spikes
815: if (self.weapon == 2)
816: {
817: if (other.ammo_nails >= 200)
818: return;
819: other.ammo_nails = other.ammo_nails + self.aflag;
820: }
821:
822: // rockets
823: if (self.weapon == 3)
824: {
825: if (other.ammo_rockets >= 100)
826: return;
827: other.ammo_rockets = other.ammo_rockets + self.aflag;
828: }
829:
830: // cells
831: if (self.weapon == 4)
832: {
833: if (other.ammo_cells >= 100)
834: return;
835: other.ammo_cells = other.ammo_cells + self.aflag;
836: }
837:
838: bound_other_ammo ();
839:
840: sprint (other, PRINT_LOW, "You got the ");
841: sprint (other, PRINT_LOW, self.netname);
842: sprint (other, PRINT_LOW, "\n");
843: // ammo touch sound
844: sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM);
845: stuffcmd (other, "bf\n");
846:
847: // change to a better weapon if appropriate
848:
849: if ( other.weapon == best )
850: {
851: stemp = self;
852: self = other;
853: self.weapon = W_BestWeapon();
854: W_SetCurrentAmmo ();
855: self = stemp;
856: }
857:
858: // if changed current ammo, update it
859: stemp = self;
860: self = other;
861: W_SetCurrentAmmo();
862: self = stemp;
863:
864: // remove it in single player, or setup for respawning in deathmatch
865: self.model = string_null;
866: self.solid = SOLID_NOT;
867: if (deathmatch != 2)
868: self.nextthink = time + 30;
869:
870: // Xian -- If playing in DM 3.0 mode, halve the time ammo respawns
871:
872: if (deathmatch == 3 || deathmatch == 5)
873: self.nextthink = time + 15;
874:
875: self.think = SUB_regen;
876:
877: activator = other;
878: SUB_UseTargets(); // fire all targets / killtargets
879: };
880:
881:
882:
883:
884: float WEAPON_BIG2 = 1;
885:
886: /*QUAKED item_shells (0 .5 .8) (0 0 0) (32 32 32) big
887: */
888:
889: void() item_shells =
890: {
891: if (deathmatch == 4)
892: return;
893:
894: self.touch = ammo_touch;
895:
896: if (self.spawnflags & WEAPON_BIG2)
897: {
898: precache_model ("maps/b_shell1.bsp");
899: setmodel (self, "maps/b_shell1.bsp");
900: self.aflag = 40;
901: }
902: else
903: {
904: precache_model ("maps/b_shell0.bsp");
905: setmodel (self, "maps/b_shell0.bsp");
906: self.aflag = 20;
907: }
908: self.weapon = 1;
909: self.netname = "shells";
910: setsize (self, '0 0 0', '32 32 56');
911: StartItem ();
912: };
913:
914: /*QUAKED item_spikes (0 .5 .8) (0 0 0) (32 32 32) big
915: */
916:
917: void() item_spikes =
918: {
919: if (deathmatch == 4)
920: return;
921:
922: self.touch = ammo_touch;
923:
924: if (self.spawnflags & WEAPON_BIG2)
925: {
926: precache_model ("maps/b_nail1.bsp");
927: setmodel (self, "maps/b_nail1.bsp");
928: self.aflag = 50;
929: }
930: else
931: {
932: precache_model ("maps/b_nail0.bsp");
933: setmodel (self, "maps/b_nail0.bsp");
934: self.aflag = 25;
935: }
936: self.weapon = 2;
937: self.netname = "nails";
938: setsize (self, '0 0 0', '32 32 56');
939: StartItem ();
940:
941: };
942:
943: /*QUAKED item_rockets (0 .5 .8) (0 0 0) (32 32 32) big
944: */
945:
946: void() item_rockets =
947: {
948: if (deathmatch == 4)
949: return;
950:
951: self.touch = ammo_touch;
952:
953: if (self.spawnflags & WEAPON_BIG2)
954: {
955: precache_model ("maps/b_rock1.bsp");
956: setmodel (self, "maps/b_rock1.bsp");
957: self.aflag = 10;
958: }
959: else
960: {
961: precache_model ("maps/b_rock0.bsp");
962: setmodel (self, "maps/b_rock0.bsp");
963: self.aflag = 5;
964: }
965: self.weapon = 3;
966: self.netname = "rockets";
967: setsize (self, '0 0 0', '32 32 56');
968: StartItem ();
969:
970: };
971:
972:
973: /*QUAKED item_cells (0 .5 .8) (0 0 0) (32 32 32) big
974: */
975:
976: void() item_cells =
977: {
978: if (deathmatch == 4)
979: return;
980:
981: self.touch = ammo_touch;
982:
983: if (self.spawnflags & WEAPON_BIG2)
984: {
985: precache_model ("maps/b_batt1.bsp");
986: setmodel (self, "maps/b_batt1.bsp");
987: self.aflag = 12;
988: }
989: else
990: {
991: precache_model ("maps/b_batt0.bsp");
992: setmodel (self, "maps/b_batt0.bsp");
993: self.aflag = 6;
994: }
995: self.weapon = 4;
996: self.netname = "cells";
997: setsize (self, '0 0 0', '32 32 56');
998: StartItem ();
999:
1000: };
1001:
1002:
1003: /*QUAKED item_weapon (0 .5 .8) (0 0 0) (32 32 32) shotgun rocket spikes big
1004: DO NOT USE THIS!!!! IT WILL BE REMOVED!
1005: */
1006:
1007: float WEAPON_SHOTGUN = 1;
1008: float WEAPON_ROCKET = 2;
1009: float WEAPON_SPIKES = 4;
1010: float WEAPON_BIG = 8;
1011: void() item_weapon =
1012: {
1013: self.touch = ammo_touch;
1014:
1015: if (self.spawnflags & WEAPON_SHOTGUN)
1016: {
1017: if (self.spawnflags & WEAPON_BIG)
1018: {
1019: precache_model ("maps/b_shell1.bsp");
1020: setmodel (self, "maps/b_shell1.bsp");
1021: self.aflag = 40;
1022: }
1023: else
1024: {
1025: precache_model ("maps/b_shell0.bsp");
1026: setmodel (self, "maps/b_shell0.bsp");
1027: self.aflag = 20;
1028: }
1029: self.weapon = 1;
1030: self.netname = "shells";
1031: }
1032:
1033: if (self.spawnflags & WEAPON_SPIKES)
1034: {
1035: if (self.spawnflags & WEAPON_BIG)
1036: {
1037: precache_model ("maps/b_nail1.bsp");
1038: setmodel (self, "maps/b_nail1.bsp");
1039: self.aflag = 40;
1040: }
1041: else
1042: {
1043: precache_model ("maps/b_nail0.bsp");
1044: setmodel (self, "maps/b_nail0.bsp");
1045: self.aflag = 20;
1046: }
1047: self.weapon = 2;
1048: self.netname = "spikes";
1049: }
1050:
1051: if (self.spawnflags & WEAPON_ROCKET)
1052: {
1053: if (self.spawnflags & WEAPON_BIG)
1054: {
1055: precache_model ("maps/b_rock1.bsp");
1056: setmodel (self, "maps/b_rock1.bsp");
1057: self.aflag = 10;
1058: }
1059: else
1060: {
1061: precache_model ("maps/b_rock0.bsp");
1062: setmodel (self, "maps/b_rock0.bsp");
1063: self.aflag = 5;
1064: }
1065: self.weapon = 3;
1066: self.netname = "rockets";
1067: }
1068:
1069: setsize (self, '0 0 0', '32 32 56');
1070: StartItem ();
1071: };
1072:
1073:
1074: /*
1075: ===============================================================================
1076:
1077: KEYS
1078:
1079: ===============================================================================
1080: */
1081:
1082: void() key_touch =
1083: {
1084: local entity stemp;
1085: local float best;
1086:
1087: if (other.classname != "player")
1088: return;
1089: if (other.health <= 0)
1090: return;
1091: if (other.items & self.items)
1092: return;
1093:
1094: sprint (other, PRINT_LOW, "You got the ");
1095: sprint (other, PRINT_LOW, self.netname);
1096: sprint (other,PRINT_LOW, "\n");
1097:
1098: sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
1099: stuffcmd (other, "bf\n");
1100: other.items = other.items | self.items;
1101:
1102: self.solid = SOLID_NOT;
1103: self.model = string_null;
1104:
1105: activator = other;
1106: SUB_UseTargets(); // fire all targets / killtargets
1107: };
1108:
1109:
1110: void() key_setsounds =
1111: {
1112: if (world.worldtype == 0)
1113: {
1114: precache_sound ("misc/medkey.wav");
1115: self.noise = "misc/medkey.wav";
1116: }
1117: if (world.worldtype == 1)
1118: {
1119: precache_sound ("misc/runekey.wav");
1120: self.noise = "misc/runekey.wav";
1121: }
1122: if (world.worldtype == 2)
1123: {
1124: precache_sound2 ("misc/basekey.wav");
1125: self.noise = "misc/basekey.wav";
1126: }
1127: };
1128:
1129: /*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32)
1130: SILVER key
1131: In order for keys to work
1132: you MUST set your maps
1133: worldtype to one of the
1134: following:
1135: 0: medieval
1136: 1: metal
1137: 2: base
1138: */
1139:
1140: void() item_key1 =
1141: {
1142: if (world.worldtype == 0)
1143: {
1144: precache_model ("progs/w_s_key.mdl");
1145: setmodel (self, "progs/w_s_key.mdl");
1146: self.netname = "silver key";
1147: }
1148: else if (world.worldtype == 1)
1149: {
1150: precache_model ("progs/m_s_key.mdl");
1151: setmodel (self, "progs/m_s_key.mdl");
1152: self.netname = "silver runekey";
1153: }
1154: else if (world.worldtype == 2)
1155: {
1156: precache_model2 ("progs/b_s_key.mdl");
1157: setmodel (self, "progs/b_s_key.mdl");
1158: self.netname = "silver keycard";
1159: }
1160: key_setsounds();
1161: self.touch = key_touch;
1162: self.items = IT_KEY1;
1163: setsize (self, '-16 -16 -24', '16 16 32');
1164: StartItem ();
1165: };
1166:
1167: /*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32)
1168: GOLD key
1169: In order for keys to work
1170: you MUST set your maps
1171: worldtype to one of the
1172: following:
1173: 0: medieval
1174: 1: metal
1175: 2: base
1176: */
1177:
1178: void() item_key2 =
1179: {
1180: if (world.worldtype == 0)
1181: {
1182: precache_model ("progs/w_g_key.mdl");
1183: setmodel (self, "progs/w_g_key.mdl");
1184: self.netname = "gold key";
1185: }
1186: if (world.worldtype == 1)
1187: {
1188: precache_model ("progs/m_g_key.mdl");
1189: setmodel (self, "progs/m_g_key.mdl");
1190: self.netname = "gold runekey";
1191: }
1192: if (world.worldtype == 2)
1193: {
1194: precache_model2 ("progs/b_g_key.mdl");
1195: setmodel (self, "progs/b_g_key.mdl");
1196: self.netname = "gold keycard";
1197: }
1198: key_setsounds();
1199: self.touch = key_touch;
1200: self.items = IT_KEY2;
1201: setsize (self, '-16 -16 -24', '16 16 32');
1202: StartItem ();
1203: };
1204:
1205:
1206:
1207: /*
1208: ===============================================================================
1209:
1210: END OF LEVEL RUNES
1211:
1212: ===============================================================================
1213: */
1214:
1215: void() sigil_touch =
1216: {
1217: local entity stemp;
1218: local float best;
1219:
1220: if (other.classname != "player")
1221: return;
1222: if (other.health <= 0)
1223: return;
1224:
1225: centerprint (other, "You got the rune!");
1226:
1227: sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
1228: stuffcmd (other, "bf\n");
1229: self.solid = SOLID_NOT;
1230: self.model = string_null;
1231: serverflags = serverflags | (self.spawnflags & 15);
1232: self.classname = ""; // so rune doors won't find it
1233:
1234: activator = other;
1235: SUB_UseTargets(); // fire all targets / killtargets
1236: };
1237:
1238:
1239: /*QUAKED item_sigil (0 .5 .8) (-16 -16 -24) (16 16 32) E1 E2 E3 E4
1240: End of level sigil, pick up to end episode and return to jrstart.
1241: */
1242:
1243: void() item_sigil =
1244: {
1245: if (!self.spawnflags)
1246: objerror ("no spawnflags");
1247:
1248: precache_sound ("misc/runekey.wav");
1249: self.noise = "misc/runekey.wav";
1250:
1251: if (self.spawnflags & 1)
1252: {
1253: precache_model ("progs/end1.mdl");
1254: setmodel (self, "progs/end1.mdl");
1255: }
1256: if (self.spawnflags & 2)
1257: {
1258: precache_model2 ("progs/end2.mdl");
1259: setmodel (self, "progs/end2.mdl");
1260: }
1261: if (self.spawnflags & 4)
1262: {
1263: precache_model2 ("progs/end3.mdl");
1264: setmodel (self, "progs/end3.mdl");
1265: }
1266: if (self.spawnflags & 8)
1267: {
1268: precache_model2 ("progs/end4.mdl");
1269: setmodel (self, "progs/end4.mdl");
1270: }
1271:
1272: self.touch = sigil_touch;
1273: setsize (self, '-16 -16 -24', '16 16 32');
1274: StartItem ();
1275: };
1276:
1277: /*
1278: ===============================================================================
1279:
1280: POWERUPS
1281:
1282: ===============================================================================
1283: */
1284:
1285: void() powerup_touch;
1286:
1287:
1288: void() powerup_touch =
1289: {
1290: local entity stemp;
1291: local float best;
1292:
1293: if (other.classname != "player")
1294: return;
1295: if (other.health <= 0)
1296: return;
1297:
1298: sprint (other, PRINT_LOW, "You got the ");
1299: sprint (other,PRINT_LOW, self.netname);
1300: sprint (other,PRINT_LOW, "\n");
1301:
1302: self.mdl = self.model;
1303:
1304: if ((self.classname == "item_artifact_invulnerability") ||
1305: (self.classname == "item_artifact_invisibility"))
1306: self.nextthink = time + 60*5;
1307: else
1308: self.nextthink = time + 60;
1309:
1310: self.think = SUB_regen;
1311:
1312: sound (other, CHAN_VOICE, self.noise, 1, ATTN_NORM);
1313: stuffcmd (other, "bf\n");
1314: self.solid = SOLID_NOT;
1315: other.items = other.items | self.items;
1316: self.model = string_null;
1317:
1318: // do the apropriate action
1319: if (self.classname == "item_artifact_envirosuit")
1320: {
1321: other.rad_time = 1;
1322: other.radsuit_finished = time + 30;
1323: }
1324:
1325: if (self.classname == "item_artifact_invulnerability")
1326: {
1327: other.invincible_time = 1;
1328: other.invincible_finished = time + 30;
1329: }
1330:
1331: if (self.classname == "item_artifact_invisibility")
1332: {
1333: other.invisible_time = 1;
1334: other.invisible_finished = time + 30;
1335: }
1336:
1337: if (self.classname == "item_artifact_super_damage")
1338: {
1339: if (deathmatch == 4)
1340: {
1341: other.armortype = 0;
1342: other.armorvalue = 0 * 0.01;
1343: other.ammo_cells = 0;
1344: }
1345: other.super_time = 1;
1346: other.super_damage_finished = time + 30;
1347: }
1348:
1349: activator = other;
1350: SUB_UseTargets(); // fire all targets / killtargets
1351: };
1352:
1353:
1354:
1355: /*QUAKED item_artifact_invulnerability (0 .5 .8) (-16 -16 -24) (16 16 32)
1356: Player is invulnerable for 30 seconds
1357: */
1358: void() item_artifact_invulnerability =
1359: {
1360: self.touch = powerup_touch;
1361:
1362: precache_model ("progs/invulner.mdl");
1363: precache_sound ("items/protect.wav");
1364: precache_sound ("items/protect2.wav");
1365: precache_sound ("items/protect3.wav");
1366: self.noise = "items/protect.wav";
1367: setmodel (self, "progs/invulner.mdl");
1368: self.netname = "Pentagram of Protection";
1369: self.effects = self.effects | EF_RED;
1370: self.items = IT_INVULNERABILITY;
1371: setsize (self, '-16 -16 -24', '16 16 32');
1372: StartItem ();
1373: };
1374:
1375: /*QUAKED item_artifact_envirosuit (0 .5 .8) (-16 -16 -24) (16 16 32)
1376: Player takes no damage from water or slime for 30 seconds
1377: */
1378: void() item_artifact_envirosuit =
1379: {
1380: self.touch = powerup_touch;
1381:
1382: precache_model ("progs/suit.mdl");
1383: precache_sound ("items/suit.wav");
1384: precache_sound ("items/suit2.wav");
1385: self.noise = "items/suit.wav";
1386: setmodel (self, "progs/suit.mdl");
1387: self.netname = "Biosuit";
1388: self.items = IT_SUIT;
1389: setsize (self, '-16 -16 -24', '16 16 32');
1390: StartItem ();
1391: };
1392:
1393:
1394: /*QUAKED item_artifact_invisibility (0 .5 .8) (-16 -16 -24) (16 16 32)
1395: Player is invisible for 30 seconds
1396: */
1397: void() item_artifact_invisibility =
1398: {
1399: self.touch = powerup_touch;
1400:
1401: precache_model ("progs/invisibl.mdl");
1402: precache_sound ("items/inv1.wav");
1403: precache_sound ("items/inv2.wav");
1404: precache_sound ("items/inv3.wav");
1405: self.noise = "items/inv1.wav";
1406: setmodel (self, "progs/invisibl.mdl");
1407: self.netname = "Ring of Shadows";
1408: self.items = IT_INVISIBILITY;
1409: setsize (self, '-16 -16 -24', '16 16 32');
1410: StartItem ();
1411: };
1412:
1413:
1414: /*QUAKED item_artifact_super_damage (0 .5 .8) (-16 -16 -24) (16 16 32)
1415: The next attack from the player will do 4x damage
1416: */
1417: void() item_artifact_super_damage =
1418: {
1419: self.touch = powerup_touch;
1420:
1421: precache_model ("progs/quaddama.mdl");
1422: precache_sound ("items/damage.wav");
1423: precache_sound ("items/damage2.wav");
1424: precache_sound ("items/damage3.wav");
1425: self.noise = "items/damage.wav";
1426: setmodel (self, "progs/quaddama.mdl");
1427: if (deathmatch == 4)
1428: self.netname = "OctaPower";
1429: else
1430: self.netname = "Quad Damage";
1431: self.items = IT_QUAD;
1432: self.effects = self.effects | EF_BLUE;
1433: setsize (self, '-16 -16 -24', '16 16 32');
1434: StartItem ();
1435: };
1436:
1437:
1438:
1439: /*
1440: ===============================================================================
1441:
1442: PLAYER BACKPACKS
1443:
1444: ===============================================================================
1445: */
1446:
1447: void() BackpackTouch =
1448: {
1449: local string s;
1450: local float best, old, new;
1451: local entity stemp;
1452: local float acount;
1453: local float b_switch;
1454:
1455: if (deathmatch == 4)
1456: if (other.invincible_time > 0)
1457: return;
1458:
1459: if ((stof(infokey(other,"b_switch"))) == 0)
1460: b_switch = 8;
1461: else
1462: b_switch = stof(infokey(other,"b_switch"));
1463:
1464:
1465: if (other.classname != "player")
1466: return;
1467: if (other.health <= 0)
1468: return;
1469:
1470: acount = 0;
1471: sprint (other, PRINT_LOW, "You get ");
1472:
1473: if (deathmatch == 4)
1474: {
1475: other.health = other.health + 10;
1476: sprint (other, PRINT_LOW, "10 additional health\n");
1477: if ((other.health > 250) && (other.health < 300))
1478: sound (other, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
1479: else
1480: sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM);
1481: stuffcmd (other, "bf\n");
1482: remove(self);
1483:
1484: if (other.health >299)
1485: {
1486: if (other.invincible_time != 1)
1487: {
1488: other.invincible_time = 1;
1489: other.invincible_finished = time + 30;
1490: other.items = other.items | IT_INVULNERABILITY;
1491:
1492: other.super_time = 1;
1493: other.super_damage_finished = time + 30;
1494: other.items = other.items | IT_QUAD;
1495:
1496: other.ammo_cells = 0;
1497:
1498:
1499: sound (other, CHAN_VOICE, "boss1/sight1.wav", 1, ATTN_NORM);
1500: stuffcmd (other, "bf\n");
1501: bprint (PRINT_HIGH, other.netname);
1502: bprint (PRINT_HIGH, " attains bonus powers!!!\n");
1503: }
1504: }
1505: self = other;
1506: return;
1507: }
1508: if (self.items)
1509: if ((other.items & self.items) == 0)
1510: {
1511: acount = 1;
1512: sprint (other, PRINT_LOW, "the ");
1513: sprint (other, PRINT_LOW, self.netname);
1514: }
1515:
1516: // if the player was using his best weapon, change up to the new one if better
1517: stemp = self;
1518: self = other;
1519: best = W_BestWeapon();
1520: self = stemp;
1521:
1522: // change weapons
1523: other.ammo_shells = other.ammo_shells + self.ammo_shells;
1524: other.ammo_nails = other.ammo_nails + self.ammo_nails;
1525: other.ammo_rockets = other.ammo_rockets + self.ammo_rockets;
1526: other.ammo_cells = other.ammo_cells + self.ammo_cells;
1527:
1528: new = self.items;
1529: if (!new)
1530: new = other.weapon;
1531: old = other.items;
1532: other.items = other.items | self.items;
1533:
1534: bound_other_ammo ();
1535:
1536: if (self.ammo_shells)
1537: {
1538: if (acount)
1539: sprint(other, PRINT_LOW, ", ");
1540: acount = 1;
1541: s = ftos(self.ammo_shells);
1542: sprint (other, PRINT_LOW, s);
1543: sprint (other, PRINT_LOW, " shells");
1544: }
1545: if (self.ammo_nails)
1546: {
1547: if (acount)
1548: sprint(other, PRINT_LOW, ", ");
1549: acount = 1;
1550: s = ftos(self.ammo_nails);
1551: sprint (other, PRINT_LOW, s);
1552: sprint (other, PRINT_LOW, " nails");
1553: }
1554: if (self.ammo_rockets)
1555: {
1556: if (acount)
1557: sprint(other, PRINT_LOW, ", ");
1558: acount = 1;
1559: s = ftos(self.ammo_rockets);
1560: sprint (other, PRINT_LOW, s);
1561: sprint (other, PRINT_LOW, " rockets");
1562: }
1563: if (self.ammo_cells)
1564: {
1565: if (acount)
1566: sprint(other, PRINT_LOW, ", ");
1567: acount = 1;
1568: s = ftos(self.ammo_cells);
1569: sprint (other, PRINT_LOW, s);
1570: sprint (other,PRINT_LOW, " cells");
1571: }
1572:
1573: if ( (deathmatch==3 || deathmatch == 5) & ( (WeaponCode(new)==6) || (WeaponCode(new)==7) ) & (other.ammo_rockets < 5) )
1574: other.ammo_rockets = 5;
1575:
1576: sprint (other, PRINT_LOW, "\n");
1577: // backpack touch sound
1578: sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM);
1579: stuffcmd (other, "bf\n");
1580:
1581: remove(self);
1582: self = other;
1583:
1584: // change to the weapon
1585:
1586:
1587: if ( WeaponCode(new) <= b_switch )
1588: {
1589: if (self.flags & FL_INWATER)
1590: {
1591: if (new != IT_LIGHTNING)
1592: {
1593: Deathmatch_Weapon (old, new);
1594: }
1595: }
1596: else
1597: {
1598: Deathmatch_Weapon (old, new);
1599: }
1600: }
1601:
1602: W_SetCurrentAmmo ();
1603: };
1604:
1605: /*
1606: ===============
1607: DropBackpack
1608: ===============
1609: */
1610: void() DropBackpack =
1611: {
1612: local entity item;
1613:
1614: if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells))
1615: return; // nothing in it
1616:
1617: item = spawn();
1618: item.origin = self.origin - '0 0 24';
1619:
1620: item.items = self.weapon;
1621: if (item.items == IT_AXE)
1622: item.netname = "Axe";
1623: else if (item.items == IT_SHOTGUN)
1624: item.netname = "Shotgun";
1625: else if (item.items == IT_SUPER_SHOTGUN)
1626: item.netname = "Double-barrelled Shotgun";
1627: else if (item.items == IT_NAILGUN)
1628: item.netname = "Nailgun";
1629: else if (item.items == IT_SUPER_NAILGUN)
1630: item.netname = "Super Nailgun";
1631: else if (item.items == IT_GRENADE_LAUNCHER)
1632: item.netname = "Grenade Launcher";
1633: else if (item.items == IT_ROCKET_LAUNCHER)
1634: item.netname = "Rocket Launcher";
1635: else if (item.items == IT_LIGHTNING)
1636: item.netname = "Thunderbolt";
1637: else
1638: item.netname = "";
1639:
1640: item.ammo_shells = self.ammo_shells;
1641: item.ammo_nails = self.ammo_nails;
1642: item.ammo_rockets = self.ammo_rockets;
1643: item.ammo_cells = self.ammo_cells;
1644:
1645: item.velocity_z = 300;
1646: item.velocity_x = -100 + (random() * 200);
1647: item.velocity_y = -100 + (random() * 200);
1648:
1649: item.flags = FL_ITEM;
1650: item.solid = SOLID_TRIGGER;
1651: item.movetype = MOVETYPE_TOSS;
1652: setmodel (item, "progs/backpack.mdl");
1653: setsize (item, '-16 -16 0', '16 16 56');
1654: item.touch = BackpackTouch;
1655:
1656: item.nextthink = time + 120; // remove after 2 minutes
1657: item.think = SUB_Remove;
1658: };
1659:
1660:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.