added worldarea -> will be responsible for world map rendering
[dboe.git] / monster.c
blob0bd8e39f72175b229a3eeebcbf66bc34440165c0
1 #include <windows.h>
2 #include "stdio.h"
4 #include "global.h"
5 #include "locutils.h"
6 #include "fields.h"
7 #include "monster.h"
8 #include "text.h"
9 #include "specials.h"
10 #include "exlsound.h"
11 #include "graphics.h"
12 #include "newgraph.h"
14 extern current_town_type far c_town;
15 extern party_record_type far party;
16 extern piles_of_stuff_dumping_type *data_store;
17 extern piles_of_stuff_dumping_type2 *data_store2;
18 extern talking_record_type far talking;
19 extern scenario_data_type far scenario;
21 extern short overall_mode;
22 extern outdoor_record_type far outdoors[2][2];
23 extern unsigned char far out[96][96];
24 extern unsigned char far out_e[96][96];
25 extern unsigned char far combat_terrain[64][64];
26 extern short which_combat_type;
27 extern pc_record_type far adven[6];
28 extern big_tr_type far t_d;
29 extern short monst_target[T_M]; // 0-5 target that pc 6 - no target 100 + x - target monster x
30 extern short spell_caster, missile_firer,current_monst_tactic;
31 extern short far hit_chance[21];
32 extern unsigned char far misc_i[64][64];
33 extern location monster_targs[T_M];
35 extern location pc_pos[6],center;
36 extern short boom_gr[8],futzing;
37 extern Boolean processing_fields,monsters_going;
38 extern town_item_list far t_i;
42 short charm_odds[20] = {90,90,85,80,78, 75,73,60,40,30, 20,10,5,2,1, 0,0,0,0,0};
44 creature_start_type null_start_type = {0,0,{80,80},1,0,0,0,0,0,0,0, 0,-1,-1,-1};
46 monster_record_type return_monster_template(unsigned char store)
47 { monster_record_type monst;
48 short m_num,i;
50 m_num = store;
51 monst = scenario.scen_monsters[store];
52 if (monst.spec_skill == 11)
53 monst.picture_num = 0;
55 monst.m_num = m_num;
56 monst.health = (PSD[306][7] == 0) ? monst.health : monst.health / 2;
58 // now adjust for difficulty
59 monst.health = monst.health * difficulty_adjust();
61 monst.m_health = monst.health; // in scenario file, health is stored in health field
62 monst.max_mp = 0;
63 monst.mp = monst.max_mp;
65 monst.ap = 0;
67 if ((monst.mu > 0) || (monst.cl > 0))
68 monst.max_mp = monst.mp = 12 * monst.level;
70 monst.m_morale = 10 * monst.level;
71 if (monst.level >= 20)
72 monst.m_morale += 10 * (monst.level - 20);
74 monst.morale = monst.m_morale;
75 monst.direction = 0;
76 for (i = 0; i < 15; i++)
77 monst.status[i] = 0;
79 return monst;
82 short difficulty_adjust()
84 short i, j = 0;
85 short to_return = 1;
87 for (i = 0; i < 6; i++)
88 if (adven[i].main_status == 1)
89 j += adven[i].level;
91 if ((scenario.difficulty <= 0) && (j >= 60))
92 to_return++;
93 if ((scenario.difficulty <= 1) && (j >= 130))
94 to_return++;
95 if ((scenario.difficulty <= 2) && (j >= 210))
96 to_return++;
97 return to_return;
100 short out_enc_lev_tot(short which)
102 short count = 0,i;
103 monster_record_type store_m;
104 short num[7] = {22,8,4,4,3,2,1};
106 if (party.out_c[which].what_monst.cant_flee == TRUE)
107 return 10000;
109 for (i = 0; i < 7; i++)
110 if (party.out_c[which].what_monst.monst[i] != 0) {
111 store_m = return_monster_template(party.out_c[which].what_monst.monst[i]);
112 count += store_m.level * num[i];
114 return count;
117 short count_monst()
119 short to_ret = 0,i;
121 for (i = 0; i < T_M; i++)
122 if (c_town.monst.dudes[i].active > 0)
123 to_ret++;
124 return to_ret;
127 void create_wand_monst()
129 short r1,r2,i = 0,num_tries = 0;
130 location p_loc;
132 r1 = get_ran(1,0,3);
133 if (overall_mode == 0)
134 if (is_null_out_wand_entry(outdoors[party.i_w_c.x][party.i_w_c.y].wandering[r1]) == 0) {
135 r2 = get_ran(1,0,3);
136 while ((point_onscreen(outdoors[party.i_w_c.x][party.i_w_c.y].wandering_locs[r2],global_to_local(party.p_loc)) == TRUE)
137 && (num_tries++ < 100))
138 r2 = get_ran(1,0,3);
139 if (is_blocked(outdoors[party.i_w_c.x][party.i_w_c.y].wandering_locs[r2]) == FALSE)
140 place_outd_wand_monst(outdoors[party.i_w_c.x][party.i_w_c.y].wandering_locs[r2],
141 outdoors[party.i_w_c.x][party.i_w_c.y].wandering[r1],0);
144 ////
146 if (overall_mode != 0) // won't place wandering is more than 50 monsters
147 if ((is_null_wand_entry(c_town.town.wandering[r1]) == 0) && (count_monst() <= 50)
148 && (party.m_killed[c_town.town_num] < c_town.town.max_num_monst)) {
149 r2 = get_ran(1,0,3);
150 while ((point_onscreen(c_town.town.wandering_locs[r2],c_town.p_loc) == TRUE) &&
151 (loc_off_act_area(c_town.town.wandering_locs[r2]) == FALSE) && (num_tries++ < 100))
152 r2 = get_ran(1,0,3);
153 for (i = 0; i < 4; i++) {
154 if (c_town.town.wandering[r1].monst[i] != 0) { // place a monster
155 p_loc = c_town.town.wandering_locs[r2];
156 p_loc.x += get_ran(1,0,4) - 2;
157 p_loc.y += get_ran(1,0,4) - 2;
158 if (is_blocked(p_loc) == FALSE)
159 place_monster(c_town.town.wandering[r1].monst[i],p_loc);
160 p_loc = c_town.town.wandering_locs[r2];
161 p_loc.x += get_ran(1,0,4) - 2;
162 p_loc.y += get_ran(1,0,4) - 2;
163 if ((r1 >= 2) && (i == 0) && (is_blocked(p_loc) == FALSE)) // place extra monsters?
164 place_monster(c_town.town.wandering[r1].monst[i],p_loc);
165 p_loc = c_town.town.wandering_locs[r2];
166 p_loc.x += get_ran(1,0,4) - 2;
167 p_loc.y += get_ran(1,0,4) - 2;
168 if ((r1 == 3) && (i == 1) && (is_blocked(p_loc) == FALSE))
169 place_monster(c_town.town.wandering[r1].monst[i],p_loc);
175 void place_outd_wand_monst(location where,out_wandering_type group,short forced)
177 short i = 0,j = 0;
178 location l;
181 while (i < 10) {
182 ////
183 if ((party.out_c[i].exists == FALSE) || ((i == 9) && (forced > 0))) {
184 if ((sd_legit(group.end_spec1,group.end_spec2) == TRUE) && (PSD[group.end_spec1][group.end_spec2] > 0))
185 return;
186 party.out_c[i].exists = TRUE;
187 party.out_c[i].direction = 0;
188 party.out_c[i].what_monst = group;
189 party.out_c[i].which_sector = party.i_w_c;
190 party.out_c[i].m_loc = where;
191 if (party.out_c[i].which_sector.x == 1)
192 party.out_c[i].m_loc.x += 48;
193 if (party.out_c[i].which_sector.y == 1)
194 party.out_c[i].m_loc.y += 48;
195 l = party.out_c[i].m_loc;
196 while ((forced == TRUE) && (is_blocked(l)) && (j < 50)) {
197 l = party.out_c[i].m_loc;
198 l.x += get_ran(1,0,2) - 1;
199 l.y += get_ran(1,0,2) - 1;
200 j++;
202 party.out_c[i].m_loc = l;
204 i = 50;
206 i++;
210 short is_null_wand_entry(wandering_type wand_entry)
212 short i = 0;
214 while (i < 4) {
215 if (wand_entry.monst[i] != 0)
216 return 0;
217 i++;
219 return 1;
222 short is_null_out_wand_entry(out_wandering_type wand_entry)
224 short i = 0;
226 while (i < 7) {
227 if (wand_entry.monst[i] != 0)
228 return 0;
229 i++;
231 return 1;
234 location get_monst_head(short m_num)
236 location l;
238 l = c_town.monst.dudes[m_num].m_loc;
239 if ((c_town.monst.dudes[m_num].m_d.direction < 4) &&
240 (c_town.monst.dudes[m_num].m_d.x_width > 1))
241 l.x++;
243 return l;
246 short get_monst_picnum(unsigned char monst)
248 return scenario.scen_monsters[monst].picture_num;
251 void get_monst_dims(unsigned char monst,short *width, short *height)
254 *width = scenario.scen_monsters[monst].x_width;
255 *height = scenario.scen_monsters[monst].y_width;
258 // Used to set up monsters for outdoor wandering encounters.
259 void set_up_monst(short mode,unsigned char m_num)
260 //mode; // 0 - unfriendly 1 - friendly & fightin'
262 short which;
264 for (which = 0; which < T_M; which++)
265 if (c_town.monst.dudes[which].active == 0) {
266 c_town.monst.dudes[which].active = 2;
267 c_town.monst.dudes[which].summoned = 0;
268 c_town.monst.dudes[which].attitude = mode + 1;
269 c_town.monst.dudes[which].number = m_num;
270 c_town.monst.dudes[which].m_d = return_monster_template(m_num);
271 c_town.monst.dudes[which].mobile = TRUE;
272 c_town.monst.dudes[which].monst_start = null_start_type;
273 which = T_M;
277 void do_monsters()
279 short i,j,r1,target;
280 location dest,l1,l2, dummy_loc = {0,0},store_loc;
281 Boolean acted_yet = FALSE;
282 char debug[60];
284 if (overall_mode == 1)
285 for (i = 0; i < T_M; i++)
286 if ((c_town.monst.dudes[i].active != 0) && (c_town.monst.dudes[i].m_d.status[11] <= 0)
287 && (c_town.monst.dudes[i].m_d.status[12] <= 0)) {
288 // have to pick targets
289 if (c_town.monst.dudes[i].active == 1)
290 target = 6;
291 else {
292 target = monst_pick_target(i); // will return 0 if target party
293 target = switch_target_to_adjacent(i,target);
294 if (target == 0) {
295 if (dist(c_town.monst.dudes[i].m_loc,c_town.p_loc) > 8)
296 target = 6;
297 else target = select_active_pc();
299 if ((c_town.monst.dudes[i].attitude % 2 != 1) && (target < 6))
300 target = 6;
302 monst_target[i] = target;
303 // sprintf((char *)debug," t: %d targets %d.",i,monst_target[i]);
304 // add_string_to_buf((char *) debug);
306 if ((c_town.monst.dudes[i].active == 2)
307 || ((c_town.monst.dudes[i].active != 0) && (c_town.monst.dudes[i].attitude % 2 != 1))) {
308 acted_yet = FALSE;
309 if (((c_town.monst.dudes[i].attitude == 0) || (monst_target[i] == 6)) && (c_town.hostile == 0)) {
310 if (c_town.monst.dudes[i].mobile == TRUE) { // OK, it doesn't see the party or
311 // isn't nasty, and the town isn't totally hostile.
312 if ((c_town.monst.dudes[i].attitude % 2 != 1) || (get_ran(1,0,1) == 0)) {
313 acted_yet = rand_move(i);
315 else acted_yet = seek_party(i,c_town.monst.dudes[i].m_loc,c_town.p_loc);
318 if ((c_town.monst.dudes[i].attitude > 0) || (c_town.hostile == 1)) {
319 if ((c_town.monst.dudes[i].mobile == TRUE) && (monst_target[i] != 6)) {
320 l1 = c_town.monst.dudes[i].m_loc;
321 l2 = (monst_target[i] <= 6) ? c_town.p_loc : c_town.monst.dudes[target - 100].m_loc;
323 if ((c_town.monst.dudes[i].m_d.morale < 0) && (c_town.monst.dudes[i].m_d.spec_skill != 13)
324 && (c_town.monst.dudes[i].m_d.m_type != 8)) {
325 acted_yet = flee_party(i,l1,l2);
326 if (get_ran(1,0,10) < 6)
327 c_town.monst.dudes[i].m_d.morale++;
329 else if (monst_hate_spot(i,&l2) == TRUE)
330 acted_yet = seek_party(i,l1,l2);
331 else if (((c_town.monst.dudes[i].m_d.mu == 0) && (c_town.monst.dudes[i].m_d.mu == 0))
332 || (can_see(l1,l2,0) > 3))
333 acted_yet = seek_party(i,l1,l2);
339 // Make hostile monsters active
340 if ((c_town.monst.dudes[i].active == 1) && (c_town.monst.dudes[i].attitude % 2 == 1)
341 && (dist(c_town.monst.dudes[i].m_loc,c_town.p_loc) <= 8)) {
342 r1 = get_ran(1,1,100);
343 r1 += (party.stuff_done[305][0] > 0) ? 46 : 0;
344 r1 += can_see(c_town.monst.dudes[i].m_loc,c_town.p_loc,0) * 10;
345 if (r1 < 50) {
346 c_town.monst.dudes[i].active = 2;
347 add_string_to_buf("Monster saw you!");
348 // play go active sound
349 switch (c_town.monst.dudes[i].m_d.m_type) {
350 case 0: case 3: case 4: case 5: case 6: case 9:
351 play_sound(18); break;
352 default: play_sound(46); break;
355 for (j = 0; j < T_M; j++)
356 if ((c_town.monst.dudes[j].active == 2)
357 && ((dist(c_town.monst.dudes[i].m_loc,c_town.monst.dudes[j].m_loc) <= 5) == TRUE))
358 c_town.monst.dudes[i].active = 2;
362 if (overall_mode == 0) {
363 for (i = 0; i < 10; i++)
364 if (party.out_c[i].exists == TRUE) {
365 acted_yet = FALSE;
366 l1 = party.out_c[i].m_loc;
367 l2 = party.p_loc;
369 r1 = get_ran(1,1,6);
370 if (r1 == 3)
371 acted_yet = rand_move(i);
372 else acted_yet = seek_party(i,l1,l2);
377 Boolean monst_hate_spot(short which_m,location *good_loc)
379 location prospect,loc;
381 loc = c_town.monst.dudes[which_m].m_loc;
382 if ((misc_i[loc.x][loc.y] & 224)
383 || (c_town.explored[loc.x][loc.y] & 64) // hate regular fields
384 || ((c_town.explored[loc.x][loc.y] & 32) && (c_town.monst.dudes[which_m].m_d.radiate_1 != 2)
385 && (c_town.monst.dudes[which_m].m_d.immunities & 32 == 0)) // hate ice wall?
386 || ((c_town.explored[loc.x][loc.y] & 4) && (c_town.monst.dudes[which_m].m_d.radiate_1 != 1)
387 && (c_town.monst.dudes[which_m].m_d.immunities & 8 == 0)) // hate fire wall?
388 || ((c_town.explored[loc.x][loc.y] & 16) && (c_town.monst.dudes[which_m].m_d.radiate_1 != 6)
389 && (c_town.monst.dudes[which_m].m_d.immunities & 3 == 0)) // hate stink cloud?
390 || ((c_town.explored[loc.x][loc.y] & 128) && (c_town.monst.dudes[which_m].m_d.radiate_1 != 5)
391 && (c_town.monst.dudes[which_m].m_d.immunities & 3 == 0)) // hate sleep cloud?
392 || ((c_town.explored[loc.x][loc.y] & 2) && (c_town.monst.dudes[which_m].m_d.radiate_1 != 3)
393 && (c_town.monst.dudes[which_m].m_d.immunities & 3 == 0)) // hate shock cloud?
394 || (((c_town.monst.dudes[which_m].m_d.mu > 0) || (c_town.monst.dudes[which_m].m_d.cl > 0))
395 && (c_town.explored[loc.x][loc.y] & 8))) // hate antimagic
397 prospect = find_clear_spot(loc,1);
398 if (prospect.x > 0) {
399 *good_loc = prospect;
400 return TRUE;
402 return FALSE;
404 else return FALSE;
407 short monst_pick_target(short which_m)
409 creature_data_type *cur_monst;
410 short r1,targ_pc,targ_m,a,b;
412 cur_monst = &c_town.monst.dudes[which_m];
414 // First, any chance target is screwed?
415 if (monst_target[which_m] >= 100) {
416 if (((cur_monst->attitude % 2 == 1) &&
417 (c_town.monst.dudes[monst_target[which_m] - 100].attitude == cur_monst->attitude)) ||
418 ((cur_monst->attitude % 2 == 0) && (c_town.monst.dudes[monst_target[which_m] - 100].attitude % 2 == 0)))
419 monst_target[which_m] = 6;
420 else if (c_town.monst.dudes[monst_target[which_m] - 100].active == 0)
421 monst_target[which_m] = 6;
423 if (monst_target[which_m] < 6)
424 if (adven[monst_target[which_m]].main_status != 1)
425 monst_target[which_m] = 6;
427 if ((is_combat()) && (cur_monst->attitude % 2 == 1)) {
428 if (spell_caster < 6)
429 if ((get_ran(1,1,5) < 5) && (monst_can_see(which_m,pc_pos[spell_caster]) == TRUE)
430 && (adven[spell_caster].main_status == 1))
431 return spell_caster;
432 if (missile_firer < 6)
433 if ((get_ran(1,1,5) < 3) && (monst_can_see(which_m,pc_pos[missile_firer]) == TRUE)
434 && (adven[missile_firer].main_status == 1))
435 return missile_firer;
436 if (monst_target[which_m] < 6)
437 if ((monst_can_see(which_m,pc_pos[monst_target[which_m]]) == TRUE)
438 && (adven[monst_target[which_m]].main_status == 1))
439 return monst_target[which_m];
442 // if (monst_target[which_m] >= 100) {
443 // if ((can_see(cur_monst->m_loc,c_town.monst.dudes[monst_target[which_m] - 100].m_loc,0) < 4)
444 // && (c_town.monst.dudes[monst_target[which_m] - 100].active > 0))
445 // return monst_target[which_m];
446 // }
448 // Now pick a target pc and a target monst and see which is more attractive
449 targ_pc = monst_pick_target_pc(which_m,cur_monst);
450 targ_m = monst_pick_target_monst(cur_monst);
452 if ((targ_pc != 6) && (targ_m == 6))
453 return targ_pc;
454 if ((targ_pc == 6) && (targ_m != 6))
455 return targ_m;
456 if ((targ_pc == 6) && (targ_m == 6))
457 return 6;
459 if (is_town()) {
460 if (cur_monst->attitude % 2 == 0) {
461 return targ_m;
463 if ((targ_m == 6) && (cur_monst->attitude % 2 == 1))
464 return 0;
465 if (dist(cur_monst->m_loc,c_town.monst.dudes[targ_m - 100].m_loc) <
466 dist(cur_monst->m_loc,c_town.p_loc))
467 return targ_m;
468 else return 0;
470 // Otherwise we're in combat
471 if ((dist(cur_monst->m_loc,c_town.monst.dudes[targ_m - 100].m_loc) ==
472 dist(cur_monst->m_loc,pc_pos[targ_pc])) && (get_ran(1,0,6) < 3))
473 return targ_m;
474 else return targ_pc;
475 if (dist(cur_monst->m_loc,c_town.monst.dudes[targ_m - 100].m_loc) <
476 dist(cur_monst->m_loc,pc_pos[targ_pc]))
477 return targ_m;
478 else return targ_pc;
482 short monst_pick_target_monst(creature_data_type *which_m)
484 short min_dist = 1000,i,cur_targ = 6;
486 for (i = 0; i < T_M; i++) {
487 if ((c_town.monst.dudes[i].active > 0) && // alive
488 (((which_m->attitude % 2 == 1) && (c_town.monst.dudes[i].attitude % 2 == 0)) ||
489 ((which_m->attitude % 2 == 0) && (c_town.monst.dudes[i].attitude % 2 == 1)) ||
490 ((which_m->attitude % 2 == 1) && (c_town.monst.dudes[i].attitude != which_m->attitude))) && // they hate each other
491 ((dist(which_m->m_loc,c_town.monst.dudes[i].m_loc) < min_dist) ||
492 ((dist(which_m->m_loc,c_town.monst.dudes[i].m_loc) == min_dist) && (get_ran(1,0,7) < 4))) &&
493 (monst_can_see(i,c_town.monst.dudes[i].m_loc) == TRUE) ) {
494 min_dist = dist(which_m->m_loc,c_town.monst.dudes[i].m_loc);
495 cur_targ = i + 100;
499 return cur_targ;
502 short monst_pick_target_pc(short m_num,creature_data_type *which_m)
504 short num_tries = 0,r1,store_targ = 6;
506 if (which_m->attitude % 2 == 0)
507 return 6;
508 if (is_town())
509 return 0;
511 // First pick any visible, nearby PC
512 r1 = get_ran(1,0,5);
513 while ((num_tries < 6) && ((adven[r1].main_status != 1) ||
514 (monst_can_see(m_num,pc_pos[r1]) == FALSE))) {
515 r1 = get_ran(1,0,5);
516 num_tries++;
518 if (num_tries < 6)
519 store_targ = r1;
521 // Then, see if target can be replaced with someone nice and close
522 r1 = get_ran(1,0,5);
523 while ((num_tries < 4) && ((adven[r1].main_status != 1) ||
524 (dist(which_m->m_loc,pc_pos[r1]) > 4) ||
525 (monst_can_see(m_num,pc_pos[r1]) == FALSE))) {
526 r1 = get_ran(1,0,5);
527 num_tries++;
530 if (num_tries < 6)
531 return r1;
532 else return store_targ;
535 // returns 6 if no
536 short select_active_pc()
538 short r1, num_tries = 0;
540 r1 = get_ran(1,0,5);
541 while ((adven[r1].main_status != 1) && (num_tries++ < 50))
542 r1 = get_ran(1,0,5);
544 return r1;
547 short closest_pc(location where)
549 short how_close = 200,i,store = 6;
551 for (i = 0; i < 6; i++)
552 if ((adven[i].main_status == 1) && (dist(where,pc_pos[i]) < how_close)) {
553 store = i;
554 how_close = dist(where,pc_pos[i]);
556 return store;
559 short closest_monst(location where,short mode)
560 //mode; // 1 - closest hostile to PCs 2 - closest friendly to PCs
562 short how_close = 200,i,store = 6;
564 for (i = 0; i < T_M; i++)
565 if ((((c_town.monst.dudes[i].attitude % 2 == 1) && (mode == 1)) ||
566 ((c_town.monst.dudes[i].attitude % 2 == 0) && (mode == 2)))
567 && (dist(where,c_town.monst.dudes[i].m_loc) < how_close)) {
568 store = i;
569 how_close = dist(where,c_town.monst.dudes[i].m_loc);
571 return store;
574 short switch_target_to_adjacent(short which_m,short orig_target)
576 location monst_loc;
577 short i,num_adj = 0,targ_pc = 6, targ_m = 6;
579 monst_loc = c_town.monst.dudes[which_m].m_loc;
581 // First, take care of friendly monsters.
582 if (c_town.monst.dudes[which_m].attitude % 2 == 0) {
583 if (orig_target >= 100)
584 if ((c_town.monst.dudes[orig_target - 100].active > 0) &&
585 (monst_adjacent(c_town.monst.dudes[orig_target - 100].m_loc,which_m) == TRUE))
586 return orig_target;
587 for (i = 0; i < T_M; i++)
588 if ((c_town.monst.dudes[i].active > 0) &&
589 (c_town.monst.dudes[i].attitude % 2 == 1) &&
590 (monst_adjacent(c_town.monst.dudes[i].m_loc,which_m) == TRUE))
591 return i + 100;
592 return orig_target;
595 // If we get here while in town, just need to check if switch to pc
596 if ((is_town()) && (monst_adjacent(c_town.p_loc,which_m) == TRUE))
597 return 0;
598 if (is_town())
599 return orig_target;
601 // If target is already adjacent, we're done here.
602 if ((is_combat()) && (orig_target < 6))
603 if ((adven[orig_target].main_status == 1) && (monst_adjacent(pc_pos[orig_target],which_m) == TRUE))
604 return orig_target;
605 if (orig_target >= 100)
606 if ((c_town.monst.dudes[orig_target - 100].active > 0) &&
607 (monst_adjacent(c_town.monst.dudes[orig_target - 100].m_loc,which_m) == TRUE))
608 return orig_target;
610 // Anyone unarmored? Heh heh heh...
611 if (is_combat())
612 for (i = 0; i < 6; i++)
613 if ((adven[i].main_status == 1) && (monst_adjacent(pc_pos[i],which_m) == TRUE) &&
614 (get_encumberance(i) < 2))
615 return i;
617 // Check for a nice, adjacent, friendly monster and maybe attack
618 for (i = 0; i < T_M; i++)
619 if ((c_town.monst.dudes[i].active > 0) &&
620 (c_town.monst.dudes[i].attitude % 2 == 0) &&
621 (monst_adjacent(c_town.monst.dudes[i].m_loc,which_m) == TRUE) &&
622 (get_ran(1,0,2) < 2))
623 return i + 100;
625 // OK. Now if this monster has PCs adjacent, pick one at randomn and hack. Otherwise,
626 // stick with orig. target.
627 for (i = 0; i < 6; i++)
628 if ((adven[i].main_status == 1) && (monst_adjacent(pc_pos[i],which_m) == TRUE))
629 num_adj++;
631 if (num_adj == 0)
632 return orig_target;
634 i = 0;
635 num_adj = get_ran(1,1,num_adj);
636 while ((num_adj > 1) || (adven[i].main_status != 1) || (monst_adjacent(pc_pos[i],which_m) == FALSE)) {
637 if ((adven[i].main_status == 1) && (monst_adjacent(pc_pos[i],which_m) == TRUE))
638 num_adj--;
639 i++;
641 return i;
645 Boolean rand_move(char i)
647 Boolean acted_yet = FALSE;
648 short j;
649 location store_loc;
651 // first, if outdoor, just roam.
652 if (is_out()) {
653 store_loc = random_shift(party.out_c[i].m_loc);
654 return outdoor_move_monster(i,store_loc);
657 if (same_point(monster_targs[i],c_town.monst.dudes[i].m_loc) == TRUE)
658 monster_targs[i].x = 0;
660 // FIrst, try to move to monst_targs. If it don't work, then we'll shift.
661 if (monster_targs[i].x > 0)
662 acted_yet = seek_party(i,c_town.monst.dudes[i].m_loc,monster_targs[i]);
664 if (acted_yet == FALSE) {
665 monster_targs[i].x = 0;
666 for (j = 0; j < 3; j++) {
667 store_loc = c_town.monst.dudes[i].m_loc;
668 store_loc.x += get_ran(1,0,24) - 12;
669 store_loc.y += get_ran(1,0,24) - 12;
670 if ((loc_off_act_area(store_loc) == FALSE) && (can_see(c_town.monst.dudes[i].m_loc,store_loc,0) < 5)) {
671 monster_targs[i] = store_loc; j = 3;
675 if (monster_targs[i].x == 0) {
676 // maybe pick a wand loc, else juist pick a loc
677 j = get_ran(1,0,3);
678 store_loc = c_town.town.wandering_locs[j];
680 if ((loc_off_act_area(store_loc) == FALSE) && (get_ran(1,0,1) == 1))
681 monster_targs[i] = store_loc;
682 else {
683 store_loc = c_town.monst.dudes[i].m_loc;
684 store_loc.x += get_ran(1,0,20) - 10;
685 store_loc.y += get_ran(1,0,20) - 10;
686 if (loc_off_act_area(store_loc) == FALSE)
687 monster_targs[i] = store_loc;
690 if (monster_targs[i].x > 0)
691 acted_yet = seek_party(i,c_town.monst.dudes[i].m_loc,monster_targs[i]);
694 return acted_yet;
701 Boolean seek_party(short i,location l1,location l2)
703 Boolean acted_yet = FALSE;
704 short m,n;
705 if ((l1.x > l2.x) && (l1.y > l2.y))
706 acted_yet = try_move(i,l1,-1,-1);
707 if ((l1.x < l2.x) & (l1.y < l2.y) & (acted_yet == FALSE))
708 acted_yet = try_move(i,l1,1,1);
709 if ((l1.x > l2.x) & (l1.y < l2.y) & (acted_yet == FALSE))
710 acted_yet = try_move(i,l1,-1,1);
711 if ((l1.x < l2.x) & (l1.y > l2.y) & (acted_yet == FALSE))
712 acted_yet = try_move(i,l1,1,-1);
713 if ((l1.x > l2.x) & (acted_yet == FALSE))
714 acted_yet = try_move(i,l1,-1,0);
715 if ((l1.x < l2.x) & (acted_yet == FALSE))
716 acted_yet = try_move(i,l1,1,0);
717 if ( (l1.y < l2.y) & (acted_yet == FALSE))
718 acted_yet = try_move(i,l1,0,1);
719 if ( (l1.y > l2.y) & (acted_yet == FALSE))
720 acted_yet = try_move(i,l1,0,-1);
721 if (acted_yet == FALSE) {
722 futzing++;
723 m = get_ran(1,0,2) - 1;
724 n = get_ran(1,0,2) - 1;
725 acted_yet = try_move(i,l1,m,n);
727 return acted_yet;
730 Boolean flee_party(short i,location l1,location l2)
732 Boolean acted_yet = FALSE;
734 if ((l1.x > l2.x) & (l1.y > l2.y))
735 acted_yet = try_move(i,l1,1,1);
736 if ((l1.x < l2.x) & (l1.y < l2.y) & (acted_yet == FALSE))
737 acted_yet = try_move(i,l1,-1,-1);
738 if ((l1.x > l2.x) & (l1.y < l2.y) & (acted_yet == FALSE))
739 acted_yet = try_move(i,l1,1,-1);
740 if ((l1.x < l2.x) & (l1.y > l2.y) & (acted_yet == FALSE))
741 acted_yet = try_move(i,l1,-1,+1);
742 if ((l1.x > l2.x) & (acted_yet == FALSE))
743 acted_yet = try_move(i,l1,1,0);
744 if ((l1.x < l2.x) & (acted_yet == FALSE))
745 acted_yet = try_move(i,l1,-1,0);
746 if ( (l1.y < l2.y) & (acted_yet == FALSE))
747 acted_yet = try_move(i,l1,0,-1);
748 if ( (l1.y > l2.y) & (acted_yet == FALSE))
749 acted_yet = try_move(i,l1,0,1);
750 if (acted_yet == FALSE) {
751 futzing++;
752 acted_yet = rand_move(i);
754 return acted_yet;
757 Boolean try_move(short i,location start,short x,short y)
759 location dest;
761 dest = start;
762 dest.x = dest.x + x;
763 dest.y = dest.y + y;
766 if (overall_mode == 1)
767 return town_move_monster(i,dest);
768 if (overall_mode == 0)
769 return outdoor_move_monster(i,dest);
770 if (overall_mode == 10)
771 return combat_move_monster((short) i,dest);
772 return 0;
775 Boolean combat_move_monster(short which,location destination)
777 short r1;
780 if (monst_can_be_there(destination,which) == FALSE)
781 return FALSE;
782 else if (monst_check_special_terrain(destination,2,which) == FALSE)
783 return FALSE;
784 else {
785 //if (point_onscreen(destination,center) == TRUE) {
786 // print_nums(999, c_town.monst.dudes[which].m_loc.x,c_town.monst.dudes[which].m_loc.y);
787 // print_nums(monst_target[which],destination.x,destination.y);
788 // }
789 c_town.monst.dudes[which].m_d.direction =
790 set_direction(c_town.monst.dudes[which].m_loc, destination);
791 c_town.monst.dudes[which].m_loc = destination;
792 monst_inflict_fields(which);
794 if ((monst_target[which] != 6) && (point_onscreen(destination,center) == TRUE)) {
795 if (is_combat())
796 move_sound(combat_terrain[destination.x][destination.y],
797 (short) c_town.monst.dudes[which].m_d.ap);
798 else move_sound(t_d.terrain[destination.x][destination.y],
799 (short) c_town.monst.dudes[which].m_d.ap);
802 return TRUE;
804 return FALSE;
807 // Looks at all spaces within 2, looking for a spot which is clear of nastiness and beings
808 // returns {0,0} if none found
809 // THIS MAKES NO ADJUSTMENTS FOR BIG MONSTERS!!!
810 location find_clear_spot(location from_where,short mode)
811 //mode; // 0 - normal 1 - prefer adjacent space
813 location loc,store_loc = {0,0};
814 short num_tries = 0,r1;
816 while (num_tries < 75) {
817 num_tries++;
818 loc = from_where;
819 r1 = get_ran(1,-2,2);
820 loc.x = loc.x + r1;
821 r1 = get_ran(1,-2,2);
822 loc.y = loc.y + r1;
823 if ((loc_off_act_area(loc) == FALSE) && (is_blocked(loc) == FALSE)
824 && (can_see(from_where,loc,1) == 0)
825 && (!(is_combat()) || (pc_there(loc) == 6))
826 && (!(is_town()) || (same_point(loc,c_town.p_loc) == FALSE))
827 && (!(misc_i[loc.x][loc.y] & 248)) &&
828 (!(c_town.explored[loc.x][loc.y] & 254))) {
829 if ((mode == 0) || ((mode == 1) && (adjacent(from_where,loc) == TRUE)))
830 return loc;
831 else store_loc = loc;
834 return store_loc;
837 short pc_there(location where)
839 short i;
841 for (i = 0; i < 6; i++)
842 if ((same_point(where,pc_pos[i]) == TRUE) && (adven[i].main_status == 1))
843 return i;
844 return 6;
847 location random_shift(location start)
849 location store;
851 store = start;
852 store.x = store.x + get_ran(1,0,2) - 1;
853 store.y = store.y + get_ran(1,0,2) - 1;
855 return store;
858 Boolean outdoor_move_monster(short num,location dest)
861 if ((outd_is_blocked(dest) == FALSE) && (outd_is_special(dest) == FALSE) &&
862 (same_point(dest, party.p_loc) != TRUE) &&
863 ((out[dest.x][dest.y] > 21) || (out[dest.x][dest.y] < 5))) {
864 party.out_c[num].direction =
865 set_direction(party.out_c[num].m_loc, dest);
866 party.out_c[num].m_loc = dest;
867 return TRUE;
869 else return FALSE;
872 Boolean town_move_monster(short num,location dest)
874 if (monst_check_special_terrain(dest,1,num) == FALSE)
875 return FALSE;
877 if (monst_can_be_there(dest,num) == TRUE) {
878 c_town.monst.dudes[num].m_d.direction =
879 set_direction(c_town.monst.dudes[num].m_loc, dest);
880 c_town.monst.dudes[num].m_loc = dest;
881 monst_inflict_fields(num);
882 return TRUE;
884 else return FALSE;
887 Boolean monster_placid(short m_num)
889 if ((c_town.monst.dudes[m_num].attitude == 0) ||
890 ((c_town.monst.dudes[m_num].attitude == 2) && (party.stuff_done[305][9] == 0)))
891 { return TRUE;}
892 else { return FALSE;}
895 // This damages a monster by any fields it's in, and destroys any barrels or crates
896 // it's stiing on.
897 void monst_inflict_fields(short which_monst)
899 short i,j,r1,k;
900 location where_check;
901 creature_data_type *which_m;
903 if (c_town.monst.dudes[which_monst].active == 0)
904 return;
906 which_m = &c_town.monst.dudes[which_monst];
907 for (i = 0; i < c_town.monst.dudes[which_monst].m_d.x_width; i++)
908 for (j = 0; j < c_town.monst.dudes[which_monst].m_d.y_width; j++)
909 if (c_town.monst.dudes[which_monst].active > 0) {
910 where_check.x = c_town.monst.dudes[which_monst].m_loc.x + i;
911 where_check.y = c_town.monst.dudes[which_monst].m_loc.y + j;
912 if (is_quickfire(where_check.x,where_check.y)) {
913 r1 = get_ran(2,1,8);
914 damage_monst(which_monst,7,r1,0,1);
915 break;
917 if (is_blade_wall(where_check.x,where_check.y)) {
918 r1 = get_ran(6,1,8);
919 damage_monst(which_monst,7,r1,0,0);
920 break;
922 if (is_force_wall(where_check.x,where_check.y)) {
923 r1 = get_ran(3,1,6);
924 damage_monst(which_monst,7,r1,0,3);
925 break;
927 if (is_sleep_cloud(where_check.x,where_check.y)) {
928 charm_monst(which_m,0,11,3);
929 break;
931 if (is_ice_wall(where_check.x,where_check.y)) {
932 r1 = get_ran(3,1,6);
933 if (c_town.monst.dudes[which_monst].m_d.spec_skill != 23)
934 damage_monst(which_monst,7,r1,0,5);
935 break;
937 if (is_scloud(where_check.x,where_check.y)) {
938 r1 = get_ran(1,2,3);
939 curse_monst(which_m,r1);
940 break;
942 if ((is_web(where_check.x,where_check.y)) && (which_m->m_d.m_type != 12)) {
943 monst_spell_note(which_m->number,19);
944 r1 = get_ran(1,2,3);
945 web_monst(which_m,r1);
946 take_web(where_check.x,where_check.y);
947 break;
949 if (is_fire_wall(where_check.x,where_check.y)) {
950 r1 = get_ran(2,1,6);
951 if (c_town.monst.dudes[which_monst].m_d.spec_skill != 22)
952 damage_monst(which_monst,7,r1,0,1);
953 break;
956 if (c_town.monst.dudes[which_monst].active > 0)
957 for (i = 0; i < c_town.monst.dudes[which_monst].m_d.x_width; i++)
958 for (j = 0; j < c_town.monst.dudes[which_monst].m_d.y_width; j++) {
959 where_check.x = c_town.monst.dudes[which_monst].m_loc.x + i;
960 where_check.y = c_town.monst.dudes[which_monst].m_loc.y + j;
961 if ((is_crate(where_check.x,where_check.y)) ||
962 (is_barrel(where_check.x,where_check.y)) )
963 for (k = 0; k < NUM_TOWN_ITEMS; k++)
964 if ((t_i.items[k].variety > 0) && (is_contained(t_i.items[k]) == TRUE)
965 && (same_point(t_i.items[k].item_loc,where_check) == TRUE))
966 t_i.items[k].item_properties = t_i.items[k].item_properties & 247;
967 take_crate(where_check.x,where_check.y);
968 take_barrel(where_check.x,where_check.y);
969 if (is_fire_barrier(where_check.x,where_check.y)) {
970 r1 = get_ran(2,1,10);
971 damage_monst(which_monst,7,r1,0,1);
977 Boolean monst_check_special_terrain(location where_check,short mode,short which_monst)
978 //mode; // 1 - town 2 - combat
980 char debug[60];
981 unsigned char ter;
982 short r1,i,j,choice,door_pc,guts = 0;
983 Boolean can_enter = TRUE,mage = FALSE;
984 location out_where,from_loc,to_loc;
985 Boolean do_look = FALSE; // If becomes true, terrain changed, so need to update what party sees
986 creature_data_type *which_m;
987 short ter_abil;
989 from_loc = c_town.monst.dudes[which_monst].m_loc;
990 switch (mode) {
991 case 1:
992 ter = t_d.terrain[where_check.x][where_check.y];
993 break;
994 case 2:
995 ter = combat_terrain[where_check.x][where_check.y];
996 break;
998 which_m = &c_town.monst.dudes[which_monst];
999 ter_abil = scenario.ter_types[ter].special;
1001 if ((mode > 0) && (ter_abil >= 16) &&
1002 (ter_abil <= 19)) {
1003 if (
1004 ((ter_abil == 16) && (where_check.y > from_loc.y)) ||
1005 ((ter_abil == 17) && (where_check.x < from_loc.x)) ||
1006 ((ter_abil == 18) && (where_check.y < from_loc.y)) ||
1007 ((ter_abil == 19) && (where_check.x > from_loc.x)) ) {
1008 return FALSE;
1012 // begin determining guts, which determines how enthused the monst is about entering
1013 // nasty barriers
1014 if ((which_m->m_d.mu > 0) || (which_m->m_d.cl > 0))
1015 mage = TRUE;
1016 if (which_m->m_d.spec_skill == 13)
1017 guts = 20;
1018 else guts = get_ran(1,1,(which_m->m_d.level / 2));
1019 guts += which_m->m_d.health / 20;
1020 if (mage == TRUE)
1021 guts = guts / 2;
1022 if (which_m->attitude == 0)
1023 guts = guts / 2;
1025 if ((is_antimagic(where_check.x,where_check.y)) && (mage == TRUE))
1026 return FALSE;
1027 if ((is_fire_wall(where_check.x,where_check.y)) && (which_m->m_d.spec_skill != 22)) {
1028 if (guts < 3) return FALSE;
1030 if (is_force_wall(where_check.x,where_check.y)) {
1031 if (guts < 4) return FALSE;
1033 if ((is_ice_wall(where_check.x,where_check.y)) && (which_m->m_d.spec_skill != 23)) {
1034 if (guts < 5) return FALSE;
1036 if (is_sleep_cloud(where_check.x,where_check.y)) {
1037 if (guts < 8) return FALSE;
1039 if (is_blade_wall(where_check.x,where_check.y)) {
1040 if (guts < 8) return FALSE;
1042 if (is_quickfire(where_check.x,where_check.y)) {
1043 if (guts < 8) return FALSE;
1045 if (is_scloud(where_check.x,where_check.y)) {
1046 if (guts < 4) return FALSE;
1048 if ((is_web(where_check.x,where_check.y)) && (which_m->m_d.m_type != 12)) {
1049 if (guts < 3) return FALSE;
1051 if (is_fire_barrier(where_check.x,where_check.y)) {
1052 if ((which_m->attitude % 2 == 1) && (get_ran(1,0,100) < (which_m->m_d.mu * 10 + which_m->m_d.cl * 4))) {
1053 play_sound(60);
1054 add_string_to_buf("Monster breaks barrier.");
1055 take_fire_barrier(where_check.x,where_check.y);
1057 else {
1058 if (guts < 6) return FALSE;
1059 r1 = get_ran(1,0,10);
1060 if ((r1 < 8) || (monster_placid(which_monst)))
1061 can_enter = FALSE;
1064 if (is_force_barrier(where_check.x,where_check.y)) { /// Not in big towns
1065 if ((which_m->attitude % 2 == 1) && (get_ran(1,0,100) < (which_m->m_d.mu * 10 + which_m->m_d.cl * 4))
1066 && (c_town.town_num >= 20)) {
1067 play_sound(60);
1068 add_string_to_buf("Monster breaks barrier.");
1069 take_force_barrier(where_check.x,where_check.y);
1071 else can_enter = FALSE;
1073 if (is_crate(where_check.x,where_check.y)) {
1074 if (monster_placid(which_monst))
1075 can_enter = FALSE;
1076 else {
1077 to_loc = push_loc(from_loc,where_check);
1078 take_crate((short) where_check.x,(short) where_check.y);
1079 if (to_loc.x > 0)
1080 make_crate((short) to_loc.x,(short) to_loc.y);
1081 for (i = 0; i < NUM_TOWN_ITEMS; i++)
1082 if ((t_i.items[i].variety > 0) && (same_point(t_i.items[i].item_loc,where_check))
1083 && (is_contained(t_i.items[i]) == TRUE))
1084 t_i.items[i].item_loc = to_loc;
1087 if (is_barrel(where_check.x,where_check.y)) {
1088 if (monster_placid(which_monst))
1089 can_enter = FALSE;
1090 else {
1091 to_loc = push_loc(from_loc,where_check);
1092 take_barrel((short) where_check.x,(short) where_check.y);
1093 if (to_loc.x > 0)
1094 make_barrel((short) to_loc.x,(short) to_loc.y);
1095 for (i = 0; i < NUM_TOWN_ITEMS; i++)
1096 if ((t_i.items[i].variety > 0) && (same_point(t_i.items[i].item_loc,where_check))
1097 && (is_contained(t_i.items[i]) == TRUE))
1098 t_i.items[i].item_loc = to_loc;
1102 if (monster_placid(which_monst) && // monstyers don't hop into bed when things are calm
1103 (scenario.ter_types[ter].picture == 143))
1104 can_enter = FALSE;
1105 if ((scenario.ter_types[ter].picture <= 212) && (scenario.ter_types[ter].picture >= 207))
1106 can_enter = FALSE;
1107 if (ter == 90) {
1108 if ((is_combat()) && (which_combat_type == 0)) {
1109 c_town.monst.dudes[which_monst].active = 0;
1110 add_string_to_buf("Monster escaped! ");
1112 return FALSE;
1114 switch (ter_abil) {
1115 // changing ter
1116 case 1:
1117 can_enter = FALSE;
1118 if (!(monster_placid(which_monst))) {
1119 t_d.terrain[where_check.x][where_check.y] = scenario.ter_types[ter].flag1;
1120 combat_terrain[where_check.x][where_check.y] = scenario.ter_types[ter].flag1;
1121 do_look = TRUE;
1122 if (point_onscreen(center,where_check))
1123 play_sound(scenario.ter_types[ter].flag2);
1125 break;
1127 case 20: case 21: case 15:
1128 can_enter = FALSE;
1129 break;
1131 case 2:
1132 if (c_town.monst.dudes[which_monst].m_d.immunities & 8)
1133 return TRUE;
1134 else return FALSE;
1135 break;
1138 // Action may change terrain, so update what's been seen
1139 if (do_look == TRUE) {
1140 if (is_town())
1141 update_explored(c_town.p_loc);
1142 if (is_combat())
1143 for (i = 0; i < 6; i++)
1144 if (adven[i].main_status == 1)
1145 update_explored(pc_pos[i]);
1148 return can_enter;
1151 void forced_place_monster(unsigned char which,location where)
1153 Boolean free_spot = FALSE;
1154 short i = 0,r1;
1156 while ((free_spot == FALSE) && (i < T_M)) {
1157 if (c_town.monst.dudes[i].active == 0)
1158 free_spot = TRUE;
1159 i++;
1162 r1 = get_ran(1,0,59);
1163 while ((c_town.monst.dudes[r1].monst_start.spec1 != 0) || (c_town.monst.dudes[r1].monst_start.spec2 != 0));
1164 if (free_spot == FALSE)
1165 c_town.monst.dudes[r1].active = 0;
1166 place_monster(which,where);
1169 void magic_adjust(creature_data_type *which_m,short *how_much)
1171 if (which_m->m_d.spec_skill == 26) {
1172 *how_much = 0;
1173 which_m->m_d.health += 3;
1175 if (which_m->m_d.immunities & 1)
1176 *how_much = *how_much / 2;
1177 if (which_m->m_d.immunities & 2)
1178 *how_much = 0; /* crash!! */
1181 void poison_monst(creature_data_type *which_m,short how_much)
1183 if (which_m->m_d.immunities & 64)
1184 how_much = how_much / 2;
1185 if (which_m->m_d.immunities & 128) {
1186 monst_spell_note(which_m->number,10);
1187 return;
1189 which_m->m_d.status[2] = min(8, which_m->m_d.status[2] + how_much);
1190 monst_spell_note(which_m->number,(how_much == 0) ? 10 : 4);
1193 void acid_monst(creature_data_type *which_m,short how_much)
1195 short i;
1197 i = how_much;
1198 magic_adjust(which_m,&i);
1199 how_much = i;
1200 which_m->m_d.status[13] = minmax(-8,8, which_m->m_d.status[13] + how_much);
1201 monst_spell_note(which_m->number,31);
1205 void slow_monst(creature_data_type *which_m,short how_much)
1207 short i;
1209 i = how_much;
1210 magic_adjust(which_m,&i);
1211 how_much = i;
1212 which_m->m_d.status[3] = minmax(-8,8, which_m->m_d.status[3] - how_much);
1213 monst_spell_note(which_m->number,(how_much == 0) ? 10 : 2);
1216 void curse_monst(creature_data_type *which_m,short how_much)
1218 short i;
1220 i = how_much;
1221 magic_adjust(which_m,&i);
1222 how_much = i;
1225 which_m->m_d.status[1] = minmax(-8,8, which_m->m_d.status[1] - how_much);
1226 monst_spell_note(which_m->number,(how_much == 0) ? 10 : 5);
1229 void web_monst(creature_data_type *which_m,short how_much)
1231 short i;
1233 i = how_much;
1234 magic_adjust(which_m,&i);
1235 how_much = i;
1236 which_m->m_d.status[6] = minmax(-8,8, which_m->m_d.status[6] + how_much);
1237 monst_spell_note(which_m->number,(how_much == 0) ? 10 : 19);
1240 void scare_monst(creature_data_type *which_m,short how_much)
1242 short i;
1244 i = how_much;
1245 magic_adjust(which_m,&i);
1246 how_much = i;
1247 which_m->m_d.morale = which_m->m_d.morale - how_much;
1248 monst_spell_note(which_m->number,(how_much == 0) ? 10 : 1);
1251 void disease_monst(creature_data_type *which_m,short how_much)
1253 short i;
1255 i = how_much;
1256 magic_adjust(which_m,&i);
1257 how_much = i;
1258 which_m->m_d.status[7] = minmax(-8,8, which_m->m_d.status[7] + how_much);
1259 monst_spell_note(which_m->number,(how_much == 0) ? 10 : 25);
1263 void dumbfound_monst(creature_data_type *which_m,short how_much)
1265 short i;
1267 i = how_much;
1268 magic_adjust(which_m,&i);
1269 how_much = i;
1270 which_m->m_d.status[9] = minmax(-8,8, which_m->m_d.status[9] + how_much);
1271 monst_spell_note(which_m->number,(how_much == 0) ? 10 : 22);
1275 void charm_monst(creature_data_type *which_m,short penalty,short which_status,short amount)
1276 // Also used for sleep and paralyze, which_statys is 0 means charm
1278 short r1;
1280 if ((which_status == 11) && (which_m->number >= 138) && (which_m->number <= 142))
1281 return;
1282 if ((which_status == 11) && (which_m->m_d.m_type == 8))
1283 return;
1284 r1 = get_ran(1,0,100);
1285 if (which_m->m_d.immunities & 1)
1286 r1 = r1 * 2;
1287 if (which_m->m_d.immunities & 2)
1288 r1 = 200;
1289 r1 += penalty;
1290 if (which_status == 11)
1291 r1 -= 25;
1292 if (which_status == 12)
1293 r1 -= 15;
1294 if ((which_status == 11) && (which_m->m_d.spec_skill == 32))
1295 return;
1297 if (r1 > charm_odds[which_m->m_d.level / 2]) {
1298 //one_sound(68);
1299 monst_spell_note(which_m->number,10);
1301 else {
1302 if (which_status == 0) {
1303 which_m->attitude = 2;
1304 monst_spell_note(which_m->number,23);
1306 else {
1307 which_m->m_d.status[which_status] = amount;
1308 if (which_status == 11)
1309 monst_spell_note(which_m->number,28);
1310 if (which_status == 12)
1311 monst_spell_note(which_m->number,30);
1313 //one_sound(53);
1316 void record_monst(creature_data_type *which_m)
1318 short r1;
1319 char str[60];
1321 r1 = get_ran(1,0,100);
1322 r1 = (r1 * 7) / 10;
1324 if ((which_m->m_d.x_width > 1) || (which_m->m_d.y_width > 1)) {
1325 ASB("Capture Soul: Monster is too big.");
1327 else if ((r1 > charm_odds[which_m->m_d.level / 2]) || (which_m->m_d.spec_skill == 12)
1328 || (which_m->m_d.m_type == 3)) {
1329 monst_spell_note(which_m->number,10);
1330 play_sound(68);
1332 else {
1333 monst_spell_note(which_m->number,24);
1334 r1 = get_ran(1,0,3);
1335 if (party.imprisoned_monst[r1] == 0)
1336 party.imprisoned_monst[r1] = which_m->number;
1337 else {
1338 r1 = get_ran(1,0,3);
1339 party.imprisoned_monst[r1] = which_m->number;
1341 ASB("Capture Soul: Success!");
1342 sprintf((char *)str," Caught in slot %d.",r1 + 1);
1343 add_string_to_buf((char *)str);
1344 play_sound(53);
1347 // returns 90 is no placement, OW returns # of spot
1348 short place_monster(unsigned char which,location where)
1350 short i = 0,x,y,j;
1352 while ((i < T_M) && ((c_town.monst.dudes[i].active != 0) ||
1353 (c_town.monst.dudes[i].monst_start.spec_enc_code > 0))) {
1354 i++;
1357 if (i < T_M) {
1358 c_town.monst.dudes[i].m_d = return_monster_template((unsigned char) which);
1359 c_town.monst.dudes[i].attitude = scenario.scen_monsters[which].default_attitude;
1360 if (c_town.monst.dudes[i].attitude % 2 == 0)
1361 c_town.monst.dudes[i].attitude = 1;
1362 c_town.monst.dudes[i].mobile = TRUE;
1363 c_town.monst.dudes[i].active = 2;
1364 c_town.monst.dudes[i].number = which;
1365 c_town.monst.dudes[i].m_loc = where;
1366 c_town.monst.dudes[i].summoned = 0;
1367 c_town.monst.dudes[i].monst_start = null_start_type;
1368 monst_target[i] = 6;
1370 if (c_town.monst.dudes[i].m_d.picture_num < 1000) {
1371 add_monst_graphic(which,1);
1374 take_crate(where.x,where.y);
1375 take_barrel(where.x,where.y);
1377 return i;
1379 return 90;
1382 // returns TRUE if placement was successful
1383 Boolean summon_monster(unsigned char which,location where,short duration,short given_attitude)
1384 //which; // if in town, this is caster loc., if in combat, this is where to try
1385 // to put monster
1387 location loc;
1388 short which_m,spot;
1390 if ((is_town()) || (monsters_going)) {
1391 // Ooooh ... mondo kludge. Need to find caster's attitude to give it to monst.
1392 which_m = monst_there(where);
1393 // if (pc_there(where) < 6)
1394 // which_att = 2;
1395 // else if (which_m == 90)
1396 // which_att = 1;
1397 // else which_att = c_town.monst.dudes[which_m].attitude;
1398 loc = find_clear_spot(where,0);
1399 if (loc.x == 0)
1400 return FALSE;
1402 else {
1403 // pc may be summoning using item, in which case where will be pc's space, so fix
1404 if (pc_there(where) < 6) {
1405 where = find_clear_spot(where,0);
1406 if (where.x == 0)
1407 return FALSE;
1409 if ((is_barrel(where.x,where.y)) || (is_crate(where.x,where.y)))
1410 return FALSE;
1411 loc = where;
1414 spot = place_monster(which,loc);
1415 if (spot >= T_M) {
1416 if (duration < 100)
1417 add_string_to_buf(" Too many monsters.");
1418 //ASB(" Monster fails to summon monster.");
1419 return FALSE;
1421 //play_sound(61);
1423 // if (duration < 100)
1424 c_town.monst.dudes[spot].attitude = given_attitude;
1425 // else c_town.monst.dudes[spot].attitude = which_att;
1427 if (which > 0) {//monster here for good
1428 c_town.monst.dudes[spot].summoned = duration;
1429 monst_spell_note(which,21);
1431 else c_town.monst.dudes[spot].summoned = 0;
1433 return TRUE;
1436 void activate_monsters(short code,short attitude)
1438 short i,pict;
1439 unsigned char which;
1441 if (code == 0)
1442 return;
1443 for (i = 0; i < T_M; i++)
1444 if (c_town.monst.dudes[i].monst_start.spec_enc_code == code)
1446 c_town.monst.dudes[i].monst_start.spec_enc_code = 0;
1447 c_town.monst.dudes[i].active = 2;
1448 which = c_town.monst.dudes[i].number;
1449 c_town.monst.dudes[i].attitude = t_d.creatures[i].start_attitude;
1451 c_town.monst.dudes[i].summoned = 0;
1452 c_town.monst.dudes[i].m_loc = t_d.creatures[i].start_loc;
1453 c_town.monst.dudes[i].m_d = return_monster_template(c_town.monst.dudes[i].number);
1454 monst_target[i] = 6;
1456 add_monst_graphic(c_town.monst.dudes[i].number,1);
1457 take_crate(c_town.monst.dudes[i].m_loc.x,c_town.monst.dudes[i].m_loc.y);
1458 take_barrel(c_town.monst.dudes[i].m_loc.x,c_town.monst.dudes[i].m_loc.y);
1462 short get_encumberance(short pc_num)
1464 short store = 0,i,what_val;
1466 for (i = 0; i < 16; i++)
1467 if (adven[pc_num].equip[i] == TRUE) {
1468 what_val = adven[pc_num].items[i].awkward;
1469 if ((what_val == 1) && (get_ran(1,0,130) < hit_chance[adven[pc_num].skills[8]]))
1470 what_val--;
1471 if ((what_val > 1) && (get_ran(1,0,70) < hit_chance[adven[pc_num].skills[8]]))
1472 what_val--;
1473 store += what_val;
1475 return store;
1478 short get_summon_monster(short summon_class)
1480 short i,j;
1482 for (i = 0; i < 200; i++) {
1483 j = get_ran(1,0,255);
1484 if (scenario.scen_monsters[j].summon_type == summon_class) {
1485 return j;
1488 ASB(" Summon failed.");
1489 return -1;