Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
golem.qc
Go to the documentation of this file.
1#include "golem.qh"
2
3#ifdef SVQC
5string autocvar_g_monster_golem_loot = "health_mega electro";
21
22.float golem_lastattack; // delay attacks separately
23
25{
26 makevectors(this.angles);
27 Send_Effect(EFFECT_EXPLOSION_MEDIUM, (this.origin + (v_forward * 150)) - ('0 0 1' * this.maxs.z), '0 0 0', 1);
28 sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
29
30 vector loc = this.origin + v_forward * 50;
31
32 entity dmgent = spawn();
33 dmgent.owner = dmgent.realowner = this;
34 setorigin(dmgent, loc);
35 RadiusDamage(dmgent, this,
39 this,
40 NULL,
42 DEATH_MONSTER_GOLEM_SMASH.m_id,
44 NULL
45 );
46 delete(dmgent);
47}
48
50{
51 Monster_Attack_Melee(this, this.enemy, autocvar_g_monster_golem_attack_claw_damage, ((random() >= 0.5) ? this.anim_melee2 : this.anim_melee3), this.attack_range, 0.8, DEATH_MONSTER_GOLEM_CLAW.m_id, true);
52}
53
55
57{
58 sound(this, CH_SHOTS, SND_MON_GOLEM_LIGHTNING_IMPACT, VOL_BASE, ATTEN_NORM);
59 Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
60
61 this.event_damage = func_null;
62 this.takedamage = DAMAGE_NO;
64 this.velocity = '0 0 0';
65
66 if (this.move_movetype == MOVETYPE_NONE)
67 this.velocity = this.oldvelocity;
68
69 RadiusDamage(this, this.realowner,
73 NULL,
74 NULL,
78 directhitentity
79 );
80
82 {
83 te_csqc_lightningarc(this.origin, it.origin);
84 Damage(it, this, this.realowner,
85 autocvar_g_monster_golem_attack_lightning_damage_zap * MONSTER_SKILLMOD(this),
86 DEATH_MONSTER_GOLEM_ZAP.m_id,
87 DMG_NOWEP,
88 it.origin,
89 '0 0 0'
90 );
91 });
92
93 setthink(this, SUB_Remove);
94 this.nextthink = time + 0.2;
95}
96
98{
100}
101
102void M_Golem_Attack_Lightning_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
103{
104 if (GetResource(this, RES_HEALTH) <= 0)
105 return;
106 if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
107 return; // g_projectiles_damage says to halt
108
109 TakeResource(this, RES_HEALTH, damage);
110
111 if (GetResource(this, RES_HEALTH) <= 0)
112 W_PrepareExplosionByDamage(this, attacker, adaptor_think2use);
113}
114
116{
118
119 this.use(this, NULL, toucher);
120}
121
123{
124 this.nextthink = time;
125 if (time > this.cnt)
126 {
128 return;
129 }
130}
131
133{
134 monster_makevectors(this, this.enemy);
135
136 entity gren = new(grenade);
137 gren.owner = gren.realowner = this;
138 gren.bot_dodge = true;
142 gren.projectiledeathtype = DEATH_MONSTER_GOLEM_ZAP.m_id;
143 setorigin(gren, CENTER_OR_VIEWOFS(this));
144 setsize(gren, '-8 -8 -8', '8 8 8');
145 gren.scale = 2.5;
146
147 gren.cnt = time + 5;
148 gren.nextthink = time;
152
153 gren.takedamage = DAMAGE_YES;
154 SetResourceExplicit(gren, RES_HEALTH, 50);
155 gren.damageforcescale = 0;
156 gren.event_damage = M_Golem_Attack_Lightning_Damage;
157 gren.damagedbycontents = true;
159 gren.missile_flags = MIF_SPLASH | MIF_ARC;
161
162 gren.angles = vectoangles(gren.velocity);
163 gren.flags = FL_PROJECTILE;
164 IL_PUSH(g_projectiles, gren);
165 IL_PUSH(g_bot_dodge, gren);
166
168}
169
170.int state;
171
172bool M_Golem_Attack(int attack_type, entity actor, entity targ, .entity weaponentity)
173{
174 switch (attack_type)
175 {
177 {
178 setanim(actor, ((random() >= 0.5) ? actor.anim_melee2 : actor.anim_melee3), false, true, true);
179 int swing_cnt = bound(1, floor(random() * 4), 3);
180 Monster_Delay(actor, swing_cnt, 0.5, M_Golem_Attack_Swing);
181 actor.anim_finished = actor.attack_finished_single[0] = time + (0.5 * swing_cnt); // set this for the delay
182 return true;
183 }
185 {
186 float randomness = random();
187
188 if (time < actor.golem_lastattack || !IS_ONGROUND(actor))
189 return false;
190
191 if (randomness <= 0.5 && vdist(actor.enemy.origin - actor.origin, <=, autocvar_g_monster_golem_attack_smash_range))
192 {
193 setanim(actor, actor.anim_melee1, false, true, true);
194 Monster_Delay(actor, 1, 1.1, M_Golem_Attack_Smash);
195 if (actor.animstate_endtime > time)
196 actor.anim_finished = actor.animstate_endtime;
197 else
198 actor.anim_finished = time + 1.2;
199 actor.attack_finished_single[0] = actor.anim_finished + 0.2;
200 actor.state = MONSTER_ATTACK_MELEE; // kinda a melee attack
201 actor.golem_lastattack = time + 3 + random() * 1.5;
202 return true;
203 }
204 else if (randomness <= 0.1 && vdist(actor.enemy.origin - actor.origin, >=, autocvar_g_monster_golem_attack_smash_range * 1.5)) // small chance, don't want this spammed
205 {
206 setanim(actor, actor.anim_melee2, true, true, false);
207 actor.state = MONSTER_ATTACK_MELEE; // maybe we should rename this to something more general
208 actor.attack_finished_single[0] = time + 1.1;
209 actor.anim_finished = 1.1;
210 actor.golem_lastattack = time + 3 + random() * 1.5;
212 return true;
213 }
214 return false;
215 }
216 }
217
218 return false;
219}
220
221spawnfunc(monster_golem)
222{
223 Monster_Spawn(this, true, MON_GOLEM);
224}
225// compatibility
226spawnfunc(monster_shambler)
227{
228 spawnfunc_monster_golem(this);
229}
230
231METHOD(Golem, mr_think, bool(Golem this, entity actor))
232{
233 TC(Golem, this);
234 return true;
235}
236
237METHOD(Golem, mr_pain, float(Golem this, entity actor, float damage_take, entity attacker, float deathtype))
238{
239 TC(Golem, this);
240 actor.pain_finished = time + 0.5;
241 setanim(actor, ((random() >= 0.5) ? actor.anim_pain2 : actor.anim_pain1), true, true, false);
242 return damage_take;
243}
244
245METHOD(Golem, mr_death, bool(Golem this, entity actor))
246{
247 TC(Golem, this);
248 setanim(actor, actor.anim_die1, false, true, true);
249 return true;
250}
251#endif // SVQC
252#ifdef GAMEQC
253METHOD(Golem, mr_anim, bool(Golem this, entity actor))
254{
255 TC(Golem, this);
256 vector none = '0 0 0';
257 actor.anim_idle = animfixfps(actor, '0 1 1', none);
258 actor.anim_walk = animfixfps(actor, '1 1 1', none);
259 actor.anim_run = animfixfps(actor, '2 1 1', none);
260 //actor.anim_melee1 = animfixfps(actor, '3 1 5', none); // analyze models and set framerate
261 actor.anim_melee2 = animfixfps(actor, '4 1 5', none); // analyze models and set framerate
262 actor.anim_melee3 = animfixfps(actor, '5 1 5', none); // analyze models and set framerate
263 //actor.anim_melee4 = animfixfps(actor, '6 1 5', none); // analyze models and set framerate
264 actor.anim_melee1 = animfixfps(actor, '6 1 5', none); // analyze models and set framerate
265 actor.anim_pain1 = animfixfps(actor, '7 1 2', none); // 0.5 seconds
266 actor.anim_pain2 = animfixfps(actor, '8 1 2', none); // 0.5 seconds
267 //actor.anim_pain3 = animfixfps(actor, '9 1 2', none); // 0.5 seconds
268 //actor.anim_pain4 = animfixfps(actor, '10 1 2', none); // 0.5 seconds
269 //actor.anim_pain5 = animfixfps(actor, '11 1 2', none); // 0.5 seconds
270 actor.anim_spawn = animfixfps(actor, '12 1 5', none); // analyze models and set framerate
271 actor.anim_die1 = animfixfps(actor, '13 1 0.5', none); // 2 seconds
272 //actor.anim_dead = animfixfps(actor, '14 1 0.5', none); // 2 seconds
273 actor.anim_die2 = animfixfps(actor, '15 1 0.5', none); // 2 seconds
274 // dead2 16
275 //actor.anim_dieback = animfixfps(actor, '16 1 0.5', none); // 2 seconds
276 //actor.anim_deadback = animfixfps(actor, '17 1 0.5', none); // 2 seconds
277 //actor.anim_dead2 = animfixfps(actor, '18 1 0.5', none); // 2 seconds
278 //actor.anim_dead3 = animfixfps(actor, '19 1 0.5', none); // 2 seconds
279 //actor.anim_dead4 = animfixfps(actor, '20 1 0.5', none); // 2 seconds
280 //actor.anim_dead5 = animfixfps(actor, '21 1 0.5', none); // 2 seconds
281 //actor.anim_dead6 = animfixfps(actor, '22 1 0.5', none); // 2 seconds
282 return true;
283}
284#endif // GAMEQC
285#ifdef SVQC
286METHOD(Golem, mr_setup, bool(Golem this, entity actor))
287{
288 TC(Golem, this);
289 if (!GetResource(actor, RES_HEALTH))
291 if (!actor.attack_range) actor.attack_range = 150;
292 if (!actor.speed) actor.speed = autocvar_g_monster_golem_speed_walk;
293 if (!actor.speed2) actor.speed2 = autocvar_g_monster_golem_speed_run;
294 if (!actor.stopspeed) actor.stopspeed = autocvar_g_monster_golem_speed_stop;
295 if (!actor.damageforcescale) actor.damageforcescale = autocvar_g_monster_golem_damageforcescale;
296
297 actor.monster_loot = autocvar_g_monster_golem_loot;
298
299 setanim(actor, actor.anim_spawn, false, true, true);
300 actor.spawn_time = actor.animstate_endtime;
301 StatusEffects_apply(STATUSEFFECT_SpawnShield, actor, actor.spawn_time, 0);
302 actor.monster_attackfunc = M_Golem_Attack;
303
304 return true;
305}
306#endif // SVQC
307#ifdef MENUQC
308METHOD(Golem, describe, string(Golem this))
309{
310 TC(Golem, this);
312 PAR(_("Golems are large powerful brutes capable of taking and dealing a beating. Keeping your distance is advised."));
313 PAR(_("The Golem's primary melee attack is a series of punches. "
314 "On occasion the Golem may jump into the air, dealing massive damage in an area as it slams the ground."));
315 PAR(_("To deal with distant foes, the Golem may throw a chunk of its electrified rocky exterior, zapping nearby targets on impact."));
316 return PAGE_TEXT;
317}
318#endif // MENUQC
#define setanim(...)
Definition anim.qh:45
IntrusiveList g_bot_dodge
Definition api.qh:150
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
void TakeResource(entity receiver, Resource res_type, float amount)
Takes an entity some resource.
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
Definition golem.qh:9
float cnt
Definition powerups.qc:24
const int FL_PROJECTILE
Definition constants.qh:85
vector v_up
vector velocity
float time
vector maxs
float nextthink
vector v_forward
vector origin
#define spawn
#define use
void CSQCProjectile(entity e, float clientanimate, int type, float docull)
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype,.entity weaponentity, entity directhitentity)
Definition damage.qc:943
IntrusiveList g_damagedbycontents
Definition damage.qh:143
#define DMG_NOWEP
Definition damage.qh:104
int state
void SUB_Remove(entity this)
Remove entity.
Definition defer.qh:13
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:120
ent angles
Definition ent_cs.qc:121
void M_Golem_Attack_Lightning_Explode(entity this, entity directhitentity)
Definition golem.qc:56
float autocvar_g_monster_golem_attack_lightning_force
Definition golem.qc:13
void M_Golem_Attack_Lightning_Explode_use(entity this, entity actor, entity trigger)
Definition golem.qc:97
float autocvar_g_monster_golem_attack_lightning_damage
Definition golem.qc:11
float autocvar_g_monster_golem_attack_lightning_radius_zap
Definition golem.qc:15
string autocvar_g_monster_golem_loot
Definition golem.qc:5
float autocvar_g_monster_golem_speed_walk
Definition golem.qc:20
float golem_lastattack
Definition golem.qc:22
void M_Golem_Attack_Lightning_Touch(entity this, entity toucher)
Definition golem.qc:115
float autocvar_g_monster_golem_attack_lightning_damage_zap
Definition golem.qc:12
void M_Golem_Attack_Lightning_Think(entity this)
Definition golem.qc:122
float autocvar_g_monster_golem_attack_lightning_radius
Definition golem.qc:14
float autocvar_g_monster_golem_attack_smash_range
Definition golem.qc:9
float autocvar_g_monster_golem_health
Definition golem.qc:4
float autocvar_g_monster_golem_speed_stop
Definition golem.qc:18
float autocvar_g_monster_golem_attack_claw_damage
Definition golem.qc:10
float autocvar_g_monster_golem_attack_lightning_speed_up
Definition golem.qc:17
float autocvar_g_monster_golem_damageforcescale
Definition golem.qc:6
void M_Golem_Attack_Smash(entity this)
Definition golem.qc:24
float autocvar_g_monster_golem_attack_smash_damage
Definition golem.qc:7
float autocvar_g_monster_golem_attack_lightning_speed
Definition golem.qc:16
float autocvar_g_monster_golem_speed_run
Definition golem.qc:19
void M_Golem_Attack_Swing(entity this)
Definition golem.qc:49
void M_Golem_Attack_Lightning(entity this)
Definition golem.qc:132
float autocvar_g_monster_golem_attack_smash_force
Definition golem.qc:8
bool M_Golem_Attack(int attack_type, entity actor, entity targ,.entity weaponentity)
Definition golem.qc:172
void M_Golem_Attack_Lightning_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition golem.qc:102
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define FOREACH_ENTITY_RADIUS(org, dist, cond, body)
Definition iter.qh:160
#define TC(T, sym)
Definition _all.inc:82
float bound(float min, float value, float max)
float random(void)
vector vectoangles(vector v)
float floor(float f)
vector anim_melee2
Definition monster.qh:29
vector animfixfps(entity e, vector a, vector b)
Definition util.qc:1905
vector anim_melee3
Definition monster.qh:30
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_NONE
Definition movetypes.qh:129
float move_movetype
Definition movetypes.qh:76
const int MOVETYPE_BOUNCE
Definition movetypes.qh:139
#define IS_ONGROUND(s)
Definition movetypes.qh:16
var void func_null()
#define METHOD(cname, name, prototype)
Definition oo.qh:269
#define NULL
Definition post.qh:14
#define makevectors
Definition post.qh:21
const int PROJECTILE_GOLEM_LIGHTNING
#define setthink(e, f)
vector
Definition self.qh:92
entity entity toucher
Definition self.qh:72
#define settouch(e, f)
Definition self.qh:73
vector oldvelocity
Definition main.qh:42
float W_CheckProjectileDamage(entity inflictor, entity projowner, int deathtype, float exception)
Definition common.qc:45
void W_PrepareExplosionByDamage(entity this, entity attacker, void(entity this) explode)
Definition common.qc:87
const int MIF_SPLASH
Definition common.qh:46
int projectiledeathtype
Definition common.qh:21
#define PROJECTILE_TOUCH(e, t)
Definition common.qh:28
IntrusiveList g_projectiles
Definition common.qh:58
const int MIF_ARC
Definition common.qh:47
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:34
const float VOL_BASE
Definition sound.qh:36
const int CH_SHOTS
Definition sound.qh:14
const float ATTEN_NORM
Definition sound.qh:30
#define sound(e, c, s, v, a)
Definition sound.qh:52
#define spawnfunc(id)
Definition spawnfunc.qh:96
void StatusEffects_apply(StatusEffect this, entity actor, float eff_time, int eff_flags)
#define PAGE_TEXT
Definition string.qh:642
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:648
#define PAGE_TEXT_INIT()
Definition string.qh:641
const int DAMAGE_YES
Definition subs.qh:80
const int DAMAGE_NO
Definition subs.qh:79
float takedamage
Definition subs.qh:78
entity enemy
Definition sv_ctf.qh:153
void Monster_Delay(entity this, int repeat_count, float defer_amnt, void(entity) func)
bool Monster_Spawn(entity this, bool check_appear, Monster mon)
Setup the basic required properties for a monster.
void monster_makevectors(entity this, entity targ)
bool Monster_Attack_Melee(entity this, entity targ, float damg, vector anim, float er, float animtime, int deathtype, bool dostop)
#define MONSTER_SKILLMOD(mon)
float attack_range
melee attack if closer, ranged attack if further away (TODO: separate ranged attack range?...
const int MONSTER_ATTACK_MELEE
const int MONSTER_ATTACK_RANGED
entity realowner
void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float pSpeed, float pUpSpeed, float pZSpeed, float spread, float forceAbsolute)
Definition tracing.qc:185
#define CENTER_OR_VIEWOFS(ent)
Definition utils.qh:31
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition vector.qh:8