]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/spawner.qc
The first of many bad mistakes (forgot to include the new files)
[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_target_recheck_delay;
9 float autocvar_g_monster_spawner_target_range;
10 float autocvar_g_monster_spawner_spawn_range;
11 float autocvar_g_monster_spawner_maxmobs;
12 string autocvar_g_monster_spawner_forcespawn;
13
14 void() spawner_think;
15
16 void spawnmonsters ()
17 {
18         if(self.spawner_monstercount >= autocvar_g_monster_spawner_maxmobs || self.frozen || self.freezetag_frozen)
19                 return;
20                 
21         vector posi1 = '0 0 0', posi2 = '0 0 0', posi3 = '0 0 0', posi4 = '0 0 0', chosenposi = '0 0 0';
22         float r = random();
23         string type = string_null;
24         entity e = world;
25         
26         self.spawner_monstercount += 1;
27         
28         if(self.spawnmob != "")
29                 type = self.spawnmob;
30                 
31         if(autocvar_g_monster_spawner_forcespawn != "0")
32                 type = autocvar_g_monster_spawner_forcespawn;
33                 
34         if(type == "" || type == "spawner") // spawner spawning spawners?!
35                 type = "knight";
36         
37         posi1 = self.origin - '0 70 -50' * self.scale;
38         posi2 = self.origin + '0 70 50' * self.scale;
39         posi3 = self.origin - '70 0 -50' * self.scale;
40         posi4 = self.origin + '70 0 -50' * self.scale;
41            
42         if (r < 0.20)
43                 chosenposi = posi1;
44         else if (r < 0.50)
45                 chosenposi = posi2;
46         else if (r < 80)
47                 chosenposi = posi3;
48         else
49                 chosenposi = posi4;
50
51         e = spawnmonster(type, self, self, chosenposi, FALSE, MONSTER_MOVE_WANDER);
52         
53         if(teamplay && autocvar_g_monsters_teams)
54                 e.team = self.team;
55         
56         if(self.spawnflags & MONSTERFLAG_GIANT)
57                 e.spawnflags = MONSTERFLAG_GIANT;
58                 
59         if(self.flags & MONSTERFLAG_MINIBOSS)
60                 e.spawnflags = MONSTERFLAG_MINIBOSS;
61 }
62
63 void spawner_die () 
64 {
65         setmodel(self, "");
66         pointparticles(particleeffectnum(((self.scale > 3) ? "explosion_big" : "explosion_medium")), self.origin, '0 0 0', 1);
67         sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
68         
69         self.solid                      = SOLID_NOT;
70         self.takedamage         = DAMAGE_NO;
71         self.event_damage   = func_null;
72         self.enemy                      = world;
73         self.think                      = Monster_Fade;
74         self.nextthink          = time + 1;
75         
76         monster_hook_death(); // for post-death mods
77 }
78
79 void spawner_recount()
80 {
81         self.spawner_monstercount = 0;
82         self.think = spawner_think;
83         self.nextthink = time;
84 }
85
86 void spawner_think() 
87 {
88         float finished = FALSE, enemyDistance = 0;
89         self.think = spawner_think;
90         
91         if(self.spawner_monstercount == autocvar_g_monster_spawner_maxmobs)
92         {
93                 self.think = spawner_recount;
94                 self.nextthink = time + 20;
95                 return;
96         }
97           
98         // remove enemy that ran away
99         if (self.enemy)
100         if (self.delay <= time) // check if we can do the rescan now
101         if (vlen(self.origin - self.enemy.origin) > autocvar_g_monster_spawner_target_range * self.scale)
102                 self.enemy = world;
103         else
104                 self.delay = time + autocvar_g_monster_spawner_target_recheck_delay;
105         
106         if not(self.enemy) 
107         {
108                 self.enemy = FindTarget(self);
109                 if (self.enemy)
110                         self.delay = time + autocvar_g_monster_spawner_target_recheck_delay;
111         }
112
113         if (self.enemy) 
114         {
115                 // this spawner has an enemy
116                 traceline(self.origin, self.enemy.origin, FALSE, self);
117                 enemyDistance = vlen(trace_endpos - self.origin);
118                 
119                 if (trace_ent == self.enemy)
120                 if (self.enemy.deadflag == DEAD_NO)
121                 if (self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs)
122                 if (enemyDistance <= autocvar_g_monster_spawner_spawn_range * self.scale) 
123                 {
124                         spawnmonsters();
125                         finished = TRUE;
126                 }               
127         }
128         
129         self.nextthink = time + 1;
130
131         if(self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs)
132                 self.nextthink = time + 0.1;
133         
134         if not(finished) 
135         {
136                 if (self.enemy)
137                         self.nextthink = time + 0.1;
138         }  
139 }
140
141 void spawner_spawn() 
142 {
143         if not(self.health)
144                 self.health = autocvar_g_monster_spawner_health * self.scale;
145         
146         self.classname                  = "monster_spawner";
147         self.nextthink                  = time + 2.1;
148         self.velocity                   = '0 0 0';
149         self.think                              = spawner_think;
150         self.touch                              = func_null;    
151         self.sprite_height      = 80 * self.scale;
152         
153         self.spawner_monstercount = 0;
154         
155         droptofloor();
156         self.movetype = MOVETYPE_NONE;
157         
158         monster_hook_spawn(); // for post-spawn mods
159 }
160
161 /*QUAKED monster_spawner (1 0 0) (-18 -18 -25) (18 18 47)
162 ---------NOTES----------
163 Spawns monsters when a player is nearby
164 -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
165 modeldisabled="models/containers/crate01.md3"
166 */
167 void spawnfunc_monster_spawner() 
168 {
169         if not(autocvar_g_monster_spawner) 
170         {
171                 remove(self);
172                 return;
173         }
174         
175         self.monster_spawnfunc = spawnfunc_monster_spawner;
176         
177         if(self.spawnflags & MONSTERFLAG_APPEAR)
178         {
179                 self.think = func_null;
180                 self.nextthink = -1;
181                 self.use = Monster_Appear;
182                 return;
183         }
184         
185         self.scale = 0.8;
186         
187         if not (monster_initialize(
188                          "Monster spawner",
189                          "models/containers/crate01.md3",
190                          SPAWNER_MIN, SPAWNER_MAX,
191                          FALSE,
192                          spawner_die, spawner_spawn))
193         {
194                 remove(self);
195                 return;
196         }
197
198         precache_sound("weapons/rocket_impact.wav");
199 }