1 /*
2  *  combat.h - Combat scheduling.
3  *
4  *  Copyright (C) 2000-2013  The Exult Team
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24 
25 #include <memory>
26 
27 #include "actors.h"
28 #include "combat.h"
29 #include "combat_opts.h"
30 #include "gamewin.h"
31 #include "gameclk.h"
32 #include "gamemap.h"
33 #include "paths.h"
34 #include "Astar.h"
35 #include "actions.h"
36 #include "items.h"
37 #include "effects.h"
38 #include "Audio.h"
39 #include "ready.h"
40 #include "game.h"
41 #include "monstinf.h"
42 #include "ucmachine.h"
43 #include "game.h"
44 #include "Gump_manager.h"
45 #include "spellbook.h"
46 #include "animate.h"
47 #include "ucsched.h"
48 #include "ucscriptop.h"
49 #include "cheat.h"
50 #include "ammoinf.h"
51 #include "weaponinf.h"
52 #include "ready.h"
53 #include "usefuns.h"
54 
55 using std::cout;
56 using std::endl;
57 using std::rand;
58 using std::list;
59 
60 unsigned long Combat_schedule::battle_time = static_cast<unsigned long>(-30000);
61 unsigned long Combat_schedule::battle_end_time = 0;
62 
63 bool Combat::paused = false;
64 int Combat::difficulty = 0;
65 Combat::Mode Combat::mode = Combat::original;
66 bool Combat::show_hits = false;
67 bool Combat::charmed_more_difficult = false;
68 
69 extern bool combat_trace;
70 
71 const unsigned int dex_to_attack = 30;
72 
not_in_melee_range(const Weapon_info * winf,int dist,int reach)73 static inline bool not_in_melee_range(
74     const Weapon_info *winf,        // 0 for monsters or natural weaponry.
75     int dist,
76     int reach
77 ) {
78 	if (!winf)
79 		return dist > reach;
80 	return (winf->get_uses() == Weapon_info::ranged) || (dist > reach);
81 }
82 
83 /*
84  *  Is a given ammo shape in a given family.
85  */
86 
In_ammo_family(int shnum,int family)87 bool In_ammo_family(int shnum, int family) {
88 	if (shnum == family)
89 		return true;
90 	const Ammo_info *ainf = ShapeID::get_info(shnum).get_ammo_info();
91 	return ainf != nullptr && ainf->get_family_shape() == family;
92 }
93 
94 /*
95  *  Start music if battle has recently started.
96  */
97 
start_battle()98 void Combat_schedule::start_battle(
99 ) {
100 	if (started_battle)
101 		return;
102 	// But only if Avatar is main char.
103 	if (gwin->get_camera_actor() != gwin->get_main_actor())
104 		return;
105 	unsigned long curtime = Game::get_ticks();
106 	// If this is the avatar, and it has been at least .5 minute since last
107 	// start, then change music. This allows the danger music to be heard.
108 	Game_object *target = npc->get_target();
109 	if (npc == gwin->get_main_actor() && curtime - battle_time >= 30000 &&
110 	        (!opponents.empty() || (target && target->as_actor()))) {
111 		Audio::get_ptr()->start_music_combat((rand() % 2) ?
112 		                                     CSAttacked1 : CSAttacked2, false);
113 		battle_time = curtime;
114 		battle_end_time = curtime - 1;
115 	}
116 	started_battle = true;
117 }
118 
119 /*
120  *  This (static) method is called when a monster dies.  It checks to
121  *  see if there are still hostile NPC's around.  If not, it plays
122  *  'victory' music.
123  */
124 
monster_died()125 void Combat_schedule::monster_died(
126 ) {
127 	if (battle_end_time >= battle_time)// Battle raging?
128 		return;         // No, it's over.
129 	Actor_vector nearby;        // Get all nearby NPC's.
130 	gwin->get_nearby_npcs(nearby);
131 	for (auto *actor : nearby) {
132 		if (!actor->is_dead() &&
133 		        actor->get_attack_mode() != Actor::flee &&
134 		        actor->get_effective_alignment() >= Actor::evil)
135 			return;     // Still possible enemies.
136 	}
137 	battle_end_time = Game::get_ticks();
138 	// Figure #seconds battle lasted.
139 	unsigned long len = (battle_end_time - battle_time) / 1000;
140 	bool hard = len > 15u && (rand() % 60u < len);
141 	Audio::get_ptr()->start_music_combat(hard ? CSBattle_Over
142 	                                     : CSVictory, false);
143 }
144 
145 /*
146  *  This (static) method is called to stop attacking a given NPC.
147  *  This can happen because the NPC died, fell asleep or became
148  *  invisible.
149  */
150 
stop_attacking_npc(Game_object * npc)151 void Combat_schedule::stop_attacking_npc(
152     Game_object *npc
153 ) {
154 	Actor_vector nearby;        // Get all nearby NPC's.
155 	gwin->get_nearby_npcs(nearby);
156 	for (auto *actor : nearby) {
157 		if (actor->get_target() == npc)
158 			actor->set_target(nullptr);
159 	}
160 }
161 
162 /*
163  *  This (static) method is called to stop attacking a given NPC.
164  *  This can happen because the NPC died or fell asleep.
165  */
166 
stop_attacking_invisible(Game_object * npc)167 void Combat_schedule::stop_attacking_invisible(
168     Game_object *npc
169 ) {
170 	Actor_vector nearby;        // Get all nearby NPC's.
171 	gwin->get_nearby_npcs(nearby);
172 	for (auto *actor : nearby) {
173 		if (actor->get_target() == npc && !actor->can_see_invisible())
174 			actor->set_target(nullptr);
175 	}
176 }
177 
178 /*
179  *  Can a given shape teleport? summon?  turn invisible?
180  */
181 
Can_teleport(Actor * npc)182 static bool Can_teleport(
183     Actor *npc
184 ) {
185 	if (npc->get_flag(Obj_flags::no_spell_casting))
186 		return false;
187 	return npc->get_info().can_teleport();
188 }
189 
Can_summon(Actor * npc)190 static bool Can_summon(
191     Actor *npc
192 ) {
193 	if (npc->get_flag(Obj_flags::no_spell_casting))
194 		return false;
195 	return npc->get_info().can_summon();
196 }
197 
Can_be_invisible(Actor * npc)198 static bool Can_be_invisible(
199     Actor *npc
200 ) {
201 	if (npc->get_flag(Obj_flags::no_spell_casting))
202 		return false;
203 	return npc->get_info().can_be_invisible();
204 }
205 
206 /*
207  *  Certain monsters (wisps, mages) can teleport during battle.
208  */
209 
teleport()210 bool Combat_schedule::teleport(
211 ) {
212 	Game_object *trg = npc->get_target();   // Want to get close to targ.
213 	if (!trg)
214 		return false;
215 	unsigned int curtime = SDL_GetTicks();
216 	if (curtime < teleport_time)
217 		return false;
218 	teleport_time = curtime + 2000 + rand() % 2000;
219 	Tile_coord dest = trg->get_tile();
220 	dest.tx += 4 - rand() % 8;
221 	dest.ty += 4 - rand() % 8;
222 	dest = Map_chunk::find_spot(dest, 3, npc, 1);
223 	if (dest.tx == -1)
224 		return false;       // No spot found.
225 	Tile_coord src = npc->get_tile();
226 	if (dest.distance(src) > 7 && rand() % 2 != 0)
227 		return false;       // Got to give Avatar a chance to
228 	//   get away.
229 	// Create fire-field where he was.
230 	src.tz = npc->get_chunk()->get_highest_blocked(src.tz,
231 	         src.tx % c_tiles_per_chunk, src.ty % c_tiles_per_chunk);
232 	if (src.tz < 0)
233 		src.tz = 0;
234 	eman->add_effect(std::make_unique<Fire_field_effect>(src));
235 	int sfx = Audio::game_sfx(43);
236 	Audio::get_ptr()->play_sound_effect(sfx, npc);  // The weird noise.
237 	npc->move(dest.tx, dest.ty, dest.tz);
238 	// Show the stars.
239 	eman->add_effect(std::make_unique<Sprites_effect>(7, npc, 0, 0, 0, 0));
240 	return true;
241 }
242 
243 /*
244  *  Some monsters can do the "summon" spell.
245  */
246 
summon()247 bool Combat_schedule::summon(
248 ) {
249 	ucmachine->call_usecode(SummonSpellUsecode,
250 	                        npc, Usecode_machine::double_click);
251 	npc->start_std();       // Back into queue.
252 	return true;
253 }
254 
255 /*
256  *  Some can turn invisible.
257  */
258 
be_invisible()259 bool Combat_schedule::be_invisible(
260 ) {
261 	Object_sfx::Play(npc, Audio::game_sfx(44));
262 	gwin->get_effects()->add_effect(
263 	    std::make_unique<Sprites_effect>(12, npc, 0, 0, 0, 0, 0, -1));
264 	npc->set_flag(Obj_flags::invisible);
265 	npc->add_dirty();
266 	npc->start_std();       // Back into queue.
267 	return true;
268 }
269 
270 /*
271  *  Off-screen?
272  */
273 
Off_screen(Game_window * gwin,Game_object * npc)274 inline bool Off_screen(
275     Game_window *gwin,
276     Game_object *npc
277 ) {
278 	// See if off screen.
279 	Tile_coord t = npc->get_tile();
280 	TileRect screen = gwin->get_win_tile_rect().enlarge(2);
281 	return !screen.has_world_point(t.tx, t.ty);
282 }
283 
is_enemy(int align,int other)284 bool Combat_schedule::is_enemy(
285     int align, int other
286 ) {
287 	switch (align) {
288 	case Actor::good:
289 		return other == Actor::evil
290 		       || other == Actor::chaotic;
291 	case Actor::evil:
292 		return other == Actor::good
293 		       || other == Actor::chaotic;
294 	case Actor::neutral:
295 		return false;
296 	case Actor::chaotic:
297 		return other == Actor::evil
298 		       || other == Actor::good;
299 	}
300 	return true;    // This should never happen.
301 }
302 
303 /*
304  *  Find nearby opponents in the 9 surrounding chunks.
305  */
306 
find_opponents()307 void Combat_schedule::find_opponents(
308 ) {
309 	opponents.clear();
310 	Game_window *gwin = Game_window::get_instance();
311 	Actor_vector nearby;
312 	Actor_vector sleeping;            // Get all nearby NPC's.
313 	gwin->get_nearby_npcs(nearby);
314 	Actor *avatar = gwin->get_main_actor();
315 	nearby.push_back(avatar);   // Incl. Avatar!
316 	bool charmed_avatar = Combat::charmed_more_difficult &&
317 	                      avatar->get_effective_alignment() !=  Actor::good;
318 	// See if we're a party member.
319 	bool in_party = npc->is_in_party() || npc == avatar;
320 	int npc_align = npc->get_effective_alignment();
321 	bool see_invisible = npc->can_see_invisible();
322 	for (auto *actor : nearby) {
323 		if (actor->is_dead() || (!see_invisible && actor->get_flag(Obj_flags::invisible)))
324 			continue;   // Dead or invisible.
325 		if (is_enemy(npc_align, actor->get_effective_alignment())) {
326 			if (actor->get_flag(Obj_flags::asleep)) {
327 				// sleeping
328 				sleeping.push_back(actor);
329 				if (combat_trace)
330 					cout << npc->get_name() << " pushed back(asleep,1) " << actor->get_name() << endl;
331 			} else {
332 				opponents.push_back(actor->weak_from_this());
333 				if (combat_trace)
334 					cout << npc->get_name() << " pushed back(1) " << actor->get_name() << endl;
335 			}
336 		} else if (in_party) {  // Attacking party member?
337 			Game_object *t = actor->get_target();
338 			if (!t)
339 				continue;
340 			// Is actor attacking a party member?
341 			if ((t->get_flag(Obj_flags::in_party) || t == avatar) &&
342 			        t->as_actor() && is_enemy(npc_align, t->as_actor()->get_effective_alignment())) {
343 				opponents.push_back(actor->weak_from_this());
344 				if (combat_trace)
345 					cout << npc->get_name() << " pushed back(2) " << actor->get_name() << endl;
346 			}
347 			int oppressor = actor->get_oppressor();
348 			if (oppressor < 0)
349 				continue;
350 			Actor *oppr = gwin->get_npc(oppressor);
351 			assert(oppr != nullptr);
352 			// Is actor being attacked by a party member?
353 			if ((oppr->get_flag(Obj_flags::in_party) || oppr == avatar) &&
354 			        is_enemy(npc_align, oppr->get_effective_alignment())) {
355 				opponents.push_back(actor->weak_from_this());
356 				if (combat_trace)
357 					cout << npc->get_name() << " pushed back(3) " << actor->get_name() << endl;
358 			}
359 		}
360 	}
361 	// None found?  Use Avatar's if same effective alignment
362 	if (opponents.empty() && in_party &&
363 	        avatar->get_effective_alignment() == npc_align) {
364 		Game_object *opp = avatar->get_target();
365 		Actor *oppnpc = opp ? opp->as_actor() : nullptr;
366 		if (oppnpc && oppnpc != npc
367 		        && oppnpc->get_schedule_type() == Schedule::combat) {
368 			opponents.push_back(oppnpc->weak_from_this());
369 			if (combat_trace)
370 				cout << npc->get_name() << " pushed back (4) " << oppnpc->get_name() << endl;
371 		}
372 	}
373 	// Still none? Try the sleeping/unconscious foes.
374 	if (opponents.empty() && !sleeping.empty()
375 	    && (npc != avatar || charmed_avatar)) {
376 		for (auto *act : sleeping) {
377 		    opponents.push_front(weak_from_obj(act));
378 		}
379 		if (combat_trace)
380 			cout << npc->get_name() << " pushed back asleep opponents" << endl;
381 	}
382 }
383 
384 /*
385  *  Find 'protected' party member's attackers.
386  *
387  *  Output: ->attacker in opponents, or opponents.end() if not found.
388  */
389 
find_protected_attacker()390 list<Game_object_weak>::iterator Combat_schedule::find_protected_attacker(
391 ) {
392 	if (!npc->is_in_party())    // Not in party?
393 		return opponents.end();
394 	Game_window *gwin = Game_window::get_instance();
395 	Actor *party[9];        // Get entire party, including Avatar.
396 	int cnt = gwin->get_party(party, 1);
397 	Actor *prot_actor = nullptr;
398 	for (int i = 0; i < cnt; i++)
399 		if (party[i]->is_combat_protected()) {
400 			prot_actor = party[i];
401 			break;
402 		}
403 	if (!prot_actor)        // Not found?
404 		return opponents.end();
405 	// Find closest attacker.
406 	int best_dist = 4 * c_tiles_per_chunk;
407 	auto best_opp = opponents.end();
408 	for (auto it = opponents.begin();
409 	        it != opponents.end(); ++it) {
410 		Actor_shared opp = std::static_pointer_cast<Actor>((*it).lock());
411 		int dist;
412 		if (opp && opp->get_target() == prot_actor &&
413 		        (dist = npc->distance(opp.get())) < best_dist) {
414 			best_dist = dist;
415 			best_opp = it;
416 		}
417 	}
418 	if (best_opp == opponents.end())
419 		return opponents.end();
420 	if (failures < 5 && yelled && rand() % 2 && npc != prot_actor) {
421 		if (npc->is_goblin())
422 			npc->say(goblin_will_help);
423 		else if (can_yell)
424 			npc->say(first_will_help, last_will_help);
425 	}
426 	return best_opp;
427 }
428 
429 /*
430  *  Find a foe.
431  *
432  *  Output: Opponent that was found.
433  */
434 
find_foe(int mode)435 Game_object *Combat_schedule::find_foe(
436     int mode            // Mode to use.
437 ) {
438 	if (combat_trace) {
439 		cout << "'" << npc->get_name() << "' is looking for a foe" <<
440 		     endl;
441 	}
442 	int new_align = npc->get_effective_alignment();
443 	if (new_align != alignment) {
444 		// Alignment changed.
445 		opponents.clear();
446 		alignment = new_align;
447 	}
448 	Actor *avatar = gwin->get_main_actor();
449 	bool charmed_avatar = Combat::charmed_more_difficult &&
450 	                      avatar->get_effective_alignment() !=  Actor::good;
451 	// Remove any that died.
452 	opponents.erase(std::remove_if(opponents.begin(), opponents.end(),
453 		[this, avatar, charmed_avatar](const Game_object_weak& curr) {
454 			Actor_shared actor = std::static_pointer_cast<Actor>(curr.lock());
455 			return !actor || actor->is_dead() ||
456 			       (npc == avatar && !charmed_avatar &&
457 			        actor->get_flag(Obj_flags::asleep));
458 		}
459 		), opponents.end());
460 	if (opponents.empty()) { // No more from last scan?
461 		find_opponents();   // Find all nearby.
462 		if (practice_target)    // For dueling.
463 			return practice_target;
464 	}
465 	auto new_opp_link = opponents.end();
466 	switch (static_cast<Actor::Attack_mode>(mode)) {
467 	case Actor::weakest: {
468 		int str;
469 		int least_str = 100;
470 		for (auto it = opponents.begin();
471 		        it != opponents.end(); ++it) {
472 			Actor_shared opp = std::static_pointer_cast<Actor>((*it).lock());
473 			if (!opp)
474 			    continue;
475 			str = opp->get_property(Actor::strength);
476 			if (str < least_str) {
477 				least_str = str;
478 				new_opp_link = it;
479 			}
480 		}
481 		break;
482 	}
483 	case Actor::strongest: {
484 		int str;
485 		int best_str = -100;
486 		for (auto it = opponents.begin();
487 		        it != opponents.end(); ++it) {
488 			Actor_shared opp = std::static_pointer_cast<Actor>((*it).lock());
489 			if (!opp)
490 			    continue;
491 			str = opp->get_property(Actor::strength);
492 			if (str > best_str) {
493 				best_str = str;
494 				new_opp_link = it;
495 			}
496 		}
497 		break;
498 	}
499 	case Actor::nearest: {
500 		int best_dist = 4 * c_tiles_per_chunk;
501 		for (auto it = opponents.begin();
502 		        it != opponents.end(); ++it) {
503 			Actor_shared opp = std::static_pointer_cast<Actor>((*it).lock());
504 			if (!opp)
505 			    continue;
506 			int dist = npc->distance(opp.get());
507 			if (opp->get_attack_mode() == Actor::flee)
508 				dist += 16; // Avoid fleeing.
509 			if (dist < best_dist) {
510 				best_dist = dist;
511 				new_opp_link = it;
512 			}
513 		}
514 		break;
515 	}
516 	case Actor::protect:
517 		new_opp_link = find_protected_attacker();
518 		if (new_opp_link != opponents.end())
519 			break;      // Found one.
520 		// FALLTHROUGH
521 	case Actor::random:
522 	default:            // Default to random.
523 		if (!opponents.empty())
524 			new_opp_link = opponents.begin();
525 		break;
526 	}
527 	Actor_shared new_opponent;
528 	if (new_opp_link != opponents.end()) {
529 		new_opponent = std::static_pointer_cast<Actor>((*new_opp_link).lock());
530 		opponents.erase(new_opp_link);
531 	}
532 	return new_opponent ? new_opponent.get() : nullptr;
533 }
534 
535 /*
536  *  Find a foe.
537  *
538  *  Output: Opponent that was found.
539  */
540 
find_foe()541 inline Game_object *Combat_schedule::find_foe(
542 ) {
543 	if (npc->get_attack_mode() == Actor::manual)
544 		return nullptr;       // Find it yourself.
545 	return find_foe(static_cast<int>(npc->get_attack_mode()));
546 }
547 
548 /*
549  *  Back off if we're closer than our weapon's range.
550  */
551 
back_off(Actor * npc,Game_object * attacker)552 void Combat_schedule::back_off(
553 	Actor *npc,
554     Game_object *attacker
555 ) {
556 	int points;
557 	int weapon_shape;
558 	Game_object *weapon;
559 	const Weapon_info *winf = npc->get_weapon(points, weapon_shape, weapon);
560 	int weapon_dist = winf ? winf->get_range() : 3;
561 	int attacker_dist = npc->distance(attacker);
562 	Game_object *opponent = npc->get_target();
563 	if (opponent == attacker && weapon_dist <= attacker_dist)
564 	    return;	 			 			// Stay within our weapon's range.
565 	Tile_coord npc_tile = npc->get_tile();
566 	Tile_coord attacker_tile = attacker->get_tile();
567 	int dx = npc_tile.tx - attacker_tile.ty;
568 	int dy = npc_tile.ty - attacker_tile.ty;
569 	dx = dx < 0 ? -1 : dx > 0 ? 1 : 0;
570 	dy = dy < 0 ? -1 : dy > 0 ? 1 : 0;
571     Tile_coord spots[3];
572 	if (dx) {
573 	    if (dy) {
574 	        spots[0] = npc_tile + Tile_coord(dx, 0, 0);
575 		    spots[1] = npc_tile + Tile_coord(dx, dy, 0);
576 			spots[2] = npc_tile + Tile_coord(0, dy, 0);
577 		} else {
578 	        spots[0] = npc_tile + Tile_coord(dx, 0, 0);
579 		    spots[1] = npc_tile + Tile_coord(dx, -1, 0);
580 			spots[2] = npc_tile + Tile_coord(dx, 1, 0);
581 		}
582     } else {							// dx == 0;
583 	    spots[0] = npc_tile + Tile_coord(0, dy, 0);
584 		spots[1] = npc_tile + Tile_coord(-1, dy, 0);
585 		spots[2] = npc_tile + Tile_coord(1, dy, 0);
586     }
587 	int ind = rand()%3;
588 	if (npc->is_blocked(spots[ind])) {
589 	    ind = (ind + 1)%3;
590 		if (npc->is_blocked(spots[ind])) {
591 		    ind = (ind + 1)%3;
592 			if (npc->is_blocked(spots[ind]))
593 			   return;
594 		}
595     }
596 	npc->move(spots[ind]);
597     int dir = npc->get_facing_direction(attacker);
598 	npc->change_frame(npc->get_dir_framenum(dir, Actor::standing));
599 	cout << "***" << npc->get_name() << " is backing off" << endl;
600 }
601 
602 /*
603  *  Handle the 'approach' state.
604  */
605 
approach_foe(bool for_projectile)606 void Combat_schedule::approach_foe(
607     bool for_projectile     // Want to attack with projectile.
608     // FOR NOW:  Called as last resort,
609     //  and we try to reach target.
610 ) {
611 	int points;
612 	const Weapon_info *winf = npc->get_weapon(points, weapon_shape, weapon);
613 	int dist = for_projectile ? 1 : winf ? winf->get_range() : 3;
614 	Game_object *opponent = npc->get_target();
615 	// Find opponent.
616 	if (!opponent && !(opponent = find_foe())) {
617 		failures++;
618 		npc->start(200, 400);   // Try again in 2/5 sec.
619 		return;         // No one left to fight.
620 	}
621 	npc->set_target(opponent);
622 	Actor::Attack_mode mode = npc->get_attack_mode();
623 	Game_window *gwin = Game_window::get_instance();
624 	// Time to run?
625 	const Monster_info *minf = npc->get_info().get_monster_info();
626 	if ((!minf || !minf->cant_die()) &&
627 	        (mode == Actor::flee ||
628 	         (mode != Actor::berserk &&
629 	          (npc->get_type_flags()&MOVE_ALL) != 0 &&
630 	          npc != gwin->get_main_actor() &&
631 	          npc->get_property(Actor::health) < 3))) {
632 		run_away();
633 		return;
634 	}
635 	if (rand() % 4 == 0 && Can_teleport(npc) && // Try 1/4 to teleport.
636 	        teleport()) {
637 		start_battle();
638 		npc->start_std();
639 		return;
640 	}
641 	PathFinder *path = new Astar();
642 	// Try this for now:
643 	Monster_pathfinder_client cost(npc, dist, opponent);
644 	Tile_coord pos = npc->get_tile();
645 	if (!path->NewPath(pos, opponent->get_tile(), &cost)) {
646 		// Failed?  Try nearest opponent.
647 		failures++;
648 		bool retry_ok = false;
649 		if (npc->get_attack_mode() != Actor::manual) {
650 			Game_object *closest = find_foe(Actor::nearest);
651 			if (!closest) {
652 				// No one nearby.
653 				if (combat_trace)
654 					cout << npc->get_name() << " has no opponents nearby."
655 					     << endl;
656 				npc->set_target(nullptr);
657 				retry_ok = false;
658 			} else if (closest != opponent) {
659 				opponent = closest;
660 				npc->set_target(opponent);
661 				Monster_pathfinder_client cost(npc, dist,
662 				                               opponent);
663 				retry_ok = (opponent != nullptr && path->NewPath(
664 				                pos, opponent->get_tile(), &cost));
665 			}
666 		}
667 		if (!retry_ok) {
668 			delete path;    // Really failed.  Try again in
669 			//  after wandering.
670 			// Just try to walk towards opponent.
671 			Tile_coord pos = npc->get_tile();
672 			Tile_coord topos = opponent->get_tile();
673 			int dirx = topos.tx > pos.tx ? 2
674 			           : (topos.tx < pos.tx ? -2 : (rand() % 3 - 1));
675 			int diry = topos.ty > pos.ty ? 2
676 			           : (topos.ty < pos.ty ? -2 : (rand() % 3 - 1));
677 			pos.tx += dirx * (1 + rand() % 4);
678 			pos.ty += diry * (1 + rand() % 4);
679 			npc->walk_to_tile(pos, 2 * gwin->get_std_delay(),
680 			                  500 + rand() % 500);
681 			failures++;
682 			return;
683 		}
684 	}
685 	failures = 0;           // Clear count.  We succeeded.
686 	start_battle();         // Music if first time.
687 	if (combat_trace) {
688 		cout << npc->get_name() << " is pursuing " << opponent->get_name()
689 		     << endl;
690 	}
691 	// First time (or 256th), visible?
692 	if (!yelled && gwin->add_dirty(npc)) {
693 		yelled++;
694 		if (can_yell && rand() % 2) { // Half the time.
695 			if (npc->is_goblin())       // Goblin?
696 				npc->say(goblin_to_battle);
697 			else if (can_yell)
698 				npc->say(first_to_battle, last_to_battle);
699 		}
700 	}
701 	int extra_delay = 0;
702 	// Walk there, & check half-way.
703 	npc->set_action(new Approach_actor_action(path, opponent,
704 	                for_projectile));
705 	// Start walking.  Delay a bit if
706 	//   opponent is off-screen.
707 	npc->start(gwin->get_std_delay(), extra_delay +
708 	           (Off_screen(gwin, opponent) ?
709 	            5 * gwin->get_std_delay() : gwin->get_std_delay()));
710 }
711 
712 /*
713  *  Check for a useful weapon at a given ready-spot.
714  */
715 
Get_usable_weapon(Actor * npc,int index)716 static Game_object *Get_usable_weapon(
717     Actor *npc,
718     int index           // Ready-spot to check.
719 ) {
720 	Game_object *bobj = npc->get_readied(index);
721 	if (!bobj)
722 		return nullptr;
723 	const Shape_info &info = bobj->get_info();
724 	const Weapon_info *winf = info.get_weapon_info();
725 	if (!winf)
726 		return nullptr;       // Not a weapon.
727 	Game_object *aobj;  // Check ranged first.
728 	int need_ammo = npc->get_weapon_ammo(bobj->get_shapenum(),
729 	                                     winf->get_ammo_consumed(), winf->get_projectile(),
730 	                                     true, &aobj);
731 	if (need_ammo) {
732 		if (!aobj)  // Try melee.
733 			need_ammo = npc->get_weapon_ammo(bobj->get_shapenum(),
734 			                                 winf->get_ammo_consumed(), winf->get_projectile(),
735 			                                 false, &aobj);
736 		if (need_ammo && !aobj)
737 			return nullptr;
738 	}
739 	if (info.get_ready_type() == both_hands &&
740 	        npc->get_readied(rhand) != nullptr)
741 		return nullptr;       // Needs two free hands.
742 	return bobj;
743 }
744 
745 /*
746  *  Swap weapon with the one in the belt.
747  *
748  *  Output: 1 if successful.
749  */
750 
Swap_weapons(Actor * npc)751 static int Swap_weapons(
752     Actor *npc
753 ) {
754 	int index = belt;
755 	Game_object *bobj = Get_usable_weapon(npc, index);
756 	if (!bobj) {
757 		index = back_2h;
758 		bobj = Get_usable_weapon(npc, index);
759 		if (!bobj) {
760 			// Do thorough search for NPC's.
761 			if (!npc->is_in_party())
762 				return npc->ready_best_weapon();
763 			else
764 				return 0;
765 		}
766 	}
767 	Game_object *oldweap = npc->get_readied(lhand);
768 	if (oldweap)
769 		npc->remove(oldweap);
770 	npc->remove(bobj);
771 	npc->add(bobj, true);      // Should go into weapon hand.
772 	if (oldweap)            // Put old where new one was.
773 		npc->add_readied(oldweap, index, true, true);
774 	return 1;
775 }
776 
777 // Just move around a bit.
wander_for_attack()778 void Combat_schedule::wander_for_attack(
779 ) {
780 	Tile_coord pos = npc->get_tile();
781 	Game_object *opponent = npc->get_target();
782 	int dir = npc->get_direction(opponent);
783 
784 	dir += rand()%2 ? 2 : 6;			// A perpendicular direction.
785 	dir %= 8;
786 	int tries = 3;
787 	while (tries--) {
788 	    int cnt = 2 + rand()%3;
789 	    while (cnt--)
790 	        pos = pos.get_neighbor(dir);
791 	    // Find a free spot.
792 	    Tile_coord dest = Map_chunk::find_spot(pos, 3, npc, 1);
793 	    if (dest.tx != -1 && npc->walk_path_to_tile(dest,
794 								gwin->get_std_delay(), rand() % 1000))
795 		    return;				// Success.
796 	}
797 	// Failed?  Try again a little later.
798 	npc->start(250, rand() % 3000);
799 }
800 
801 /*
802  *  Begin a strike at the opponent.
803  */
804 
start_strike()805 void Combat_schedule::start_strike(
806 ) {
807 	Game_object *opponent = npc->get_target();
808 	bool check_lof = !no_blocking;
809 	// Get difference in lift.
810 	const Weapon_info *winf = weapon_shape >= 0 ?
811 	                    ShapeID::get_info(weapon_shape).get_weapon_info() : nullptr;
812 	int dist = npc->distance(opponent);
813 	int reach;
814 	if (!winf) {
815 		const Monster_info *minf = npc->get_info().get_monster_info();
816 		reach = minf ? minf->get_reach() : Monster_info::get_default()->get_reach();
817 	} else
818 		reach = winf->get_range();
819 	bool ranged = not_in_melee_range(winf, dist, reach);
820 	// Out of range?
821 	if (!spellbook && npc->get_effective_range(winf, reach) < dist) {
822 		state = approach;
823 		approach_foe();     // Get a path.
824 		return;
825 	} else if (spellbook || ranged) {
826 		bool weapon_dead = false;
827 		if (spellbook)
828 			weapon_dead = !spellbook->can_do_spell(npc);
829 		else if (winf) {
830 			// See if we can fire spell/projectile.
831 			Game_object *ammo = nullptr;
832 			int need_ammo = npc->get_weapon_ammo(weapon_shape,
833 			                                     winf->get_ammo_consumed(), winf->get_projectile(),
834 			                                     ranged, &ammo);
835 			if (need_ammo && !ammo && !npc->ready_ammo())
836 				weapon_dead = true;
837 		}
838 		if (weapon_dead) {
839 			// Out of ammo/reagents/charges.
840 			if (npc->get_schedule_type() != Schedule::duel) {
841 				// Look in pack for ammo.
842 				if (Swap_weapons(npc))
843 					Combat_schedule::set_weapon();
844 				else
845 					set_hand_to_hand();
846 			}
847 			if (!npc->get_info().has_strange_movement())
848 				npc->change_frame(npc->get_dir_framenum(
849 				                      Actor::standing));
850 			state = approach;
851 			npc->set_target(nullptr);
852 			npc->start(200, 500);
853 			return;
854 		}
855 		state = fire;       // Clear to go.
856 	} else {
857 		check_lof = (reach > 1);
858 		state = strike;
859 	}
860 	// At this point, we're within range, with state set.
861 	if (check_lof &&
862 	        !Fast_pathfinder_client::is_straight_path(npc, opponent)) {
863 		state = approach;
864 		wander_for_attack();
865 		return;
866 	}
867 	if (!started_battle)
868 		start_battle(); // Play music if first time.
869 	// Some battle cries. Guessing at where to do it, and how often.
870 	if (yelled && !(rand() % 20)) {
871 		if (npc->is_goblin())
872 			npc->say(first_goblin_taunt, last_goblin_taunt);
873 		else if (can_yell)
874 			npc->say(first_taunt, last_taunt);
875 	}
876 	if (combat_trace) {
877 		cout << npc->get_name() << " attacks " << opponent->get_name() << endl;
878 	}
879 	int dir = npc->get_direction(opponent);
880 	signed char frames[12];     // Get frames to show.
881 	int cnt = npc->get_attack_frames(weapon_shape, ranged, dir, frames);
882 	if (cnt)
883 		npc->set_action(new Frames_actor_action(frames, cnt, gwin->get_std_delay()));
884 	npc->start();           // Get back into time queue.
885 	int sfx = -1;           // Play sfx.
886 	if (winf)
887 		sfx = winf->get_sfx();
888 	if (sfx < 0 || !winf) {
889 		const Monster_info *minf = ShapeID::get_info(
890 		                         npc->get_shapenum()).get_monster_info();
891 		if (minf)
892 			sfx = minf->get_hitsfx();
893 	}
894 	if (sfx >= 0) {
895 		int delay = ranged ? cnt : cnt / 2;
896 		Object_sfx::Play(npc, sfx, delay * gwin->get_std_delay());
897 	}
898 	dex_points -= dex_to_attack;
899 }
900 
901 /*
902  *  This static method causes the NPC to attack a given target/tile
903  *  using the given weapon shape as weapon. This does not add
904  *  an attack animation; rather, it is the actual strike attempt.
905  *
906  *  This function is called from (a) an intrinsic, (b) a script opcode
907  *  or (c) the combat schedule.
908  *
909  *  Output: Returns false the attack cannot be realized (no ammo,
910  *  out of range, etc.) or if a melee attack misses, true otherwise.
911  */
912 
attack_target(Game_object * attacker,Game_object * target,Tile_coord const & tile,int weapon,bool combat)913 bool Combat_schedule::attack_target(
914     Game_object *attacker,      // Who/what is attacking.
915     Game_object *target,        // Who/what is being attacked.
916     Tile_coord const &tile,     // What tile is under fire, if no target.
917     int weapon,                 // What is being used as weapon.
918     // or < 0 for none.
919     bool combat                 // We got here from combat schedule.
920 ) {
921 	// Bail out if no attacker or if no target and no valid tile.
922 	if (!attacker || (!target && tile.tx == -1))
923 		return false;
924 
925 	// Do not proceed if target is dead.
926 	Actor *att = attacker->as_actor();
927 	if (att && att->is_dead())
928 		return false;
929 	bool flash_mouse = !combat && att && gwin->get_main_actor() == att
930 	                   && att->get_attack_mode() != Actor::manual;
931 
932 	const Shape_info &info = ShapeID::get_info(weapon);
933 	const Weapon_info *winf = weapon >= 0 ? info.get_weapon_info() : nullptr;
934 
935 	int reach;
936 	int family = -1;    // Ammo, is needed, is the weapon itself.
937 	int proj = -1;  // This is what we will use as projectile sprite.
938 	if (!winf) {
939 		const Monster_info *minf = attacker->get_info().get_monster_info();
940 		reach = minf ? minf->get_reach() : Monster_info::get_default()->get_reach();
941 	} else {
942 		reach = winf->get_range();
943 		proj = winf->get_projectile();
944 		family = winf->get_ammo_consumed();
945 	}
946 	int dist = target ? attacker->distance(target) : attacker->distance(tile);
947 	bool ranged = not_in_melee_range(winf, dist, reach);
948 	// Out of range?
949 	if (attacker->get_effective_range(winf, reach) < dist) {
950 		// We are out of range.
951 		if (flash_mouse)
952 			Mouse::mouse->flash_shape(Mouse::outofrange);
953 		return false;
954 	}
955 
956 	// See if we need ammo.
957 	Game_object *ammo = nullptr;
958 	int need_ammo = attacker->get_weapon_ammo(weapon, family,
959 	                proj, ranged, &ammo);
960 	Game_object_shared ammo_keep = shared_from_obj(ammo);
961 	if (need_ammo && !ammo) {
962 		if (flash_mouse)
963 			Mouse::mouse->flash_shape(Mouse::outofammo);
964 		// We don't have ammo, so bail out.
965 		return false;
966 	}
967 
968 	// proj == -3 means use weapon shape for projectile sprite.
969 	if (proj == -3)
970 		proj = weapon;
971 	const Ammo_info *ainf;
972 	int basesprite;
973 	if (need_ammo && family >= 0) {
974 		// ammo should be nonzero here.
975 		ainf = ammo->get_info().get_ammo_info();
976 		basesprite = ammo->get_shapenum();
977 	} else {
978 		ainf = info.get_ammo_info();
979 		basesprite = weapon;
980 	}
981 	if (ainf) {
982 		int sprite = ainf->get_sprite_shape();
983 		if (sprite == -3)
984 			proj = basesprite;
985 		else if (sprite != -1 && sprite != ainf->get_family_shape())
986 			proj = sprite;
987 	} else
988 		ainf = Ammo_info::get_default();    // So we don't need to keep checking.
989 
990 	// By now, proj should be >=0 or -1 for none.
991 	assert(proj >= -1);
992 	if (!winf)  // So we don't have to keep checking.
993 		winf = Weapon_info::get_default();
994 	if (need_ammo) {
995 		// We should only ever get here for containers and NPCs.
996 		// Also, ammo should never be zero in this branch.
997 		bool need_new_weapon = false;
998 		bool ready = att ? att->find_readied(ammo) >= 0 : false;
999 
1000 		// Time to use up ammo.
1001 		if (winf->uses_charges()) {
1002 			if (ammo->get_info().has_quality())
1003 				ammo->set_quality(ammo->get_quality() - need_ammo);
1004 			if (winf->delete_depleted() &&
1005 			        (!ammo->get_quality() || !ammo->get_info().has_quality())) {
1006 				// Call unready usecode if needed.
1007 				if (att)
1008 					att->remove(ammo);
1009 				ammo->remove_this();
1010 				need_new_weapon = true;
1011 			}
1012 		} else {
1013 			int quant = ammo->get_quantity();
1014 			// Call unready usecode if needed.
1015 			if (att && quant == need_ammo)
1016 				att->remove(ammo);
1017 			ammo->modify_quantity(-need_ammo, &need_new_weapon);
1018 		}
1019 
1020 		if (att && need_new_weapon && ready) {
1021 			// Readied weapon was depleted; we need a new one.
1022 			if (winf->returns() || ainf->returns()) {
1023 				// Weapon will return, so wait for it.
1024 				if (combat) {
1025 					// We got here due to combat schedule.
1026 					auto *sched =
1027 					    dynamic_cast<Combat_schedule *>(att->get_schedule());
1028 					if (sched)  // May not need this check.
1029 						sched->set_state(wait_return);
1030 				}
1031 			}
1032 			// Try readying ammo first.
1033 			else if (att && !att->ready_ammo()) {
1034 				// Need new weapon.
1035 				att->ready_best_weapon();
1036 				// Tell schedule about it.
1037 				att->get_schedule()->set_weapon(true);
1038 			}
1039 		}
1040 	}
1041 
1042 	Actor *trg = target ? target->as_actor() : nullptr;
1043 	bool trg_party = trg ? trg->is_in_party() : false;
1044 	bool att_party = att ? att->is_in_party() : false;
1045 	int attval = att ? att->get_effective_prop(static_cast<int>(Actor::combat)) : 0;
1046 	// These two give the correct statistics:
1047 	attval += (winf->lucky() ? 3 : 0);
1048 	attval += (ainf->lucky() ? 3 : 0);
1049 	int bias = trg_party ? Combat::difficulty :
1050 	           (att_party ? -Combat::difficulty : 0);
1051 	attval += 2 * bias; // Apply all bias to the attack value.
1052 	if (ranged) {
1053 		int uses = winf->get_uses();
1054 		attval += 6;
1055 		// This seems reasonably close to how the originals do it,
1056 		// although the error bands of the statistics are too wide here.
1057 		if (uses == Weapon_info::poor_thrown)
1058 			attval -= dist;
1059 		else if (uses == Weapon_info::good_thrown)
1060 			attval -= dist / 2;
1061 		// We need to pass the attack value here to guard against
1062 		// the possibility of the attacker's combat be lowered
1063 		// (e.g., due to being paralyzed) while the projectile is
1064 		// in flight and before it hits.
1065 		std::unique_ptr<Projectile_effect> projectile;
1066 		if (target)
1067 			projectile = std::make_unique<Projectile_effect>(attacker, target, weapon,
1068 			                                   ammo ? ammo->get_shapenum() : proj, proj, attval);
1069 		else
1070 			projectile = std::make_unique<Projectile_effect>(attacker, tile, weapon,
1071 			                                   ammo ? ammo->get_shapenum() : proj, proj, attval);
1072 		gwin->get_effects()->add_effect(std::move(projectile));
1073 		return true;
1074 	} else if (target) {
1075 		// Do nothing when attacking tiles in melee.
1076 		bool autohit = winf->autohits() || ainf->autohits();
1077 		// godmode effects:
1078 		if (cheat.in_god_mode())
1079 			autohit = trg_party ? false : (att_party ? true : autohit);
1080 		if (!autohit && !target->try_to_hit(attacker, attval))
1081 			return false;   // Missed.
1082 		target->play_hit_sfx(weapon, false);
1083 		//if (weapon == 704)    // Powder keg.
1084 		if (info.is_explosive()) {  // Powder keg.
1085 			// Blow up *instead*.
1086 			Tile_coord offset(0, 0, target->get_info().get_3d_height() / 2);
1087 			eman->add_effect(std::make_unique<Explosion_effect>(target->get_tile() + offset,
1088 			                                      target, 0, weapon, -1, attacker));
1089 		} else {
1090 		    Game_object_weak trg_check = weak_from_obj(trg);
1091 			target->attacked(attacker, weapon,
1092 			                 ammo ? ammo->get_shapenum() : -1, false);
1093             if (trg && !trg_check.expired())
1094 			    back_off(trg, attacker);
1095 		}
1096 		return true;
1097 	}
1098 	return false;
1099 }
1100 
1101 /*
1102  *  Run away.
1103  */
1104 
run_away()1105 void Combat_schedule::run_away(
1106 ) {
1107 	Game_window *gwin = Game_window::get_instance();
1108 	fleed++;
1109 	// Might be nice to run from opp...
1110 	int rx = rand();        // Get random position away from here.
1111 	int ry = rand();
1112 	int dirx = 2 * (rx % 2) - 1; // Get 1 or -1.
1113 	int diry = 2 * (ry % 2) - 1;
1114 	Tile_coord pos = npc->get_tile();
1115 	pos.tx += dirx * (8 + rx % 8);
1116 	pos.ty += diry * (8 + ry % 8);
1117 	npc->walk_to_tile(pos, gwin->get_std_delay(), 0);
1118 	if (fleed == 1 && !npc->get_flag(Obj_flags::tournament) &&
1119 	        rand() % 3 && gwin->add_dirty(npc)) {
1120 		yelled++;
1121 		if (npc->is_goblin()) {
1122 			if (rand() % 4)
1123 				npc->say(goblin_flee_screaming);
1124 			else
1125 				npc->say(first_goblin_flee, last_goblin_flee);
1126 		} else if (can_yell) {
1127 			if (rand() % 4)
1128 				npc->say(flee_screaming);
1129 			else
1130 				npc->say(first_flee, last_flee);
1131 		}
1132 	}
1133 }
1134 
1135 /*
1136  *  See if a spellbook is readied with a spell
1137  *  available.
1138  *
1139  *  Output: ->spellbook if so, else nullptr.
1140  */
1141 
readied_spellbook()1142 Spellbook_object *Combat_schedule::readied_spellbook(
1143 ) {
1144 	Spellbook_object *book = nullptr;
1145 	// Check both hands.
1146 	Game_object *obj = npc->get_readied(lhand);
1147 	if (obj && obj->get_info().get_shape_class() == Shape_info::spellbook) {
1148 		book = static_cast<Spellbook_object *>(obj);
1149 		if (book->can_do_spell(npc))
1150 			return book;
1151 	}
1152 	obj = npc->get_readied(rhand);
1153 	if (obj && obj->get_info().get_shape_class() == Shape_info::spellbook) {
1154 		book = static_cast<Spellbook_object *>(obj);
1155 		if (book->can_do_spell(npc))
1156 			return book;
1157 	}
1158 	return nullptr;
1159 }
1160 
1161 /*
1162  *  Set weapon 'max_range' and 'ammo'.  Ready a new weapon if needed.
1163  */
1164 
set_weapon(bool removed)1165 void Combat_schedule::set_weapon(
1166     bool removed            // The weapon was just removed.
1167 ) {
1168 	int points;
1169 	spellbook = nullptr;
1170 	const Weapon_info *info = npc->get_weapon(points, weapon_shape, weapon);
1171 	if (!removed &&
1172 	        // Not dragging?
1173 	        !gwin->is_dragging() &&
1174 	        // And not dueling?
1175 	        npc->get_schedule_type() != Schedule::duel &&
1176 	        state != wait_return) { // And not waiting for boomerang.
1177 		if (!info &&    // No weapon?
1178 		        !(spellbook = readied_spellbook())) { // No spellbook?
1179 			npc->ready_best_weapon();
1180 			info = npc->get_weapon(points, weapon_shape, weapon);
1181 		} else
1182 			npc->ready_best_shield();
1183 	}
1184 	if (!info) {        // Still nothing.
1185 		if (spellbook)      // Did we find a spellbook?
1186 			no_blocking = true;
1187 		else    // Don't do this if using spellbook.
1188 			set_hand_to_hand();
1189 	} else {
1190 		no_blocking = false;
1191 	}
1192 	if (state == strike || state == fire)
1193 		state = approach;   // Got to restart attack.
1194 }
1195 
1196 
1197 /*
1198  *  Set for hand-to-hand combat (no weapon).
1199  */
1200 
set_hand_to_hand()1201 void Combat_schedule::set_hand_to_hand(
1202 ) {
1203 	weapon = nullptr;
1204 	weapon_shape = -1;
1205 	no_blocking = false;
1206 	// Put aside weapon.
1207 	Game_object *weapon = npc->get_readied(lhand);
1208 	if (weapon) {
1209 	    Game_object_shared keep = weapon->shared_from_this();
1210 	    npc->remove(weapon);
1211 		if (!npc->add_readied(weapon, belt, true) &&
1212 		        !npc->add_readied(weapon, back_2h, true) &&
1213 		        !npc->add_readied(weapon, back_shield, true) &&
1214 		        !npc->add_readied(weapon, rhand, true) &&
1215 		        !npc->add_readied(weapon, backpack, true))
1216 			npc->add(weapon, false, false, true);
1217 	}
1218 }
1219 
1220 /*
1221  *  See if we need a new opponent.
1222  */
1223 
Need_new_opponent(Game_window * gwin,Actor * npc)1224 inline int Need_new_opponent(
1225     Game_window *gwin,
1226     Actor *npc
1227 ) {
1228 	Game_object *opponent = npc->get_target();
1229 	Actor *act;
1230 	bool see_invisible = npc->can_see_invisible();
1231 	// Nonexistent or dead?
1232 	if (!opponent ||
1233 	        ((act = opponent->as_actor()) != nullptr && act->is_dead()) ||
1234 	        // Or invisible?
1235 	        (!see_invisible && opponent->get_flag(Obj_flags::invisible)
1236 	         && rand() % 4 == 0))
1237 		return 1;
1238 	// See if off screen.
1239 	return Off_screen(gwin, opponent) && !Off_screen(gwin, npc);
1240 }
1241 
1242 /*
1243  *  Create.
1244  */
1245 
Combat_schedule(Actor * n,Schedule_types prev_sched)1246 Combat_schedule::Combat_schedule(
1247     Actor *n,
1248     Schedule_types
1249     prev_sched
1250 ) : Schedule(n), state(initial), prev_schedule(prev_sched),
1251 	practice_target(nullptr), weapon(nullptr), weapon_shape(-1), spellbook(nullptr),
1252 	no_blocking(false), yelled(0), started_battle(false), fleed(0),
1253 	failures(0), teleport_time(0), summon_time(0),
1254 	dex_points(0), alignment(n->get_effective_alignment()) {
1255 	Combat_schedule::set_weapon();
1256 	// Cache some data.
1257 	can_yell = npc->can_speak();
1258 	unsigned int curtime = SDL_GetTicks();
1259 	summon_time = curtime + 4000;
1260 	invisible_time = curtime + 4500;
1261 }
1262 
1263 
1264 /*
1265  *  Previous action is finished.
1266  */
1267 
now_what()1268 void Combat_schedule::now_what(
1269 ) {
1270 	Game_window *gwin = Game_window::get_instance();
1271 	if (state == initial) {     // Do NOTHING in initial state so
1272 		//   usecode can, e.g., set opponent.
1273 		// Way far away (50 tiles)?
1274 		if (npc->distance(gwin->get_camera_actor()) > 50) {
1275 			npc->set_dormant();
1276 			return;     // Just go dormant.
1277 		}
1278 		state = approach;
1279 		npc->start(200, 200);
1280 		return;
1281 	}
1282 	if (npc->get_flag(Obj_flags::asleep)) {
1283 		npc->start(200, 1000);  // Check again in a second.
1284 		return;
1285 	}
1286 	// Running away?
1287 	if (npc->get_attack_mode() == Actor::flee) {
1288 		// If not in combat, stop running.
1289 		const Monster_info *minf = npc->get_info().get_monster_info();
1290 		if (minf && minf->cant_die())
1291 			npc->set_attack_mode(Actor::nearest);
1292 		else if (fleed > 2 && !gwin->in_combat() &&
1293 		         npc->get_party_id() >= 0)
1294 			// WARNING:  Destroys ourself.
1295 			npc->set_schedule_type(Schedule::follow_avatar);
1296 		else
1297 			run_away();
1298 		return;
1299 	}
1300 	// Check if opponent still breathes.
1301 	if (Need_new_opponent(gwin, npc)) {
1302 		npc->set_target(nullptr);
1303 		state = approach;
1304 	}
1305 	Game_object *opponent = npc->get_target();
1306 	switch (state) {        // Note:  state's action has finished.
1307 	case approach:
1308 		if (!opponent)
1309 			approach_foe();
1310 		else if (dex_points >= dex_to_attack) {
1311 			int effint = npc->get_effective_prop(
1312 			                 Actor::intelligence);
1313 			if (!npc->get_flag(Obj_flags::invisible) &&
1314 			        Can_be_invisible(npc) && rand() % 300 < effint) {
1315 				(void) be_invisible();
1316 				dex_points -= dex_to_attack;
1317 			} else if (Can_summon(npc) && rand() % 600 < effint &&
1318 			           summon())
1319 				dex_points -= dex_to_attack;
1320 			else
1321 				start_strike();
1322 		} else {
1323 			dex_points += npc->get_property(Actor::dexterity);
1324 			npc->start_std();
1325 		}
1326 		break;
1327 	case strike: {          // He hasn't moved away?
1328 		state = approach;
1329 		// Back into queue.
1330 		npc->start_std();
1331 		Actor_shared safenpc = std::static_pointer_cast<Actor>(
1332 											npc->shared_from_this());
1333 		// Change back to ready frame.
1334 		int delay = gwin->get_std_delay();
1335 		// Neither slime nor BG sea serpent?
1336 		if (!npc->get_info().has_strange_movement()) {
1337 			auto frame =
1338 			    static_cast<signed char>(npc->get_dir_framenum(Actor::ready_frame));
1339 			npc->set_action(new Frames_actor_action(&frame, 1, delay));
1340 		} else if (!npc->is_slime()) { // Sea serpent?
1341 			signed char frames[] = {
1342 				static_cast<signed char>(npc->get_dir_framenum(3)),
1343 				static_cast<signed char>(npc->get_dir_framenum(2)),
1344 				static_cast<signed char>(npc->get_dir_framenum(1))
1345 			};
1346 			npc->set_action(new Frames_actor_action(frames, sizeof(frames), delay));
1347 		}
1348 		npc->start(delay, delay);
1349 		if (attack_target(npc, opponent, Tile_coord(-1, -1, 0), weapon_shape, true)) {
1350 			// Strike but once at objects.
1351 			Game_object *newtarg = safenpc->get_target();
1352 			if (newtarg && !newtarg->as_actor())
1353 				safenpc->set_target(nullptr);
1354 			return;     // We may no longer exist!
1355 		}
1356 		break;
1357 	}
1358 	case fire: {        // Range weapon.
1359 		failures = 0;
1360 		state = approach;
1361 		if (spellbook) {
1362 			// Cast the spell.
1363 			if (!spellbook->do_spell(npc, true))
1364 				Combat_schedule::set_weapon();
1365 		} else
1366 			attack_target(npc, opponent, Tile_coord(-1, -1, 0), weapon_shape, true);
1367 
1368 		int delay = 1;
1369 		if (spellbook) {
1370 			Usecode_script *scr = Usecode_script::find(npc);
1371 			// Warning: assuming that the most recent script for the
1372 			// actor is the spellcasting script.
1373 			delay += (scr ? scr->get_length() : 0) + 2;
1374 		}
1375 		delay *= gwin->get_std_delay();
1376 		// Change back to ready frame.
1377 		// Neither slime nor BG sea serpent?
1378 		if (!npc->get_info().has_strange_movement()) {
1379 			auto frame =
1380 			    static_cast<signed char>(npc->get_dir_framenum(Actor::ready_frame));
1381 			npc->set_action(new Frames_actor_action(&frame, 1, delay));
1382 		} else if (!npc->is_slime()) { // Sea serpent?
1383 			signed char frames[] = {
1384 				static_cast<signed char>(npc->get_dir_framenum(3)),
1385 				static_cast<signed char>(npc->get_dir_framenum(2)),
1386 				static_cast<signed char>(npc->get_dir_framenum(1))
1387 			};
1388 			npc->set_action(new Frames_actor_action(frames, sizeof(frames), delay));
1389 		}
1390 		npc->start(gwin->get_std_delay(), delay);
1391 
1392 		// Strike but once at objects.
1393 		Game_object *newtarg = npc->get_target();
1394 		if (newtarg && !newtarg->as_actor()) {
1395 			npc->set_target(nullptr);
1396 			return;     // We may no longer exist!
1397 		}
1398 		break;
1399 	}
1400 	case wait_return:       // Boomerang should have returned.
1401 		state = approach;
1402 		dex_points += npc->get_property(Actor::dexterity);
1403 		npc->start_std();
1404 		break;
1405 	default:
1406 		break;
1407 	}
1408 	if (failures > 5 && npc != gwin->get_camera_actor()) {
1409 		// Too many failures.  Give up for now.
1410 		if (combat_trace) {
1411 			cout << npc->get_name() << " is giving up" << endl;
1412 		}
1413 		if (npc->get_party_id() >= 0) {
1414 			// Party member.
1415 			npc->walk_to_tile(
1416 			    gwin->get_main_actor()->get_tile(),
1417 			    gwin->get_std_delay());
1418 			// WARNING:  Destroys ourself.
1419 			npc->set_schedule_type(Schedule::follow_avatar);
1420 		} else if (!gwin->get_game_rect().intersects(
1421 		               gwin->get_shape_rect(npc))) {
1422 			// Off screen?  Stop trying.
1423 			gwin->get_tqueue()->remove(npc);
1424 			npc->set_dormant();
1425 		} else if (npc->get_alignment() == Actor::good &&
1426 		           prev_schedule != Schedule::combat) {
1427 			// Return to normal schedule.
1428 			npc->update_schedule(gclock->get_hour() / 3);
1429 			if (npc->get_schedule_type() == Schedule::combat)
1430 				npc->set_schedule_type(prev_schedule);
1431 		} else {
1432 			// Wander randomly.
1433 			Tile_coord t = npc->get_tile();
1434 			int dist = 2 + rand() % 3;
1435 			int newx = t.tx - dist + rand() % (2 * dist);
1436 			int newy = t.ty - dist + rand() % (2 * dist);
1437 			// Wait a bit.
1438 			npc->walk_to_tile(newx, newy, t.tz,
1439 			                  2 * gwin->get_std_delay(), rand() % 1000);
1440 		}
1441 	}
1442 }
1443 
1444 /*
1445  *  Npc just went dormant (probably off-screen).
1446  */
1447 
im_dormant()1448 void Combat_schedule::im_dormant(
1449 ) {
1450 	if (npc->get_effective_alignment() == Actor::good &&
1451 	        prev_schedule != npc->get_schedule_type() && npc->is_monster())
1452 		// Good, so end combat.
1453 		npc->set_schedule_type(prev_schedule);
1454 }
1455 
1456 /*
1457  *  Leaving combat.
1458  */
1459 
ending(int)1460 void Combat_schedule::ending(
1461     int /* newtype */
1462 ) {
1463 	Game_window *gwin = Game_window::get_instance();
1464 	if (gwin->get_main_actor() == npc &&
1465 	        // Not if called from usecode.
1466 	        !gwin->get_usecode()->in_usecode()) {
1467 		// See if being a coward.
1468 		find_opponents();
1469 		bool found = false; // Find a close-by enemy.
1470 		for (auto& opponent : opponents) {
1471 			Actor_shared opp = std::static_pointer_cast<Actor>(opponent.lock());
1472 			if (opp && opp->distance(npc) < (c_screen_tile_size / 2 - 2) &&
1473 			        Fast_pathfinder_client::is_grabable(npc, opp.get())) {
1474 				found = true;
1475 				break;
1476 			}
1477 		}
1478 		if (found)
1479 			Audio::get_ptr()->start_music_combat(CSRun_Away,
1480 			                                     false);
1481 	}
1482 }
1483 
1484 
1485 /*
1486  *  Create duel schedule.
1487  */
1488 
Duel_schedule(Actor * n)1489 Duel_schedule::Duel_schedule(
1490     Actor *n
1491 ) : Combat_schedule(n, duel), start(n->get_tile()),
1492 	attacks(0) {
1493 	started_battle = true;      // Avoid playing music.
1494 }
1495 
1496 /*
1497  *  Ready a bow-and-arrows.
1498  */
1499 
Ready_duel_weapon(Actor * npc,int wshape,int ashape)1500 void Ready_duel_weapon(
1501     Actor *npc,
1502     int wshape,         // Weapon shape.
1503     int ashape          // Ammo shape, or -1.
1504 ) {
1505 	Game_map *gmap = Game_window::get_instance()->get_map();
1506 	Game_object *weap = npc->get_readied(lhand);
1507 	if (!weap || weap->get_shapenum() != wshape) {
1508 		// Need a bow.
1509 		Game_object_shared newweap;
1510 		Game_object_shared keep;
1511 		Game_object_shared newkeep;
1512 		Game_object *found =
1513 		    npc->find_item(wshape, c_any_qual, c_any_framenum);
1514 		if (found) {        // Have it?
1515 		    newweap = found->shared_from_this();
1516 			newweap->remove_this(&newkeep);
1517 		} else            // Create new one.
1518 			newweap = gmap->create_ireg_object(wshape, 0);
1519 		if (weap)       // Remove old item.
1520 			weap->remove_this(&keep);
1521 		npc->add(newweap.get(), true);   // Should go in correct spot.
1522 		if (weap)
1523 			npc->add(weap, true);
1524 	}
1525 	if (ashape == -1)       // No ammo needed.
1526 		return;
1527 	// Now provide 1-3 arrows.
1528 	Game_object *aobj = npc->get_readied(quiver);
1529 	if (aobj)
1530 		aobj->remove_this();    // Toss current ammo.
1531 	Game_object_shared arrows = gmap->create_ireg_object(ashape, 0);
1532 	int extra = rand() % 3;     // Add 1 or 2.
1533 	if (extra)
1534 		arrows->modify_quantity(extra);
1535 	npc->add(arrows.get(), true);        // Should go to right spot.
1536 }
1537 
1538 /*
1539  *  Find dueling opponents.
1540  */
1541 
find_opponents()1542 void Duel_schedule::find_opponents(
1543 ) {
1544 	opponents.clear();
1545 	attacks = 0;
1546 	practice_target = nullptr;
1547 	int r = rand() % 3;
1548 	if (r == 0) {       // First look for practice targets.
1549 		// Archery target:
1550 		practice_target = npc->find_closest(735);
1551 		if (practice_target)    // Need bow-and-arrows.
1552 			Ready_duel_weapon(npc, 597, 722);
1553 	}
1554 	if (!practice_target) {     // Fencing dummy or dueling opponent.
1555 		Ready_duel_weapon(npc, 602, -1);
1556 		if (r == 1)
1557 			practice_target = npc->find_closest(860);
1558 	}
1559 	Combat_schedule::set_weapon();
1560 	if (practice_target) {
1561 		npc->set_target(practice_target);
1562 		return;         // Just use that.
1563 	}
1564 	Actor_vector vec;       // Find all nearby NPC's.
1565 	npc->find_nearby_actors(vec, c_any_shapenum, 24);
1566 	for (auto *opp : vec) {
1567 		Game_object *oppopp = opp->get_target();
1568 		if (opp != npc && opp->get_schedule_type() == duel &&
1569 		        (!oppopp || oppopp == npc))
1570 			opponents.push_back(opp->weak_from_this());
1571 	}
1572 }
1573 
1574 /*
1575  *  Previous action is finished.
1576  */
1577 
now_what()1578 void Duel_schedule::now_what(
1579 ) {
1580 	if (state == strike || state == fire) {
1581 		attacks++;
1582 		// Practice target full?
1583 		if (practice_target && practice_target->get_shapenum() == 735
1584 		        && practice_target->get_framenum() > 0 &&
1585 		        practice_target->get_framenum() % 3 == 0) {
1586 			attacks = 0;    // Break off.
1587 			//++++++Should walk there.
1588 			practice_target->change_frame(0);
1589 		}
1590 	} else {
1591 		Combat_schedule::now_what();
1592 		return;
1593 	}
1594 	if (attacks % 8 == 0) { // Time to break off.
1595 		npc->set_target(nullptr);
1596 		Tile_coord pos = start;
1597 		pos.tx += rand() % 24 - 12;
1598 		pos.ty += rand() % 24 - 12;
1599 		// Find a free spot.
1600 		Tile_coord dest = Map_chunk::find_spot(pos, 3, npc, 1);
1601 		if (dest.tx == -1 || !npc->walk_path_to_tile(dest,
1602 		        gwin->get_std_delay(), rand() % 2000))
1603 			// Failed?  Try again a little later.
1604 			npc->start(250, rand() % 3000);
1605 	} else
1606 		Combat_schedule::now_what();
1607 }
1608 
1609 /*
1610  *  Pause/unpause while in combat.
1611  */
1612 
toggle_pause()1613 void Combat::toggle_pause(
1614 ) {
1615 	if (!paused && mode == original)
1616 		return;         // Not doing that sort of thing.
1617 	if (paused) {
1618 		resume();       // Text is probably for debugging.
1619 		eman->center_text("Combat resumed");
1620 	} else {
1621 		gwin->get_tqueue()->pause(SDL_GetTicks());
1622 		eman->center_text("Combat paused");
1623 		paused = true;
1624 	}
1625 }
1626 
1627 /*
1628  *  Resume.
1629  */
1630 
resume()1631 void Combat::resume(
1632 ) {
1633 	if (!paused)
1634 		return;
1635 	gwin->get_tqueue()->resume(SDL_GetTicks());
1636 	paused = false;
1637 }
1638