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