3 float RUNE_STRENGTH = 1;
4 float RUNE_DEFENSE = 2;
7 float RUNE_VAMPIRE = 16;
10 float CURSE_FIRST = 8192;
11 float CURSE_WEAK = 8192;
12 float CURSE_VULNER = 16384;
13 float CURSE_VENOM = 32768;
14 float CURSE_SLOW = 65536;
15 float CURSE_EMPATHY = 131072;
16 float CURSE_LAST = 131072;
21 Rune: When you damage enemies, you have a slight chance of instant-killing them (porportional to damage dealt / their health)
22 Curse: When you are damaged, you have a chance of being instant-killed
25 Rune: The lower your health below 100, the more damage you deal (does not decrease your damage if you're above 100)
26 Curse: The higher your health (up to 100), the less damage you deal (at 100 hp deal 1/5th damage)
30 /*QUAKED runematch_spawn_point (1 0 0) (-16 -16 -24) (16 16 24)
31 spawn point for runes in runematch
34 void runematch_spawn_point()
36 if(!cvar("g_runematch"))
42 setorigin(self, find_floor(self.origin) + '0 0 35');
45 string RuneName(float r)
47 if(r == RUNE_STRENGTH)
48 return "^1Strength^7";
52 return "^2Vitality^7";
59 return "^1Weakness^7";
61 return "^4Vulnerability^7";
66 if(r == CURSE_EMPATHY)
68 return strcat("^8[unnamed", ftos(r), "]^7");
71 vector RuneColormod(float r)
74 if(r == RUNE_STRENGTH)
77 _color = '0 0 255';//'0 102 255';//
79 _color = '0 204 0';//'0 255 0';
81 _color = 0.35*'185 185 0';//255 230 0';//'255 255 0';
83 _color = '64 0 128';//'108 0 217';//'128 0 255';//'179 0 204';//
88 _color = '0 0 255';//'0 102 255';//
90 _color = '0 204 0';//'0 255 0';
92 _color = 0.5*'185 185 0';//'255 255 0';
93 if(r == CURSE_EMPATHY)
94 _color = '179 0 204';//'128 0 255';
96 return _color * (1 / 255) * cvar("g_runematch_rune_color_strength");
99 float count_rune_spawnpoints()
104 e = findchain(classname, "runematch_spawn_point");
114 entity rune_find_spawnpoint(float num, float r)
120 e = find(e, classname, "runematch_spawn_point");
122 e = find(e, classname, "runematch_spawn_point");
128 return e; // emergency: prevent crash
131 if(e.owner != world)//e.wait > time) // already taken
147 void RuneCarriedThink()
153 if(self.owner.classname != "player")
159 self.nextthink = time + 0.1;
161 // count runes my owner holds
163 rune = find(world, classname, "rune");
166 if(rune.owner == self.owner)
170 rune = find(rune, classname, "rune");
173 ang_y = rnum*(360 / rcount) + math_mod(time, 360)*45;//180;
177 //setorigin(self, v_forward*32);
178 self.view_ofs = v_forward*32;
183 if(other.classname != "player" || other.health < 2)
186 return; // "notouch" time isn't finished
188 // detach from the spawn point you're on
189 if(self.owner.classname == "runematch_spawn_point")
191 self.owner.owner = world;
196 self.enemy.owner = other;
197 //setattachment(self, other, "");
198 setattachment(self, world, "");
200 self.movetype = MOVETYPE_FOLLOW;
202 self.view_ofs = other.origin;
204 setorigin(self, '0 0 0');
205 other.runes = other.runes | self.runes | self.enemy.runes;
207 //self.think = SUB_Null;
208 //self.nextthink = 0;
209 self.think = RuneCarriedThink;
210 self.nextthink = time;
211 self.touch = SUB_Null;
213 self.solid = SOLID_NOT;
214 setorigin(self, self.origin);
216 //sprint(other, strcat("^3You have picked up ",
217 // RuneName(self.runes & (RUNE_LAST*2-1)), " and "));
218 //sprint(other, strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"));
220 bprint(strcat("^3", other.netname, "^7 has picked up ",
221 RuneName(self.runes & (RUNE_LAST*2-1)), "^7 and "));
222 bprint(strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"));
229 num = count_rune_spawnpoints();
230 r = ceil(random()*num);
232 if(self.owner.classname == "runematch_spawn_point")
234 self.owner.owner = world;
239 spot = rune_find_spawnpoint(num, r);
242 bprint("Warning: couldn't find spawn spot for rune respawn\n");
246 self.solid = SOLID_TRIGGER;
248 setorigin(self, spot.origin);
252 self.touch = rune_touch;
254 self.think = rune_respawn;
255 self.nextthink = time + cvar("g_runematch_shuffletime");//30 + random()*5; // fixme: cvar
258 entity FindRune(entity own, string clname, float r)
268 rune = find(rune, classname, clname);
270 rune = find(rune, classname, clname);
273 if(rune.owner == own)
287 void DropRune(entity pl, entity e)
292 // detach from player
293 setattachment(e, world, "");
295 e.enemy.owner = world;
296 // don't instantly touch player again
297 e.wait = time + 1; // "notouch" time
298 e.movetype = MOVETYPE_TOSS;
299 e.solid = SOLID_TRIGGER;
300 // reposition itself if not picked up soon
301 e.think = rune_respawn;
302 e.nextthink = time + cvar("g_runematch_respawntime");//15 + random()*5; // fixme: cvar
303 e.touch = rune_touch;
305 pl.runes = pl.runes - (pl.runes & (e.runes | e.enemy.runes));
308 setorigin(e, pl.origin + '0 0 10');
309 e.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
312 bprint(strcat("^3", pl.netname, "^7 has lost ",
313 RuneName(e.runes & (RUNE_LAST*2-1)), "^7 and "));
314 bprint(strcat(RuneName(e.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"));
317 float RuneMatchesCurse(float r, float c)
320 if(r & RUNE_STRENGTH)
322 else if(r & RUNE_DEFENSE)
324 else if(r & RUNE_REGEN)
326 else if(r & RUNE_SPEED)
328 else if(r & RUNE_VAMPIRE)
330 else return FALSE; // fixme: error?
337 // player died, drop runes
338 // each rune should pair up with a random curse and then be tossed from the player
339 void DropAllRunes(entity pl)
342 float rcount, ccount, r, c, rand, prevent_same, numtodrop, tries;
344 entity c1, r1, c2, r2;
346 rune = curse = world;
347 rcount = ccount = r = c = 0;
348 rune = find(rune, classname, "rune");
353 rune = find(rune, classname, "rune");
355 curse = find(curse, classname, "curse");
358 if(curse.owner == pl)
360 curse = find(curse, classname, "curse");
363 numtodrop = cvar("g_runematch_drop_runes_max");
364 prevent_same = !cvar("g_runematch_allow_same");
366 rune = curse = world;
369 rune = find(rune, classname, "rune");
376 // find a random curse
378 if(ccount > 1 && prevent_same)
380 // avoid pairing runes and curses that match each other
382 rand = ceil(random()*ccount);
383 curse = FindRune(pl, "curse", rand);
385 }while(RuneMatchesCurse(rune.runes, curse.runes) && tries > 0);
388 bprint("warning: couldn't prevent same rune\n");
393 rand = ceil(random()*ccount);
394 curse = FindRune(pl, "curse", rand);
398 error("Couldn't fine curse to bind rune to\n");
400 // pair rune and curse
407 if(r1 != r2) // not already attached to each other
411 setattachment(c1, r1, "");
414 setattachment(c2, r2, "");
416 //ccount = ccount - 1;
417 //rcount = rcount - 1;
423 r1.think = rune_respawn;
427 numtodrop = numtodrop - 1;
435 void spawn_default_runespawnpoints()
438 spot = find(world, classname, "info_player_deathmatch");
442 e.classname = "runematch_spawn_point";
443 e.origin = spot.origin;
444 spot = find(spot, classname, "info_player_deathmatch");
450 float r, num, max_num, rn, cs, numrunes, runes_left, curses_left, tries, prevent_same;
456 // fixme: instead of placing them all now, why not
457 // simply create them all and let them call rune_respawn() as their think?
459 runes_left = RUNE_STRENGTH | RUNE_DEFENSE | RUNE_REGEN | RUNE_SPEED | RUNE_VAMPIRE;
460 curses_left = CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY;
462 max_num = num = count_rune_spawnpoints();
466 spawn_default_runespawnpoints();
469 prevent_same = !cvar("g_runematch_allow_same");
471 max_num = num = count_rune_spawnpoints();
474 error(strcat("not enough spawn points for runematch, need ", ftos(numrunes), " but found ", ftos(num), "\n"));
478 r = ceil(random()*numrunes);
490 if(curses_left > 1 && prevent_same)
493 // avoid pairing runes and curses that match each other
495 r = ceil(random()*numrunes);
507 }while(RuneMatchesCurse(rn, cs) && tries > 0);
510 bprint("warning: couldn't prevent same rune\n");
515 r = ceil(random()*numrunes);
533 r = ceil(random()*num*1.25);
535 spot = rune_find_spawnpoint(num, r);
539 error("failed to find runematch spawnpoint!\n");
542 // choose and spawn rune
544 /* //rn = RUNE_FIRST;
545 while(!runes_left & rn && rn <= RUNE_LAST)
548 error("couldn't select rune\n");
549 runes_left = runes_left - rn;
552 while(!curses_left & cs && cs <= CURSE_LAST)
555 error("couldn't select rune\n");
556 curses_left = curses_left - cs;
558 while(!runes_left & rn)
564 runes_left = runes_left - rn;
566 while(!curses_left & cs)
572 curses_left = curses_left - cs;
576 e.classname = "rune";
577 e.touch = rune_touch;
578 e.think = rune_respawn;
579 e.nextthink = time + random();
580 e.movetype = MOVETYPE_TOSS;
581 e.solid = SOLID_TRIGGER;
583 setmodel(e, "models/runematch/rune.mdl");
584 setorigin(e, spot.origin);
585 setsize(e, '0 0 -35', '0 0 0');
589 e.enemy.classname = "curse";
591 //e.enemy.avelocity = '300 500 200';
592 setmodel(e.enemy, "models/runematch/curse.mdl");
593 setorigin(e, '0 0 0');
594 setattachment(e.enemy, e, "");
597 e.colormod = RuneColormod(rn);
598 e.enemy.colormod = RuneColormod(cs);
600 e.alpha = e.enemy.alpha = cvar("g_runematch_rune_alpha");//0.78;
601 e.effects = e.enemy.effects = cvar("g_runematch_rune_effects");//EF_ADDITIVE;// | EF_FULLBRIGHT;
603 // Savage: Save some bandwidth
604 self.effects |= EF_LOWPRECISION;
606 //e.glow_size = e.enemy.glow_size = cvar("g_runematch_rune_glow_size");
607 //e.glow_color = e.enemy.glow_color = cvar("g_runematch_rune_glow_color");
609 // this spot is taken
617 numrunes = numrunes - 1;
622 void runematch_init()
624 if(!cvar("g_runematch"))
629 e.think = spawn_runes;
630 e.nextthink = time + 0.1;
634 float runematch_point_time;
636 // give points to players who are holding runes
637 void RuneMatchGivePoints()
641 if(!cvar("g_runematch") || !cvar("g_runematch_pointamt"))
647 if(runematch_point_time > time)
650 runematch_point_time = time + cvar("g_runematch_pointrate");
655 rune = find(rune, classname, "rune");
659 if(rune.owner.classname == "player")
661 rune.owner.frags = rune.owner.frags + cvar("g_runematch_pointamt");
666 float RunematchHandleFrags(entity attacker, entity targ, float f)
669 float arunes, trunes, newfrags;
678 head = find(world, classname, "rune");
681 if(head.owner == attacker)
685 else if(head.owner == targ)
690 head = find(head, classname, "rune");
693 if(!arunes && !trunes)
694 return f - 1 + cvar("g_runematch_frags_norune"); // don't give points to players when no runes are involved.
697 { // got a kill while holding runes
698 newfrags = newfrags + cvar("g_runematch_frags_killedby_runeholder");//5;
701 { // killed an enemy holding runes
702 newfrags = newfrags + cvar("g_runematch_frags_killed_runeholder");//5;
705 f = f - 1 + newfrags;