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 return (e != WarpZone_SearchInRadius_otherent && e.takedamage);
59}
61{
62 sound(this, CH_SHOTS, SND_MON_GOLEM_LIGHTNING_IMPACT, VOL_BASE, ATTEN_NORM);
63 Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
64
65 this.event_damage = func_null;
66 this.takedamage = DAMAGE_NO;
68 this.velocity = '0 0 0';
69
70 if (this.move_movetype == MOVETYPE_NONE)
71 this.velocity = this.oldvelocity;
72
73 RadiusDamage(this, this.realowner,
77 NULL,
78 NULL,
82 directhitentity
83 );
84
88 {
89 WarpZone_TraceLine_ThroughZone(this.origin, WarpZone_UnTransformOrigin(head, head.WarpZone_findradius_nearest),
91 Damage(head, this, this.realowner,
93 DEATH_MONSTER_GOLEM_ZAP.m_id,
95 head.WarpZone_findradius_nearest,
96 '0 0 0'
97 );
98 }
99
100 setthink(this, SUB_Remove);
101 this.nextthink = time + 0.2;
102}
103
105{
107}
108
109void M_Golem_Attack_Lightning_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
110{
111 if (GetResource(this, RES_HEALTH) <= 0)
112 return;
113 if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
114 return; // g_projectiles_damage says to halt
115
116 TakeResource(this, RES_HEALTH, damage);
117
118 if (GetResource(this, RES_HEALTH) <= 0)
119 W_PrepareExplosionByDamage(this, attacker, adaptor_think2use);
120}
121
123{
125
126 this.use(this, NULL, toucher);
127}
128
130{
131 this.nextthink = time;
132 if (time > this.cnt)
133 {
135 return;
136 }
137}
138
140{
141 monster_makevectors(this, this.enemy);
142
143 entity gren = new(grenade);
144 gren.owner = gren.realowner = this;
145 gren.bot_dodge = true;
149 gren.projectiledeathtype = DEATH_MONSTER_GOLEM_ZAP.m_id;
150 setorigin(gren, CENTER_OR_VIEWOFS(this));
151 setsize(gren, '-8 -8 -8', '8 8 8');
152 gren.scale = 2.5;
153
154 gren.cnt = time + 5;
155 gren.nextthink = time;
159
160 gren.takedamage = DAMAGE_YES;
161 SetResourceExplicit(gren, RES_HEALTH, 50);
162 gren.damageforcescale = 0;
163 gren.event_damage = M_Golem_Attack_Lightning_Damage;
164 gren.damagedbycontents = true;
166 gren.missile_flags = MIF_SPLASH | MIF_ARC;
168
169 gren.angles = vectoangles(gren.velocity);
170 gren.flags = FL_PROJECTILE;
171 IL_PUSH(g_projectiles, gren);
172 IL_PUSH(g_bot_dodge, gren);
173
175}
176
177.int state;
178
179bool M_Golem_Attack(int attack_type, entity actor, entity targ, .entity weaponentity)
180{
181 switch (attack_type)
182 {
184 {
185 setanim(actor, ((random() >= 0.5) ? actor.anim_melee2 : actor.anim_melee3), false, true, true);
186 int swing_cnt = bound(1, floor(random() * 4), 3);
187 Monster_Delay(actor, swing_cnt, 0.5, M_Golem_Attack_Swing);
188 actor.anim_finished = actor.attack_finished_single[0] = time + (0.5 * swing_cnt); // set this for the delay
189 return true;
190 }
192 {
193 float randomness = random();
194
195 if (time < actor.golem_lastattack || !IS_ONGROUND(actor))
196 return false;
197
198 if (randomness <= 0.5 && vdist(actor.enemy.origin - actor.origin, <=, autocvar_g_monster_golem_attack_smash_range))
199 {
200 setanim(actor, actor.anim_melee1, false, true, true);
201 Monster_Delay(actor, 1, 1.1, M_Golem_Attack_Smash);
202 if (actor.animstate_endtime > time)
203 actor.anim_finished = actor.animstate_endtime;
204 else
205 actor.anim_finished = time + 1.2;
206 actor.attack_finished_single[0] = actor.anim_finished + 0.2;
207 actor.state = MONSTER_ATTACK_MELEE; // kinda a melee attack
208 actor.golem_lastattack = time + 3 + random() * 1.5;
209 return true;
210 }
211 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
212 {
213 setanim(actor, actor.anim_melee2, true, true, false);
214 actor.state = MONSTER_ATTACK_MELEE; // maybe we should rename this to something more general
215 actor.attack_finished_single[0] = time + 1.1;
216 actor.anim_finished = 1.1;
217 actor.golem_lastattack = time + 3 + random() * 1.5;
219 return true;
220 }
221 return false;
222 }
223 }
224
225 return false;
226}
227
228spawnfunc(monster_golem)
229{
230 Monster_Spawn(this, true, MON_GOLEM);
231}
232// compatibility
233spawnfunc(monster_shambler)
234{
235 spawnfunc_monster_golem(this);
236}
237
238METHOD(Golem, mr_think, bool(Golem this, entity actor))
239{
240 TC(Golem, this);
241 return true;
242}
243
244METHOD(Golem, mr_pain, float(Golem this, entity actor, float damage_take, entity attacker, float deathtype))
245{
246 TC(Golem, this);
247 actor.pain_finished = time + 0.5;
248 setanim(actor, ((random() >= 0.5) ? actor.anim_pain2 : actor.anim_pain1), true, true, false);
249 return damage_take;
250}
251
252METHOD(Golem, mr_death, bool(Golem this, entity actor))
253{
254 TC(Golem, this);
255 setanim(actor, actor.anim_die1, false, true, true);
256 return true;
257}
258#endif // SVQC
259#ifdef GAMEQC
260METHOD(Golem, mr_anim, bool(Golem this, entity actor))
261{
262 TC(Golem, this);
263 vector none = '0 0 0';
264 actor.anim_idle = animfixfps(actor, '0 1 1', none);
265 actor.anim_walk = animfixfps(actor, '1 1 1', none);
266 actor.anim_run = animfixfps(actor, '2 1 1', none);
267 //actor.anim_melee1 = animfixfps(actor, '3 1 5', none); // analyze models and set framerate
268 actor.anim_melee2 = animfixfps(actor, '4 1 5', none); // analyze models and set framerate
269 actor.anim_melee3 = animfixfps(actor, '5 1 5', none); // analyze models and set framerate
270 //actor.anim_melee4 = animfixfps(actor, '6 1 5', none); // analyze models and set framerate
271 actor.anim_melee1 = animfixfps(actor, '6 1 5', none); // analyze models and set framerate
272 actor.anim_pain1 = animfixfps(actor, '7 1 2', none); // 0.5 seconds
273 actor.anim_pain2 = animfixfps(actor, '8 1 2', none); // 0.5 seconds
274 //actor.anim_pain3 = animfixfps(actor, '9 1 2', none); // 0.5 seconds
275 //actor.anim_pain4 = animfixfps(actor, '10 1 2', none); // 0.5 seconds
276 //actor.anim_pain5 = animfixfps(actor, '11 1 2', none); // 0.5 seconds
277 actor.anim_spawn = animfixfps(actor, '12 1 5', none); // analyze models and set framerate
278 actor.anim_die1 = animfixfps(actor, '13 1 0.5', none); // 2 seconds
279 //actor.anim_dead = animfixfps(actor, '14 1 0.5', none); // 2 seconds
280 actor.anim_die2 = animfixfps(actor, '15 1 0.5', none); // 2 seconds
281 // dead2 16
282 //actor.anim_dieback = animfixfps(actor, '16 1 0.5', none); // 2 seconds
283 //actor.anim_deadback = animfixfps(actor, '17 1 0.5', none); // 2 seconds
284 //actor.anim_dead2 = animfixfps(actor, '18 1 0.5', none); // 2 seconds
285 //actor.anim_dead3 = animfixfps(actor, '19 1 0.5', none); // 2 seconds
286 //actor.anim_dead4 = animfixfps(actor, '20 1 0.5', none); // 2 seconds
287 //actor.anim_dead5 = animfixfps(actor, '21 1 0.5', none); // 2 seconds
288 //actor.anim_dead6 = animfixfps(actor, '22 1 0.5', none); // 2 seconds
289 return true;
290}
291#endif // GAMEQC
292#ifdef SVQC
293METHOD(Golem, mr_setup, bool(Golem this, entity actor))
294{
295 TC(Golem, this);
296 if (!GetResource(actor, RES_HEALTH))
298 if (!actor.attack_range) actor.attack_range = 150;
299 if (!actor.speed) actor.speed = autocvar_g_monster_golem_speed_walk;
300 if (!actor.speed2) actor.speed2 = autocvar_g_monster_golem_speed_run;
301 if (!actor.stopspeed) actor.stopspeed = autocvar_g_monster_golem_speed_stop;
302 if (!actor.damageforcescale) actor.damageforcescale = autocvar_g_monster_golem_damageforcescale;
303
304 actor.monster_loot = autocvar_g_monster_golem_loot;
305
306 setanim(actor, actor.anim_spawn, false, true, true);
307 actor.spawn_time = actor.animstate_endtime;
308 StatusEffects_apply(STATUSEFFECT_SpawnShield, actor, actor.spawn_time, 0);
309 actor.monster_attackfunc = M_Golem_Attack;
310
311 return true;
312}
313#endif // SVQC
314#ifdef MENUQC
315METHOD(Golem, describe, string(Golem this))
316{
317 TC(Golem, this);
319 PAR(_("Golems are large powerful brutes capable of taking and dealing a beating. Keeping your distance is advised."));
320 PAR(_("The Golem's primary melee attack is a series of punches. "
321 "On occasion the Golem may jump into the air, dealing massive damage in an area as it slams the ground."));
322 PAR(_("To deal with distant foes, the Golem may throw a chunk of its electrified rocky exterior, zapping nearby targets on impact."));
323 return PAGE_TEXT;
324}
325#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.
Definition golem.qh:9
float cnt
Definition powerups.qc:24
const int FL_PROJECTILE
Definition constants.qh:77
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)
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:484
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:937
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:12
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:155
ent angles
Definition ent_cs.qc:146
SetResourceExplicit(ent, RES_ARMOR, ReadByte() *DEC_FACTOR)) ENTCS_PROP(NAME
void M_Golem_Attack_Lightning_Explode(entity this, entity directhitentity)
Definition golem.qc:60
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:104
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:122
float autocvar_g_monster_golem_attack_lightning_damage_zap
Definition golem.qc:12
void M_Golem_Attack_Lightning_Think(entity this)
Definition golem.qc:129
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
bool M_Golem_Attack_Lightning_Explode_cond(entity e)
Definition golem.qc:56
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:139
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:179
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:109
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define TC(T, sym)
Definition _all.inc:82
entity WarpZone_SearchInRadius(vector org, float rad, float nomonsters, WarpZone_FindRadius_cond_callback_t cb)
Modified findradius aware of warpzones, that only includes entities that meet the "cb" criteria.
Definition common.qc:680
vector WarpZone_UnTransformOrigin(entity wz, vector org)
Transforms origin org backwards through warpzone wz, as the inverse of WarpZone_TransformOrigin.
Definition common.qc:526
noref entity WarpZone_SearchInRadius_otherent
Free to use in the callback.
Definition common.qh:71
#define WarpZone_TraceLine_ThroughZone(org, end, nomonsters, forent, zone, cb)
Definition common.qh:47
WarpZone_trace_callback_t te_csqc_trace_callback
Definition common.qh:38
#define MOVE_NOTHING
Definition common.qh:35
var void te_csqc_trace_callback_func(vector start, vector hit)
void te_csqc_lightningarc(vector from, vector to)
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:1917
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:133
float move_movetype
Definition movetypes.qh:80
const int MOVETYPE_BOUNCE
Definition movetypes.qh:143
#define IS_ONGROUND(s)
Definition movetypes.qh:16
var void func_null()
#define METHOD(cname, name, prototype)
Definition oo.qh:274
#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:96
entity entity toucher
Definition self.qh:76
#define settouch(e, f)
Definition self.qh:77
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:58
int projectiledeathtype
Definition common.qh:33
#define PROJECTILE_TOUCH(e, t)
Definition common.qh:40
IntrusiveList g_projectiles
Definition common.qh:70
const int MIF_ARC
Definition common.qh:59
#define PROJECTILE_MAKETRIGGER(e)
Definition common.qh:46
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:107
void StatusEffects_apply(StatusEffect this, entity actor, float eff_time, int eff_flags)
#define PAGE_TEXT
Definition string.qh:651
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:657
#define PAGE_TEXT_INIT()
Definition string.qh:650
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:152
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:188
#define CENTER_OR_VIEWOFS(ent)
Definition utils.qh:31
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt().
Definition vector.qh:8