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 spawnfunc_runematch_spawn_point (1 0 0) (-16 -16 -24) (16 16 24)
31 spawn point for runes in runematch
34 void spawnfunc_runematch_spawn_point()
42 setsize(self, '0 0 -35', '0 0 0');
46 string RuneName(float r)
48 if(r == RUNE_STRENGTH)
49 return "^1Strength^7";
53 return "^2Vitality^7";
60 return "^1Weakness^7";
62 return "^4Vulnerability^7";
67 if(r == CURSE_EMPATHY)
69 return strcat("^8[unnamed", ftos(r), "]^7");
72 vector RuneColormod(float r)
75 if(r == RUNE_STRENGTH)
78 _color = '0 0 255';//'0 102 255';//
80 _color = '0 204 0';//'0 255 0';
82 _color = 0.35*'185 185 0';//255 230 0';//'255 255 0';
84 _color = '64 0 128';//'108 0 217';//'128 0 255';//'179 0 204';//
89 _color = '0 0 255';//'0 102 255';//
91 _color = '0 204 0';//'0 255 0';
93 _color = 0.5*'185 185 0';//'255 255 0';
94 if(r == CURSE_EMPATHY)
95 _color = '179 0 204';//'128 0 255';
97 return _color * (1 / 255) * cvar("g_runematch_rune_color_strength");
100 float count_rune_spawnpoints()
105 e = findchain(classname, "runematch_spawn_point");
115 entity rune_find_spawnpoint(float num, float r)
121 e = find(e, classname, "runematch_spawn_point");
123 e = find(e, classname, "runematch_spawn_point");
129 return e; // emergency: prevent crash
132 if(e.owner != world)//e.wait > time) // already taken
148 void RuneCarriedThink()
154 if(self.owner.classname != "player" || time < game_starttime)
160 self.nextthink = time + 0.1;
162 // count runes my owner holds
164 rune = find(world, classname, "rune");
167 if(rune.owner == self.owner)
171 rune = find(rune, classname, "rune");
174 ang_y = rnum*(360 / rcount) + mod(time, 360)*45;//180;
178 setorigin(self, v_forward*32);
183 if(other.classname != "player" || other.health < 1)
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, "");
199 other.runes = other.runes | self.runes | self.enemy.runes;
201 //self.think = SUB_Null;
202 //self.nextthink = 0;
203 self.think = RuneCarriedThink;
204 self.nextthink = time;
205 self.touch = SUB_Null;
207 self.solid = SOLID_NOT;
208 setorigin(self, self.origin);
210 //sprint(other, strcat("^3You have picked up ",
211 // RuneName(self.runes & (RUNE_LAST*2-1)), " and "));
212 //sprint(other, strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"));
214 bprint("^3", other.netname, "^7 has picked up ",
215 RuneName(self.runes & (RUNE_LAST*2-1)), "^7 and ");
216 bprint(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
223 num = count_rune_spawnpoints();
224 r = floor(random()*num) + 1;
226 if(self.owner.classname == "runematch_spawn_point")
228 self.owner.owner = world;
233 spot = rune_find_spawnpoint(num, r);
236 bprint("Warning: couldn't find spawn spot for rune respawn\n");
240 self.solid = SOLID_TRIGGER;
242 setorigin(self, spot.origin);
246 self.touch = rune_touch;
248 self.think = rune_respawn;
249 self.nextthink = time + cvar("g_runematch_shuffletime");//30 + random()*5; // fixme: cvar
252 entity FindRune(entity own, string clname, float r)
262 rune = find(rune, classname, clname);
264 rune = find(rune, classname, clname);
267 if(rune.owner == own)
281 void DropRune(entity pl, entity e)
286 // detach from player
287 setattachment(e, world, "");
289 e.enemy.owner = world;
290 // don't instantly touch player again
291 e.wait = time + 1; // "notouch" time
292 e.movetype = MOVETYPE_TOSS;
293 e.solid = SOLID_TRIGGER;
294 // reposition itself if not picked up soon
295 e.think = rune_respawn;
296 e.nextthink = time + cvar("g_runematch_respawntime");//15 + random()*5; // fixme: cvar
297 e.touch = rune_touch;
299 pl.runes = pl.runes - (pl.runes & (e.runes | e.enemy.runes));
302 setorigin(e, pl.origin + '0 0 10');
303 e.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
306 bprint("^3", pl.netname, "^7 has lost ",
307 RuneName(e.runes & (RUNE_LAST*2-1)), "^7 and ");
308 bprint(RuneName(e.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
311 float RuneMatchesCurse(float r, float c)
314 if(r & RUNE_STRENGTH)
316 else if(r & RUNE_DEFENSE)
318 else if(r & RUNE_REGEN)
320 else if(r & RUNE_SPEED)
322 else if(r & RUNE_VAMPIRE)
324 else return FALSE; // fixme: error?
331 // player died, drop runes
332 // each rune should pair up with a random curse and then be tossed from the player
333 void DropAllRunes(entity pl)
336 float rcount, ccount, r, c, rand, prevent_same, numtodrop, tries;
338 entity curse1, rune1, curse2, rune2;
340 rune = curse = world;
341 rcount = ccount = r = c = 0;
342 rune = find(rune, classname, "rune");
347 rune = find(rune, classname, "rune");
349 curse = find(curse, classname, "curse");
352 if(curse.owner == pl)
354 curse = find(curse, classname, "curse");
357 numtodrop = cvar("g_runematch_drop_runes_max");
358 prevent_same = !cvar("g_runematch_allow_same");
360 rune = curse = world;
363 rune = find(rune, classname, "rune");
370 // find a random curse
372 if(ccount > 1 && prevent_same)
374 // avoid pairing runes and curses that match each other
376 rand = floor(random()*ccount) + 1;
377 curse = FindRune(pl, "curse", rand);
379 }while(RuneMatchesCurse(rune.runes, curse.runes) && tries > 0);
382 bprint("warning: couldn't prevent same rune\n");
387 rand = floor(random()*ccount) + 1;
388 curse = FindRune(pl, "curse", rand);
392 error("Couldn't fine curse to bind rune to\n");
394 // pair rune and curse
398 rune2 = curse1.enemy;
399 curse2 = rune1.enemy;
401 if(rune1 != rune2) // not already attached to each other
403 rune1.enemy = curse1;
404 curse1.enemy = rune1;
405 setattachment(curse1, rune1, "");
406 rune2.enemy = curse2;
407 curse2.enemy = rune2;
408 setattachment(curse2, rune2, "");
409 //DropRune(pl, rune2);
410 //ccount = ccount - 1;
411 //rcount = rcount - 1;
417 rune1.think = rune_respawn;
418 rune1.nextthink = time;
421 numtodrop = numtodrop - 1;
429 void spawn_default_runespawnpoints()
432 spot = find(world, classname, "info_player_deathmatch");
436 e.classname = "runematch_spawn_point";
437 e.origin = spot.origin;
438 spot = find(spot, classname, "info_player_deathmatch");
445 if(self.owner.classname != "runematch_spawn_point")
446 DropAllRunes(self.owner);
452 float r, num, max_num, rn, cs, numrunes, runes_left, curses_left, tries, prevent_same;
458 // fixme: instead of placing them all now, why not
459 // simply create them all and let them call rune_respawn() as their think?
461 runes_left = RUNE_STRENGTH | RUNE_DEFENSE | RUNE_REGEN | RUNE_SPEED | RUNE_VAMPIRE;
462 curses_left = CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY;
464 max_num = num = count_rune_spawnpoints();
468 spawn_default_runespawnpoints();
471 prevent_same = !cvar("g_runematch_allow_same");
473 max_num = num = count_rune_spawnpoints();
476 error(strcat("not enough spawn points for runematch, need ", ftos(numrunes), " but found ", ftos(num), "\n"));
480 r = floor(random()*numrunes) + 1;
492 if(curses_left > 1 && prevent_same)
495 // avoid pairing runes and curses that match each other
497 r = floor(random()*numrunes) + 1;
509 }while(RuneMatchesCurse(rn, cs) && tries > 0);
512 bprint("warning: couldn't prevent same rune\n");
517 r = floor(random()*numrunes) + 1;
535 r = floor(random()*num*1.25) + 1;
537 spot = rune_find_spawnpoint(num, r);
541 error("failed to find runematch spawnpoint!\n");
544 // choose and spawn rune
546 /* //rn = RUNE_FIRST;
547 while(!runes_left & rn && rn <= RUNE_LAST)
550 error("couldn't select rune\n");
551 runes_left = runes_left - rn;
554 while(!curses_left & cs && cs <= CURSE_LAST)
557 error("couldn't select rune\n");
558 curses_left = curses_left - cs;
560 while(!runes_left & rn)
566 runes_left = runes_left - rn;
568 while(!curses_left & cs)
574 curses_left = curses_left - cs;
578 e.classname = "rune";
579 e.touch = rune_touch;
580 e.think = rune_respawn;
581 e.nextthink = time + random();
582 e.movetype = MOVETYPE_TOSS;
583 e.solid = SOLID_TRIGGER;
585 e.reset = rune_reset;
586 setmodel(e, "models/runematch/rune.mdl"); // precision set below
587 setorigin(e, spot.origin);
588 setsize(e, '0 0 -35', '0 0 0');
592 e.enemy.classname = "curse";
594 //e.enemy.avelocity = '300 500 200';
595 setmodel(e.enemy, "models/runematch/curse.mdl"); // precision set below
596 setorigin(e, '0 0 0');
597 setattachment(e.enemy, e, "");
600 e.colormod = RuneColormod(rn);
601 e.enemy.colormod = RuneColormod(cs);
603 e.alpha = e.enemy.alpha = cvar("g_runematch_rune_alpha");//0.78;
604 e.effects = e.enemy.effects = cvar("g_runematch_rune_effects") | EF_LOWPRECISION;//EF_ADDITIVE;// | EF_FULLBRIGHT;
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()
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(!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 UpdateFrags(rune.owner, 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;