]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/spider.qc
Merge branch 'master' into Mario/monsters
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / spider.qc
1 // size
2 const vector SPIDER_MIN = '-18 -18 -25';
3 const vector SPIDER_MAX = '18 18 30';
4
5 // model
6 string SPIDER_MODEL = "models/monsters/spider.dpm";
7
8 #ifdef SVQC
9 // cvars
10 float autocvar_g_monster_spider;
11 float autocvar_g_monster_spider_stopspeed;
12 float autocvar_g_monster_spider_attack_leap_delay;
13 float autocvar_g_monster_spider_attack_stand_damage;
14 float autocvar_g_monster_spider_attack_stand_delay;
15 float autocvar_g_monster_spider_attack_fire_time;
16 float autocvar_g_monster_spider_health;
17 float autocvar_g_monster_spider_speed_walk;
18 float autocvar_g_monster_spider_speed_run;
19 float autocvar_g_monster_spider_attack_type;
20
21 // animations
22 const float spider_anim_idle            = 0;
23 const float spider_anim_walk            = 1;
24 const float spider_anim_attack          = 2;
25 const float spider_anim_attack2         = 3;
26
27 .float spider_type; // used to switch between fire & ice attacks
28 const float SPIDER_TYPE_ICE             = 0;
29 const float SPIDER_TYPE_FIRE    = 1;
30
31 void spider_think()
32 {
33         self.think = spider_think;
34         self.nextthink = time + self.ticrate;
35         
36         monster_move(autocvar_g_monster_spider_speed_run, autocvar_g_monster_spider_speed_walk, autocvar_g_monster_spider_stopspeed, spider_anim_walk, spider_anim_walk, spider_anim_idle);
37 }
38
39 void spider_web_explode ()
40 {
41         float damg = 0, edamg = 0, rad = 1;
42         switch(self.realowner.spider_type)
43         {
44                 case SPIDER_TYPE_ICE:
45                         break; // no change
46                 case SPIDER_TYPE_FIRE:
47                         damg = 15;
48                         rad = 25;
49                         edamg = 6;
50                         break;
51         }
52         
53         RadiusDamage (self, self.realowner, damg, edamg, rad, world, 0, self.projectiledeathtype, other);
54         
55         remove (self);
56 }
57
58 void spider_web_touch ()
59 {
60         PROJECTILE_TOUCH;
61         
62         if(other.takedamage == DAMAGE_AIM)
63         if(other.health > 0)
64         switch(self.realowner.spider_type)
65         {
66                 case SPIDER_TYPE_ICE:
67                         Freeze(other, 0.3, 2);
68                         break;
69                 case SPIDER_TYPE_FIRE:
70                         Fire_AddDamage(other, self.realowner, 5 * monster_skill, autocvar_g_monster_spider_attack_fire_time, DEATH_MONSTER_SPIDER_FIRE);
71                         break;
72         }
73                 
74         spider_web_explode();
75 }
76
77 void spider_shootweb(float ptype)
78 {
79         float p = 0, dt = 0;
80         string snd = "";
81         switch(ptype)
82         {
83                 case SPIDER_TYPE_ICE:
84                         p = PROJECTILE_ELECTRO;
85                         dt = WEP_ELECTRO;
86                         snd = "weapons/electro_fire2.wav";
87                         break;
88                 case SPIDER_TYPE_FIRE:
89                         p = PROJECTILE_FIREMINE;
90                         dt = WEP_FIREBALL;
91                         snd = "weapons/fireball_fire.wav";
92                         break;
93         }
94         
95         vector fmins = '-4 -4 -4', fmaxs = '4 4 4';
96
97         W_SetupShot_ProjectileSize(self, fmins, fmaxs, FALSE, 2, snd, CH_WEAPON_A, 0);
98
99         w_shotdir = v_forward; // no TrueAim for grenades please
100
101         entity proj = spawn ();
102         proj.classname = "plasma";
103         proj.owner = proj.realowner = self;
104         proj.use = spider_web_touch;
105         proj.think = adaptor_think2use_hittype_splash;
106         proj.bot_dodge = TRUE;
107         proj.bot_dodgerating = 0;
108         proj.nextthink = time + 5;
109         PROJECTILE_MAKETRIGGER(proj);
110         proj.projectiledeathtype = dt | HITTYPE_SECONDARY;
111         setorigin(proj, w_shotorg);
112
113         //proj.glow_size = 50;
114         //proj.glow_color = 45;
115         proj.movetype = MOVETYPE_BOUNCE;
116         W_SETUPPROJECTILEVELOCITY_UP(proj, g_monster_spider_attack_web);
117         proj.touch = spider_web_touch;
118         setsize(proj, fmins, fmaxs);
119         proj.takedamage = DAMAGE_NO;
120         proj.damageforcescale = 0;
121         proj.health = 500;
122         proj.event_damage = func_null;
123         proj.flags = FL_PROJECTILE;
124         proj.damagedbycontents = TRUE;
125
126         proj.bouncefactor = 0.3;
127         proj.bouncestop = 0.05;
128         proj.missile_flags = MIF_SPLASH | MIF_ARC;
129
130         CSQCProjectile(proj, TRUE, p, TRUE);
131 }
132
133 float spider_attack(float attack_type)
134 {
135         switch(attack_type)
136         {
137                 case MONSTER_ATTACK_MELEE:
138                 {
139                         monster_melee(self.enemy, autocvar_g_monster_spider_attack_stand_damage, 0.3, DEATH_MONSTER_SPIDER, TRUE);
140                         monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
141                         self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
142                         
143                         return TRUE;
144                 }
145                 case MONSTER_ATTACK_RANGED:
146                 {
147                         if(self.enemy.frozen)
148                                 return FALSE;
149                         
150                         monsters_setframe(spider_anim_attack2);
151                         self.attack_finished_single = time + autocvar_g_monster_spider_attack_leap_delay;
152                         monster_makevectors(self.enemy);
153                         spider_shootweb(self.spider_type);
154                         
155                         return TRUE;
156                 }
157         }
158         
159         return FALSE;
160 }
161
162 void spider_die ()
163 {
164         Monster_CheckDropCvars ("spider");
165         
166         self.think = monster_dead_think;
167         self.nextthink = time + self.ticrate;
168         self.ltime = time + 5;
169         monsters_setframe(spider_anim_attack);
170         self.angles += '180 0 0';
171         
172         monster_hook_death(); // for post-death mods
173 }
174
175 void spider_spawn() 
176 {
177         if not(self.health)
178                 self.health = autocvar_g_monster_spider_health;
179         
180         self.classname                  = "monster_spider";
181         self.nextthink                  = time + random() * 0.5 + 0.1;
182         self.monster_attackfunc = spider_attack;
183         self.think                              = spider_think;
184         
185         monsters_setframe(spider_anim_idle);
186         
187         monster_setupsounds("spider");
188         
189         if not(self.spider_type)
190                 self.spider_type = autocvar_g_monster_spider_attack_type;
191         
192         monster_hook_spawn(); // for post-spawn mods
193 }
194
195 void spawnfunc_monster_spider() 
196 {
197         if not(autocvar_g_monster_spider) { remove(self); return; }
198         
199         self.monster_spawnfunc = spawnfunc_monster_spider;
200         
201         if(Monster_CheckAppearFlags(self))
202                 return;
203         
204         if not (monster_initialize(
205                          "Spider", MONSTER_SPIDER,
206                          SPIDER_MIN, SPIDER_MAX,
207                          FALSE,
208                          spider_die, spider_spawn))
209         {
210                 remove(self);
211                 return;
212         }
213 }
214
215 #endif // SVQC