]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/spawner.qc
Merge branch 'master' into mario/monsters
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / spawner.qc
1 // size
2 const vector SPAWNER_MIN = '-35 -35 -10';
3 const vector SPAWNER_MAX = '35 35 70';
4
5 // cvars
6 float autocvar_g_monster_spawner;
7 float autocvar_g_monster_spawner_health;
8 float autocvar_g_monster_spawner_maxmobs;
9 string autocvar_g_monster_spawner_forcespawn;
10
11 void() spawner_think;
12
13 void spawnmonsters ()
14 {
15         if(self.spawner_monstercount >= autocvar_g_monster_spawner_maxmobs || self.frozen || self.freezetag_frozen)
16                 return;
17                 
18         vector p1, p2, p3, p4, chosenposi;
19         float r = random();
20         string type = "";
21         entity e;
22         
23         self.spawner_monstercount += 1;
24         
25         if(self.spawnmob != "")
26                 type = self.spawnmob;
27                 
28         if(autocvar_g_monster_spawner_forcespawn != "")
29                 type = autocvar_g_monster_spawner_forcespawn;
30                 
31         if(type == "" || type == "spawner") // spawner spawning spawners?!
32                 type = "knight";
33         
34         p1 = self.origin - '0 70 -50' * self.scale;
35         p2 = self.origin + '0 70 50' * self.scale;
36         p3 = self.origin - '70 0 -50' * self.scale;
37         p4 = self.origin + '70 0 -50' * self.scale;
38            
39         if (r < 0.20)
40                 chosenposi = p1;
41         else if (r < 0.50)
42                 chosenposi = p2;
43         else if (r < 80)
44                 chosenposi = p3;
45         else
46                 chosenposi = p4;
47
48         e = spawnmonster(type, self, self, chosenposi, FALSE, MONSTER_MOVE_WANDER);
49         
50         if(teamplay && autocvar_g_monsters_teams)
51                 e.team = self.team;
52         
53         if(self.spawnflags & MONSTERFLAG_GIANT)
54                 e.spawnflags = MONSTERFLAG_GIANT;
55                 
56         if(self.flags & MONSTERFLAG_MINIBOSS)
57                 e.spawnflags = MONSTERFLAG_MINIBOSS;
58 }
59
60 void spawner_die () 
61 {
62         setmodel(self, "");
63         pointparticles(particleeffectnum(((self.scale > 3) ? "explosion_big" : "explosion_medium")), self.origin, '0 0 0', 1);
64         sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
65         
66         self.solid                      = SOLID_NOT;
67         self.takedamage         = DAMAGE_NO;
68         self.event_damage   = func_null;
69         self.enemy                      = world;
70         self.think                      = Monster_Fade;
71         self.nextthink          = time + 1;
72         
73         monster_hook_death(); // for post-death mods
74 }
75
76 void spawner_think() 
77 {
78         float finished = FALSE;
79         self.think = spawner_think;
80         
81         if(self.spawner_monstercount >= autocvar_g_monster_spawner_maxmobs)
82         {
83                 self.nextthink = time + 5;
84         }
85
86         if (self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs)
87         {
88                 spawnmonsters();
89                 finished = TRUE;
90         }               
91         
92         self.nextthink = time + 1;
93
94         if(self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs || !finished)
95                 self.nextthink = time + 0.1;
96 }
97
98 void spawner_spawn() 
99 {
100         if not(self.health)
101                 self.health = autocvar_g_monster_spawner_health * self.scale;
102         
103         self.classname                  = "monster_spawner";
104         self.nextthink                  = time + 0.2;
105         self.velocity                   = '0 0 0';
106         self.think                              = spawner_think;
107         self.touch                              = func_null;    
108         self.sprite_height      = 80 * self.scale;
109         
110         self.spawner_monstercount = 0;
111         
112         droptofloor();
113         self.movetype = MOVETYPE_NONE;
114         
115         monster_hook_spawn(); // for post-spawn mods
116 }
117
118 /*QUAKED monster_spawner (1 0 0) (-18 -18 -25) (18 18 47)
119 ---------NOTES----------
120 Spawns monsters when a player is nearby
121 -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
122 modeldisabled="models/containers/crate01.md3"
123 */
124 void spawnfunc_monster_spawner() 
125 {
126         if not(autocvar_g_monster_spawner) { remove(self); return; }
127         
128         self.monster_spawnfunc = spawnfunc_monster_spawner;
129         
130         if(self.spawnflags & MONSTERFLAG_APPEAR)
131         {
132                 self.think = func_null;
133                 self.nextthink = -1;
134                 self.use = Monster_Appear;
135                 return;
136         }
137         
138         self.scale = 0.8;
139         
140         if not (monster_initialize(
141                          "Monster spawner",
142                          "models/containers/crate01.md3",
143                          SPAWNER_MIN, SPAWNER_MAX,
144                          FALSE,
145                          spawner_die, spawner_spawn))
146         {
147                 remove(self);
148                 return;
149         }
150
151         precache_sound("weapons/rocket_impact.wav");
152 }