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