Merge branch 'master' into terencehill/music_player
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / monsters / monster / zombie.qc
1 #ifdef REGISTER_MONSTER
2 REGISTER_MONSTER(
3 /* MON_##id   */ ZOMBIE,
4 /* function   */ m_zombie,
5 /* spawnflags */ MON_FLAG_MELEE,
6 /* mins,maxs  */ '-18 -18 -25', '18 18 47',
7 /* model      */ "zombie.dpm",
8 /* netname    */ "zombie",
9 /* fullname   */ _("Zombie")
10 );
11
12 #else
13 #ifdef SVQC
14 float autocvar_g_monster_zombie_health;
15 float autocvar_g_monster_zombie_attack_melee_damage;
16 float autocvar_g_monster_zombie_attack_melee_delay;
17 float autocvar_g_monster_zombie_attack_leap_damage;
18 float autocvar_g_monster_zombie_attack_leap_force;
19 float autocvar_g_monster_zombie_attack_leap_speed;
20 float autocvar_g_monster_zombie_attack_leap_delay;
21 float autocvar_g_monster_zombie_speed_stop;
22 float autocvar_g_monster_zombie_speed_run;
23 float autocvar_g_monster_zombie_speed_walk;
24
25 const float zombie_anim_attackleap                      = 0;
26 const float zombie_anim_attackrun1                      = 1;
27 const float zombie_anim_attackrun2                      = 2;
28 const float zombie_anim_attackrun3                      = 3;
29 const float zombie_anim_attackstanding1         = 4;
30 const float zombie_anim_attackstanding2         = 5;
31 const float zombie_anim_attackstanding3         = 6;
32 const float zombie_anim_blockend                        = 7;
33 const float zombie_anim_blockstart                      = 8;
34 const float zombie_anim_deathback1                      = 9;
35 const float zombie_anim_deathback2                      = 10;
36 const float zombie_anim_deathback3                      = 11;
37 const float zombie_anim_deathfront1                     = 12;
38 const float zombie_anim_deathfront2                     = 13;
39 const float zombie_anim_deathfront3                     = 14;
40 const float zombie_anim_deathleft1                      = 15;
41 const float zombie_anim_deathleft2                      = 16;
42 const float zombie_anim_deathright1                     = 17;
43 const float zombie_anim_deathright2                     = 18;
44 const float zombie_anim_idle                            = 19;
45 const float zombie_anim_painback1                       = 20;
46 const float zombie_anim_painback2                       = 21;
47 const float zombie_anim_painfront1                      = 22;
48 const float zombie_anim_painfront2                      = 23;
49 const float zombie_anim_runbackwards            = 24;
50 const float zombie_anim_runbackwardsleft        = 25;
51 const float zombie_anim_runbackwardsright       = 26;
52 const float zombie_anim_runforward                      = 27;
53 const float zombie_anim_runforwardleft          = 28;
54 const float zombie_anim_runforwardright         = 29;
55 const float zombie_anim_spawn                           = 30;
56
57 void zombie_attack_leap_touch()
58 {
59         if (self.health <= 0)
60                 return;
61
62         vector angles_face;
63
64         if(other.takedamage)
65         {
66                 angles_face = vectoangles(self.moveto - self.origin);
67                 angles_face = normalize(angles_face) * (autocvar_g_monster_zombie_attack_leap_force);
68                 Damage(other, self, self, (autocvar_g_monster_zombie_attack_leap_damage) * Monster_SkillModifier(), DEATH_MONSTER_ZOMBIE_JUMP, other.origin, angles_face);
69                 self.touch = MonsterTouch; // instantly turn it off to stop damage spam
70         }
71
72         if (trace_dphitcontents)
73                 self.touch = MonsterTouch;
74 }
75
76 void zombie_blockend()
77 {
78         if(self.health <= 0)
79                 return;
80
81         self.frame = zombie_anim_blockend;
82         self.armorvalue = 0;
83         self.m_armor_blockpercent = autocvar_g_monsters_armor_blockpercent;
84 }
85
86 float zombie_block()
87 {
88         self.frame = zombie_anim_blockstart;
89         self.armorvalue = 100;
90         self.m_armor_blockpercent = 0.9;
91         self.state = MONSTER_STATE_ATTACK_MELEE; // freeze monster
92         self.attack_finished_single = time + 2.1;
93
94         defer(2, zombie_blockend);
95
96         return TRUE;
97 }
98
99 float zombie_attack(float attack_type)
100 {
101         switch(attack_type)
102         {
103                 case MONSTER_ATTACK_MELEE:
104                 {
105                         float rand = random(), chosen_anim;
106
107                         if(rand < 0.33)
108                                 chosen_anim = zombie_anim_attackstanding1;
109                         else if(rand < 0.66)
110                                 chosen_anim = zombie_anim_attackstanding2;
111                         else
112                                 chosen_anim = zombie_anim_attackstanding3;
113
114                         if(random() < 0.3 && self.health < 75 && self.enemy.health > 10)
115                                 return zombie_block();
116
117                         return monster_melee(self.enemy, (autocvar_g_monster_zombie_attack_melee_damage), chosen_anim, self.attack_range, (autocvar_g_monster_zombie_attack_melee_delay), DEATH_MONSTER_ZOMBIE_MELEE, TRUE);
118                 }
119                 case MONSTER_ATTACK_RANGED:
120                 {
121                         makevectors(self.angles);
122                         return monster_leap(zombie_anim_attackleap, zombie_attack_leap_touch, v_forward * (autocvar_g_monster_zombie_attack_leap_speed) + '0 0 200', (autocvar_g_monster_zombie_attack_leap_delay));
123                 }
124         }
125
126         return FALSE;
127 }
128
129 void spawnfunc_monster_zombie()
130 {
131         self.classname = "monster_zombie";
132
133         if(!monster_initialize(MON_ZOMBIE)) { remove(self); return; }
134 }
135
136 float m_zombie(float req)
137 {
138         switch(req)
139         {
140                 case MR_THINK:
141                 {
142                         monster_move((autocvar_g_monster_zombie_speed_run), (autocvar_g_monster_zombie_speed_walk), (autocvar_g_monster_zombie_speed_stop), zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
143                         return TRUE;
144                 }
145                 case MR_DEATH:
146                 {
147                         self.armorvalue = 0;
148                         self.m_armor_blockpercent = autocvar_g_monsters_armor_blockpercent;
149                         self.frame = ((random() > 0.5) ? zombie_anim_deathback1 : zombie_anim_deathfront1);
150                         return TRUE;
151                 }
152                 case MR_SETUP:
153                 {
154                         if(!self.health) self.health = (autocvar_g_monster_zombie_health);
155
156                         if(self.spawnflags & MONSTERFLAG_NORESPAWN)
157                                 self.spawnflags &= ~MONSTERFLAG_NORESPAWN; // zombies always respawn
158
159                         self.spawnflags |= MONSTER_RESPAWN_DEATHPOINT;
160
161                         self.monster_loot = spawnfunc_item_health_medium;
162                         self.monster_attackfunc = zombie_attack;
163                         self.frame = zombie_anim_spawn;
164                         self.spawn_time = time + 2.1;
165                         self.spawnshieldtime = self.spawn_time;
166                         self.respawntime = 0.2;
167
168                         return TRUE;
169                 }
170                 case MR_PRECACHE:
171                 {
172                         precache_model("models/monsters/zombie.dpm");
173                         return TRUE;
174                 }
175         }
176
177         return TRUE;
178 }
179
180 #endif // SVQC
181 #ifdef CSQC
182 float m_zombie(float req)
183 {
184         switch(req)
185         {
186                 case MR_PRECACHE:
187                 {
188                         return TRUE;
189                 }
190         }
191
192         return TRUE;
193 }
194
195 #endif // CSQC
196 #endif // REGISTER_MONSTER