1/*
2==============================================================================
3
4DEMON
5
6==============================================================================
7*/
8
9$cd /raid/quake/id1/models/demon3
10$scale	0.8
11$origin 0 0 24
12$base base
13$skin base
14
15$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
16$frame stand10 stand11 stand12 stand13
17
18$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
19
20$frame run1 run2 run3 run4 run5 run6
21
22$frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9 leap10
23$frame leap11 leap12
24
25$frame pain1 pain2 pain3 pain4 pain5 pain6
26
27$frame death1 death2 death3 death4 death5 death6 death7 death8 death9
28
29$frame attacka1 attacka2 attacka3 attacka4 attacka5 attacka6 attacka7 attacka8
30$frame attacka9 attacka10 attacka11 attacka12 attacka13 attacka14 attacka15
31
32//============================================================================
33
34void()	Demon_JumpTouch;
35
36void()	demon1_stand1	=[	$stand1,	demon1_stand2	] {ai_stand();};
37void()	demon1_stand2	=[	$stand2,	demon1_stand3	] {ai_stand();};
38void()	demon1_stand3	=[	$stand3,	demon1_stand4	] {ai_stand();};
39void()	demon1_stand4	=[	$stand4,	demon1_stand5	] {ai_stand();};
40void()	demon1_stand5	=[	$stand5,	demon1_stand6	] {ai_stand();};
41void()	demon1_stand6	=[	$stand6,	demon1_stand7	] {ai_stand();};
42void()	demon1_stand7	=[	$stand7,	demon1_stand8	] {ai_stand();};
43void()	demon1_stand8	=[	$stand8,	demon1_stand9	] {ai_stand();};
44void()	demon1_stand9	=[	$stand9,	demon1_stand10	] {ai_stand();};
45void()	demon1_stand10	=[	$stand10,	demon1_stand11	] {ai_stand();};
46void()	demon1_stand11	=[	$stand11,	demon1_stand12	] {ai_stand();};
47void()	demon1_stand12	=[	$stand12,	demon1_stand13	] {ai_stand();};
48void()	demon1_stand13	=[	$stand13,	demon1_stand1	] {ai_stand();};
49
50void()	demon1_walk1	=[	$walk1,		demon1_walk2	] {
51if (random() < 0.2)
52    sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE);
53ai_walk(8);
54};
55void()	demon1_walk2	=[	$walk2,		demon1_walk3	] {ai_walk(6);};
56void()	demon1_walk3	=[	$walk3,		demon1_walk4	] {ai_walk(6);};
57void()	demon1_walk4	=[	$walk4,		demon1_walk5	] {ai_walk(7);};
58void()	demon1_walk5	=[	$walk5,		demon1_walk6	] {ai_walk(4);};
59void()	demon1_walk6	=[	$walk6,		demon1_walk7	] {ai_walk(6);};
60void()	demon1_walk7	=[	$walk7,		demon1_walk8	] {ai_walk(10);};
61void()	demon1_walk8	=[	$walk8,		demon1_walk1	] {ai_walk(10);};
62
63void()	demon1_run1	=[	$run1,		demon1_run2	] {
64if (random() < 0.2)
65    sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE);
66ai_run(20);};
67void()	demon1_run2	=[	$run2,		demon1_run3	] {ai_run(15);};
68void()	demon1_run3	=[	$run3,		demon1_run4	] {ai_run(36);};
69void()	demon1_run4	=[	$run4,		demon1_run5	] {ai_run(20);};
70void()	demon1_run5	=[	$run5,		demon1_run6	] {ai_run(15);};
71void()	demon1_run6	=[	$run6,		demon1_run1	] {ai_run(36);};
72
73void()	demon1_jump1	=[	$leap1,		demon1_jump2	] {ai_face();};
74void()	demon1_jump2	=[	$leap2,		demon1_jump3	] {ai_face();};
75void()	demon1_jump3	=[	$leap3,		demon1_jump4	] {ai_face();};
76void()	demon1_jump4	=[	$leap4,		demon1_jump5	]
77{
78	ai_face();
79
80	self.touch = Demon_JumpTouch;
81	makevectors (self.angles);
82	self.origin_z = self.origin_z + 1;
83	self.velocity = v_forward * 600 + '0 0 250';
84	if (self.flags & FL_ONGROUND)
85		self.flags = self.flags - FL_ONGROUND;
86};
87void()	demon1_jump5	=[	$leap5,		demon1_jump6	] {};
88void()	demon1_jump6	=[	$leap6,		demon1_jump7	] {};
89void()	demon1_jump7	=[	$leap7,		demon1_jump8	] {};
90void()	demon1_jump8	=[ 	$leap8,		demon1_jump9	] {};
91void()	demon1_jump9	=[ 	$leap9,		demon1_jump10	] {};
92void()	demon1_jump10	=[ 	$leap10,	demon1_jump1	] {
93self.nextthink = time + 3;
94// if three seconds pass, assume demon is stuck and jump again
95};
96
97void()	demon1_jump11	=[ 	$leap11,	demon1_jump12	] {};
98void()	demon1_jump12	=[ 	$leap12,	demon1_run1	] {};
99
100
101void()	demon1_atta1	=[	$attacka1,		demon1_atta2	] {ai_charge(4);};
102void()	demon1_atta2	=[	$attacka2,		demon1_atta3	] {ai_charge(0);};
103void()	demon1_atta3	=[	$attacka3,		demon1_atta4	] {ai_charge(0);};
104void()	demon1_atta4	=[	$attacka4,		demon1_atta5	] {ai_charge(1);};
105void()	demon1_atta5	=[	$attacka5,		demon1_atta6	] {ai_charge(2); Demon_Melee(200);};
106void()	demon1_atta6	=[	$attacka6,		demon1_atta7	] {ai_charge(1);};
107void()	demon1_atta7	=[	$attacka7,		demon1_atta8	] {ai_charge(6);};
108void()	demon1_atta8	=[	$attacka8,		demon1_atta9	] {ai_charge(8);};
109void()	demon1_atta9	=[	$attacka9,		demon1_atta10] {ai_charge(4);};
110void()	demon1_atta10	=[	$attacka10,		demon1_atta11] {ai_charge(2);};
111void()	demon1_atta11	=[	$attacka11,		demon1_atta12] {Demon_Melee(-200);};
112void()	demon1_atta12	=[	$attacka12,		demon1_atta13] {ai_charge(5);};
113void()	demon1_atta13	=[	$attacka13,		demon1_atta14] {ai_charge(8);};
114void()	demon1_atta14	=[	$attacka14,		demon1_atta15] {ai_charge(4);};
115void()	demon1_atta15	=[	$attacka15,		demon1_run1] {ai_charge(4);};
116
117void()	demon1_pain1	=[	$pain1,		demon1_pain2	] {};
118void()	demon1_pain2	=[	$pain2,		demon1_pain3	] {};
119void()	demon1_pain3	=[	$pain3,		demon1_pain4	] {};
120void()	demon1_pain4	=[	$pain4,		demon1_pain5	] {};
121void()	demon1_pain5	=[	$pain5,		demon1_pain6	] {};
122void()	demon1_pain6	=[	$pain6,		demon1_run1	] {};
123
124void(entity attacker, float damage)	demon1_pain =
125{
126	if (self.touch == Demon_JumpTouch)
127		return;
128
129	if (self.pain_finished > time)
130		return;
131
132	self.pain_finished = time + 1;
133    sound (self, CHAN_VOICE, "demon/dpain1.wav", 1, ATTN_NORM);
134
135	if (random()*200 > damage)
136		return;		// didn't flinch
137
138	demon1_pain1 ();
139};
140
141void()	demon1_die1		=[	$death1,		demon1_die2	] {
142sound (self, CHAN_VOICE, "demon/ddeath.wav", 1, ATTN_NORM);};
143void()	demon1_die2		=[	$death2,		demon1_die3	] {};
144void()	demon1_die3		=[	$death3,		demon1_die4	] {};
145void()	demon1_die4		=[	$death4,		demon1_die5	] {};
146void()	demon1_die5		=[	$death5,		demon1_die6	] {};
147void()	demon1_die6		=[	$death6,		demon1_die7	]
148{self.solid = SOLID_NOT;};
149void()	demon1_die7		=[	$death7,		demon1_die8	] {};
150void()	demon1_die8		=[	$death8,		demon1_die9	] {};
151void()	demon1_die9		=[	$death9,		demon1_die9 ] {};
152
153void() demon_die =
154{
155// check for gib
156	if (self.health < -80)
157	{
158		sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM);
159		ThrowHead ("progs/h_demon.mdl", self.health);
160		ThrowGib ("progs/gib1.mdl", self.health);
161		ThrowGib ("progs/gib1.mdl", self.health);
162		ThrowGib ("progs/gib1.mdl", self.health);
163		return;
164	}
165
166// regular death
167	demon1_die1 ();
168};
169
170
171void() Demon_MeleeAttack =
172{
173	demon1_atta1 ();
174};
175
176
177/*QUAKED monster_demon1 (1 0 0) (-32 -32 -24) (32 32 64) Ambush
178
179*/
180void() monster_demon1 =
181{
182	if (deathmatch)
183	{
184		remove(self);
185		return;
186	}
187	precache_model ("progs/demon.mdl");
188	precache_model ("progs/h_demon.mdl");
189
190	precache_sound ("demon/ddeath.wav");
191	precache_sound ("demon/dhit2.wav");
192	precache_sound ("demon/djump.wav");
193	precache_sound ("demon/dpain1.wav");
194	precache_sound ("demon/idle1.wav");
195	precache_sound ("demon/sight2.wav");
196
197	self.solid = SOLID_SLIDEBOX;
198	self.movetype = MOVETYPE_STEP;
199
200	setmodel (self, "progs/demon.mdl");
201
202	setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX);
203	self.health = 300;
204
205	self.th_stand = demon1_stand1;
206	self.th_walk = demon1_walk1;
207	self.th_run = demon1_run1;
208	self.th_die = demon_die;
209	self.th_melee = Demon_MeleeAttack;		// one of two attacks
210	self.th_missile = demon1_jump1;			// jump attack
211	self.th_pain = demon1_pain;
212
213	walkmonster_start();
214};
215
216
217/*
218==============================================================================
219
220DEMON
221
222==============================================================================
223*/
224
225/*
226==============
227CheckDemonMelee
228
229Returns TRUE if a melee attack would hit right now
230==============
231*/
232float()	CheckDemonMelee =
233{
234	if (enemy_range == RANGE_MELEE)
235	{	// FIXME: check canreach
236		self.attack_state = AS_MELEE;
237		return TRUE;
238	}
239	return FALSE;
240};
241
242/*
243==============
244CheckDemonJump
245
246==============
247*/
248float()	CheckDemonJump =
249{
250	local	vector	dist;
251	local	float	d;
252
253	if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z
254	+ 0.75 * self.enemy.size_z)
255		return FALSE;
256
257	if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z
258	+ 0.25 * self.enemy.size_z)
259		return FALSE;
260
261	dist = self.enemy.origin - self.origin;
262	dist_z = 0;
263
264	d = vlen(dist);
265
266	if (d < 100)
267		return FALSE;
268
269	if (d > 200)
270	{
271		if (random() < 0.9)
272			return FALSE;
273	}
274
275	return TRUE;
276};
277
278float()	DemonCheckAttack =
279{
280	local	vector	vec;
281
282// if close enough for slashing, go for it
283	if (CheckDemonMelee ())
284	{
285		self.attack_state = AS_MELEE;
286		return TRUE;
287	}
288
289	if (CheckDemonJump ())
290	{
291		self.attack_state = AS_MISSILE;
292        sound (self, CHAN_VOICE, "demon/djump.wav", 1, ATTN_NORM);
293		return TRUE;
294	}
295
296	return FALSE;
297};
298
299
300//===========================================================================
301
302void(float side)	Demon_Melee =
303{
304	local	float	ldmg;
305	local vector	delta;
306
307	ai_face ();
308	walkmove (self.ideal_yaw, 12);	// allow a little closing
309
310	delta = self.enemy.origin - self.origin;
311
312	if (vlen(delta) > 100)
313		return;
314	if (!CanDamage (self.enemy, self))
315		return;
316
317    sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM);
318	ldmg = 10 + 5*random();
319	T_Damage (self.enemy, self, self, ldmg);
320
321	makevectors (self.angles);
322	SpawnMeatSpray (self.origin + v_forward*16, side * v_right);
323};
324
325
326void()	Demon_JumpTouch =
327{
328	local	float	ldmg;
329
330	if (self.health <= 0)
331		return;
332
333	if (other.takedamage)
334	{
335		if ( vlen(self.velocity) > 400 )
336		{
337			ldmg = 40 + 10*random();
338			T_Damage (other, self, self, ldmg);
339		}
340	}
341
342	if (!checkbottom(self))
343	{
344		if (self.flags & FL_ONGROUND)
345		{	// jump randomly to not get hung up
346//dprint ("popjump\n");
347	self.touch = SUB_Null;
348	self.think = demon1_jump1;
349	self.nextthink = time + 0.1;
350
351//			self.velocity_x = (random() - 0.5) * 600;
352//			self.velocity_y = (random() - 0.5) * 600;
353//			self.velocity_z = 200;
354//			self.flags = self.flags - FL_ONGROUND;
355		}
356		return;	// not on ground yet
357	}
358
359	self.touch = SUB_Null;
360	self.think = demon1_jump11;
361	self.nextthink = time + 0.1;
362};
363
364