1 /*
2 * actors.cc - Game actors.
3 *
4 * Copyright (C) 1998-1999 Jeffrey S. Freedman
5 * Copyright (C) 2000-2013 The Exult Team
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <memory>
27
28 #include <iostream> /* Debugging. */
29 #include <cstdlib>
30 #include <cstring>
31 #include <algorithm> /* swap. */
32 #include <set>
33 #include <map>
34 #include "chunks.h"
35 #include "gamemap.h"
36 #include "Astar.h"
37 #include "Audio.h"
38 #include "Gump_manager.h"
39 #include "Paperdoll_gump.h"
40 #include "Zombie.h"
41 #include "actions.h"
42 #include "actors.h"
43 #include "cheat.h"
44 #include "combat.h"
45 #include "combat_opts.h"
46 #include "dir.h"
47 #include "egg.h"
48 #include "exult.h"
49 #include "Face_stats.h"
50 #include "frameseq.h"
51 #include "game.h"
52 #include "gamewin.h"
53 #include "gameclk.h"
54 #include "imagewin.h"
55 #include "items.h"
56 #include "npctime.h"
57 #include "ready.h"
58 #include "ucmachine.h"
59 #include "party.h"
60 #include "monstinf.h"
61 #include "exult_constants.h"
62 #include "monsters.h"
63 #include "effects.h"
64 #include "palette.h"
65 #include "ucsched.h"
66 #include "ucscriptop.h"
67 #include "miscinf.h"
68 #include "animate.h"
69 #include "objiter.h"
70 #include "ammoinf.h"
71 #include "armorinf.h"
72 #include "frflags.h"
73 #include "weaponinf.h"
74 #include "npcdollinf.h"
75 #include "spellbook.h"
76 #include "usefuns.h"
77 #include "ignore_unused_variable_warning.h"
78 #include "array_size.h"
79
80 #ifdef USE_EXULTSTUDIO
81 #include "server.h"
82 #include "objserial.h"
83 #include "mouse.h"
84 #include "servemsg.h"
85 #endif
86
87 using std::cerr;
88 using std::cout;
89 using std::endl;
90 using std::memcpy;
91 using std::rand;
92 using std::string;
93 using std::swap;
94
95 Game_object_shared Actor::editing;
96
97 extern bool combat_trace;
98
99 // Party positions
100 // Direction, Party num, xy (tile) from leader
101 //
102 // Please Don't Touch - Colourless
103 //
104 const short Actor::party_pos[4][10][2] = {
105 // North Facing
106 {
107 { -2, 2 },
108 { 2, 2 },
109 { 0, 4 },
110 { -4, 4 },
111 { 4, 4 },
112 { -2, 6 },
113 { 2, 6 },
114 { 0, 8 },
115 { -4, 8 },
116 { 4, 8 }
117 },
118 // East Facing,
119 {
120 { -2, -2 },
121 { -2, 2 },
122 { -4, 0 },
123 { -4, -4 },
124 { -4, 4 },
125 { -6, -2 },
126 { -6, 2 },
127 { -8, 0 },
128 { -8, -4 },
129 { -8, 4 }
130 },
131 // South Facing
132 {
133 { -2, -2 },
134 { 2, -2 },
135 { 0, -4 },
136 { -4, -4 },
137 { 4, -4 },
138 { -2, -6 },
139 { 2, -6 },
140 { 0, -8 },
141 { -4, -8 },
142 { 4, -8 }
143 },
144 // West Facing
145 {
146 { 2, -2 },
147 { 2, 2 },
148 { 4, 0 },
149 { 4, -4 },
150 { 4, 4 },
151 { 6, -2 },
152 { 6, 2 },
153 { 8, 0 },
154 { 8, -4 },
155 { 8, 4 }
156 }
157 };
158
159 // Actor frame to substitute when a frame is empty (as some are):
160 uint8 visible_frames[16] = {
161 Actor::standing, // Standing.
162 Actor::standing, // Steps.
163 Actor::standing,
164 Actor::standing, // Ready.
165 Actor::raise2_frame, // 1-handed strikes => 2-handed.
166 Actor::reach2_frame,
167 Actor::strike2_frame,
168 Actor::raise1_frame, // 2-handed => 1-handed.
169 Actor::reach1_frame,
170 Actor::strike1_frame,
171 Actor::standing, // When you can't sit...
172 Actor::kneel_frame, // When you can't bow.
173 Actor::bow_frame, // When you can't kneel.
174 Actor::standing, // Can't lie.
175 Actor::strike2_frame, // Can't raise hands.
176 Actor::ready_frame
177 }; // Can't strech arms outward.
178
179
180 // Set up actor's frame lists.
181 // Most NPC's walk with a 'stand'
182 // frame between steps.
183 const int FRAME_NUM = 5;
184 uint8 npc_north_framenums[FRAME_NUM] = { 0, 1, 0, 2, 0},
185 npc_south_framenums[FRAME_NUM] = {16, 17, 16, 18, 16},
186 npc_east_framenums[FRAME_NUM] = {48, 49, 48, 50, 48},
187 npc_west_framenums[FRAME_NUM] = {32, 33, 32, 34, 32};
188 static Frames_sequence npc_north_frames(FRAME_NUM, npc_north_framenums);
189 static Frames_sequence npc_south_frames(FRAME_NUM, npc_south_framenums);
190 static Frames_sequence npc_east_frames(FRAME_NUM, npc_east_framenums);
191 static Frames_sequence npc_west_frames(FRAME_NUM, npc_west_framenums);
192 // Avatar just walks left, right.
193 uint8 avatar_north_framenums[3] = {0, 1, 2},
194 avatar_south_framenums[3] = {16, 17, 18},
195 avatar_east_framenums[3] = {48, 49, 50},
196 avatar_west_framenums[3] = {32, 33, 34};
197 static Frames_sequence avatar_north_frames(3, avatar_north_framenums);
198 static Frames_sequence avatar_south_frames(3, avatar_south_framenums);
199 static Frames_sequence avatar_east_frames(3, avatar_east_framenums);
200 static Frames_sequence avatar_west_frames(3, avatar_west_framenums);
201
202 Frames_sequence *Actor::avatar_frames[4] = {nullptr, nullptr, nullptr, nullptr};
203 Frames_sequence *Actor::npc_frames[4] = {nullptr, nullptr, nullptr, nullptr};
204
205 const signed char sea_serpent_attack_frames[] = {1, 2, 3};
206 const signed char reach_attack_frames1[] = {3, 6};
207 const signed char raise_attack_frames1[] = {3, 4, 6};
208 const signed char fast_swing_attack_frames1[] = {3, 5, 6};
209 const signed char slow_swing_attack_frames1[] = {3, 4, 5, 6};
210 const signed char reach_attack_frames2[] = {3, 9};
211 const signed char raise_attack_frames2[] = {3, 7, 9};
212 const signed char fast_swing_attack_frames2[] = {3, 8, 9};
213 const signed char slow_swing_attack_frames2[] = {3, 7, 8, 9};
214
215 // inline int Is_attack_frame(int i) { return i >= 3 && i <= 9; }
Is_attack_frame(int i)216 inline bool Is_attack_frame(int i) {
217 return i == 6 || i == 9;
218 }
Get_dir_from_frame(int i)219 inline int Get_dir_from_frame(int i) {
220 return ((((i & 16) / 8) - ((i & 32) / 32)) + 4) % 4;
221 }
222
223 /**
224 * Provides attribute/value pairs.
225 */
226 class Actor_attributes {
227 /// The attribute names. These are shared among all actors.
228 static std::set<string> *strings;
229 using Att_map = std::map<const char *, int>;
230 /// The attribute name > value map.
231 Att_map map;
232 public:
233 /// Basic constructor. Initializes the attribute names.
Actor_attributes()234 Actor_attributes() {
235 if (!strings)
236 strings = new std::set<string>;
237 }
238 /// Sets an attribute's value and, if needed, adds it to
239 /// the attribute name list.
240 /// @param nm The name of the attribute to be set.
241 /// @param val Value to set the attribute to.
set(const char * nm,int val)242 void set(const char *nm, int val) {
243 auto siter = strings->find(nm);
244 if (siter == strings->end())
245 siter = strings->insert(nm).first;
246 nm = (*siter).c_str();
247 map[nm] = val;
248 }
249 /// Gets an attribute's value, if it is in the list.
250 /// @param nm The name of the attribute to be gotten.
251 /// @return val Current value of the attribute, or
252 /// zero if the attribute is not on the list.
get(const char * nm)253 int get(const char *nm) { // Returns 0 if not set.
254 auto siter = strings->find(nm);
255 if (siter == strings->end())
256 return 0;
257 nm = (*siter).c_str();
258 auto it = map.find(nm);
259 return it == map.end() ? 0 : (*it).second;
260 }
261 /// Gets all attributes for the current actor.
262 /// @param attlist (name, value) vector containig all attributes.
get_all(std::vector<std::pair<const char *,int>> & attlist)263 void get_all(std::vector<std::pair<const char *, int> > &attlist) {
264 for (auto& it : map)
265 attlist.emplace_back(it);
266 }
267 };
268 std::set<string> *Actor_attributes::strings = nullptr;
269
270 /**
271 * Get/create timers.
272 * @return
273 */
274
need_timers()275 Npc_timer_list *Actor::need_timers(
276 ) {
277 if (!timers)
278 timers = new Npc_timer_list(this);
279 return timers;
280 }
281
282 /**
283 * Initialize frames, properties and spots.
284 */
285
init()286 void Actor::init(
287 ) {
288 if (!avatar_frames[0])
289 init_default_frames();
290 size_t i;
291 for (i = 0; i < array_size(properties); i++)
292 properties[i] = 0;
293 for (i = 0; i < array_size(spots); i++)
294 spots[i] = nullptr;
295 }
296
297 /**
298 * Find (best) ammo of given type.
299 * @param family Desired ammo family shape.
300 * @param needed Minimum quantity needed.
301 * @return Pointer to object, if found.
302 */
303
find_best_ammo(int family,int needed)304 Game_object *Actor::find_best_ammo(
305 int family,
306 int needed
307 ) {
308 Game_object *best = nullptr;
309 int best_strength = -20;
310 Game_object_vector vec; // Get list of all possessions.
311 vec.reserve(50);
312 get_objects(vec, c_any_shapenum, c_any_qual, c_any_framenum);
313 for (auto *obj : vec) {
314 if (obj->inside_locked() || !In_ammo_family(obj->get_shapenum(), family))
315 continue;
316 const Ammo_info *ainf = obj->get_info().get_ammo_info();
317 if (!ainf) // E.g., musket ammunition doesn't have it.
318 continue;
319 // Can't use it.
320 if (obj->get_quantity() < needed)
321 continue;
322 // Calc ammo strength.
323 int strength = ainf->get_base_strength();
324 // Favor those with more shots remaining.
325 if (obj->get_quantity() < 5 * needed)
326 strength /= 3;
327 else if (obj->get_quantity() < 10 * needed)
328 strength /= 2;
329 if (strength > best_strength) {
330 best = obj;
331 best_strength = strength;
332 }
333 }
334 return best;
335 }
336
337 /**
338 * Get effective maximum range for weapon taking in consideration
339 * the actor's strength and combat.
340 * @param winf Pointer to weapon information of the current weapon,
341 * or null for no weapon.
342 * @param reach Weapon reach, or -1 to use weapon's.
343 * @return Weapon's effective range.
344 */
get_effective_range(const Weapon_info * winf,int reach) const345 int Actor::get_effective_range(
346 const Weapon_info *winf,
347 int reach
348 ) const {
349 if (reach < 0) {
350 if (!winf) {
351 const Monster_info *minf = get_info().get_monster_info();
352 return minf ? minf->get_reach()
353 : Monster_info::get_default()->get_reach();
354 }
355 reach = winf->get_range();
356 }
357 int uses = winf ? winf->get_uses() : static_cast<int>(Weapon_info::melee);
358 if (!uses || uses == Weapon_info::ranged)
359 return reach;
360 else {
361 int eff_range;
362 int str = get_effective_prop(static_cast<int>(Actor::strength));
363 int combat = get_effective_prop(static_cast<int>(Actor::combat));
364 if (str < combat)
365 eff_range = str;
366 else
367 eff_range = combat;
368 if (uses == Weapon_info::good_thrown)
369 eff_range *= 2;
370 if (eff_range < reach)
371 eff_range = reach;
372 if (eff_range > 31)
373 eff_range = 31;
374 return eff_range;
375 }
376 }
377
378 /**
379 * Find ammo used by weapon.
380 * @param weapon The weapon shape.
381 * @param needed Minimum quantity needed.
382 * @param recursive Whether or not to search inside backpacks and bags.
383 * @return Pointer to object if found.
384 */
385
find_weapon_ammo(int weapon,int needed,bool recursive)386 Game_object *Actor::find_weapon_ammo(
387 int weapon,
388 int needed,
389 bool recursive
390 ) {
391 if (weapon < 0)
392 return nullptr;
393 const Weapon_info *winf = ShapeID::get_info(weapon).get_weapon_info();
394 if (!winf)
395 return nullptr;
396 int family = winf->get_ammo_consumed();
397 if (family >= 0) {
398 Game_object *aobj = get_readied(quiver);
399 if (aobj && In_ammo_family(aobj->get_shapenum(), family) &&
400 aobj->get_quantity() >= needed)
401 return aobj; // Already readied.
402 else if (recursive)
403 return find_best_ammo(family, needed);
404 return nullptr;
405 }
406
407 // Search readied weapons first.
408 static Ready_type_Exult wspots[] = {lhand, rhand, back_2h, belt};
409 for (auto wspot : wspots) {
410 Game_object *obj = spots[static_cast<int>(wspot)];
411 if (!obj || obj->get_shapenum() != weapon)
412 continue;
413 const Shape_info &inf = obj->get_info();
414 if (family == -2) {
415 if (!inf.has_quality() || obj->get_quality() >= needed)
416 return obj;
417 }
418 // Family -1 and family -3.
419 else if (obj->get_quantity() >= needed)
420 return obj;
421 }
422
423 // Now recursively search all contents.
424 return recursive ? Container_game_object::find_weapon_ammo(weapon) : nullptr;
425 }
426
427 /**
428 * Swap new ammo with old.
429 * @param newammo Pointer to new ammo object.
430 */
431
swap_ammo(Game_object * newammo)432 void Actor::swap_ammo(
433 Game_object *newammo
434 ) {
435 Game_object *aobj = get_readied(quiver);
436 if (aobj == newammo)
437 return; // Already what we need.
438 // Keep these from getting deleted:
439 Game_object_shared aobj_shared;
440 Game_object_shared newammo_shared;
441 if (aobj) { // Something there already?
442 aobj->remove_this(&aobj_shared); // Remove it.
443 }
444 newammo->remove_this(&newammo_shared);
445 add(newammo, true); // Should go to the right place.
446 if (aobj) // Put back old ammo.
447 add(aobj, true);
448 }
449
450 /**
451 * Recursivelly searches for ammunition for a given weapon, if needed.
452 * @param npc The NPC to be searched.
453 * @param bobj The weapon we want to check.
454 * @param ammo Optional pointer that receives a pointer to the best ammunition
455 * found for the given weapon.
456 * @param recursive Whether or not to search inside backpacks and bags.
457 * @return true if the weapon can be used, ammo is pointer to best ammunition.
458 */
459
Is_weapon_usable(Actor * npc,Game_object * bobj,Game_object ** ammo=nullptr,bool recursive=true)460 static inline bool Is_weapon_usable(
461 Actor *npc,
462 Game_object *bobj,
463 Game_object **ammo = nullptr,
464 bool recursive = true
465 ) {
466 if (ammo)
467 *ammo = nullptr;
468 const Weapon_info *winf = bobj->get_info().get_weapon_info();
469 if (!winf)
470 return false; // Not a weapon.
471 Game_object *aobj = nullptr; // Check ranged first.
472 int need_ammo = npc->get_weapon_ammo(bobj->get_shapenum(),
473 winf->get_ammo_consumed(), winf->get_projectile(),
474 true, &aobj, recursive);
475 if (!need_ammo)
476 return true;
477 // Try melee if the weapon is not ranged.
478 else if (!aobj && winf->get_uses() != Weapon_info::ranged)
479 need_ammo = npc->get_weapon_ammo(bobj->get_shapenum(),
480 winf->get_ammo_consumed(), winf->get_projectile(),
481 false, &aobj, recursive);
482 if (need_ammo && !aobj)
483 return false;
484 if (ammo)
485 *ammo = aobj;
486 return true;
487 }
488
489 /**
490 * Ready ammo for weapon being carried.
491 * @return Returns true if successful.
492 */
493
ready_ammo()494 bool Actor::ready_ammo(
495 ) {
496 Game_object *weapon = spots[static_cast<int>(lhand)];
497 if (!weapon)
498 return false;
499 const Shape_info &info = weapon->get_info();
500 const Weapon_info *winf = info.get_weapon_info();
501 if (!winf)
502 return false;
503 int ammo = winf->get_ammo_consumed();
504 if (ammo < 0) {
505 // Ammo not needed.
506 return !(winf->uses_charges() && info.has_quality() &&
507 weapon->get_quality() <= 0); // Uses charges, but none left.
508 }
509 Game_object *found = nullptr;
510 // Try non-recursive search for ammo first.
511 bool usable = Is_weapon_usable(this, weapon, &found, false);
512 if (usable) // Ammo is available and ready.
513 return true;
514 // Try recursive search now.
515 found = find_best_ammo(ammo);
516 if (!found)
517 return false;
518 swap_ammo(found);
519 return true;
520 }
521
522 /**
523 * If no shield readied, look through all possessions for the best one.
524 * @return Returns true if successful.
525 */
526
ready_best_shield()527 bool Actor::ready_best_shield(
528 ) {
529 if (two_handed)
530 return false;
531 if (spots[rhand]) {
532 const Shape_info &inf = spots[rhand]->get_info();
533 if (is_in_party() || inf.get_armor() || inf.get_armor_immunity())
534 return inf.get_armor() || inf.get_armor_immunity();
535 }
536 Game_object *old_rhand = nullptr;
537 Game_object_shared rhand_keep;
538 Game_object_shared best_keep;
539 if (spots[rhand]) { // remove old offhand item
540 old_rhand = spots[rhand];
541 old_rhand->remove_this(&rhand_keep);
542 }
543 Game_object_vector vec; // Get list of all possessions.
544 vec.reserve(50);
545 get_objects(vec, c_any_shapenum, c_any_qual, c_any_framenum);
546 Game_object *best = nullptr;
547 int best_strength = -20;
548 for (auto *obj : vec) {
549 if (obj->inside_locked())
550 continue;
551 const Shape_info &info = obj->get_info();
552 // Only want those that can be readied in hand.
553 int ready = info.get_ready_type();
554 if (ready != lhand && ready != backpack)
555 continue;
556 const Armor_info *arinf = info.get_armor_info();
557 if (!arinf)
558 continue; // Not a shield.
559 if (spots[lhand] == obj) // Don't take the weapon.
560 continue;
561 int strength = arinf->get_base_strength();
562 if (strength > best_strength) {
563 best = obj;
564 best_strength = strength;
565 }
566 }
567 if (!best) {
568 if (old_rhand) // add offhand item back to where it was
569 add(old_rhand, true);
570 return false;
571 }
572 // Spot is free already.
573 best->remove_this(&best_keep);
574 add(best, true); // Should go to the right place.
575 if (old_rhand && old_rhand != best) // don't add twice
576 add(old_rhand, true);
577 return true;
578 }
579
580
581 /**
582 * If no weapon readied, look through all possessions for the best one.
583 * @return Returns true if successful.
584 */
585
ready_best_weapon()586 bool Actor::ready_best_weapon(
587 ) {
588 int points;
589 if (Actor::get_weapon(points) != nullptr && ready_ammo()) {
590 ready_best_shield();
591 return true; // Already have one.
592 }
593 // Check for spellbook.
594 Game_object *obj = get_readied(lhand);
595 if (obj && obj->get_info().get_shape_class() == Shape_info::spellbook) {
596 if ((static_cast<Spellbook_object *>(obj))->can_do_spell(this)) {
597 ready_best_shield();
598 return true;
599 }
600 }
601 Game_object_vector vec; // Get list of all possessions.
602 vec.reserve(50);
603 get_objects(vec, c_any_shapenum, c_any_qual, c_any_framenum);
604 Game_object *best = nullptr;
605 Game_object *best_ammo = nullptr;
606 Game_object_shared keep1;
607 Game_object_shared keep2;
608 Game_object_shared best_keep;
609 int best_strength = -20;
610 int wtype = backpack;
611 for (auto *obj : vec) {
612 if (obj->inside_locked())
613 continue;
614 const Shape_info &info = obj->get_info();
615 int ready = info.get_ready_type();
616 // backpack and rhand added for dragon breath and some spells
617 if (ready != lhand && ready != both_hands &&
618 ready != rhand && ready != backpack)
619 continue;
620 const Weapon_info *winf = info.get_weapon_info();
621 if (!winf)
622 continue; // Not a weapon.
623 Game_object *ammo_obj = nullptr;
624 if (!Is_weapon_usable(this, obj, &ammo_obj))
625 continue;
626 int strength = winf->get_base_strength();
627 strength += get_effective_range(winf);
628 if (strength > best_strength) {
629 wtype = ready;
630 best = obj;
631 best_ammo = ammo_obj != obj ? ammo_obj : nullptr;
632 best_strength = strength;
633 }
634 }
635 if (!best) {
636 ready_best_shield();
637 return false;
638 }
639 // If nothing is in left hand, nothing will happen.
640 Game_object* remove1 = spots[lhand];
641 Game_object* remove2 = nullptr;
642 if (wtype == both_hands && spots[rhand])
643 remove2 = spots[rhand];
644 // Prevent double removal and double add (can corrupt objects list).
645 // No need for similar check for remove1 as we wouldn't be here
646 // if remove1 were a weapon we could use.
647 if (remove2 == best)
648 remove2 = nullptr;
649 // Free the spot(s).
650 if (remove1)
651 remove1->remove_this(&keep1);
652 if (remove2)
653 remove2->remove_this(&keep2);
654 best->remove_this(&best_keep);
655 if (wtype == rhand) // tell it the correct ready spot
656 add_readied(best, lhand);
657 else
658 add(best, true); // Should go to the right place.
659 ready_best_shield(); // Also add a shield for 1-handed weapons.
660 if (remove1) // Put back other things.
661 add(remove1, true);
662 if (remove2)
663 add(remove2, true);
664 if (best_ammo)
665 swap_ammo(best_ammo);
666 return true;
667 }
668
669 /**
670 * Try to store given object.
671 */
672
empty_hand(Game_object * obj,Game_object_shared * keep)673 bool Actor::empty_hand(
674 Game_object *obj,
675 Game_object_shared *keep
676 ) {
677 if (!obj)
678 return true;
679 static int chkspots[] = {belt, backpack};
680 add_dirty();
681 obj->remove_this(keep);
682 for (int chkspot : chkspots)
683 if (add_readied(obj, chkspot, true, true)) // Slot free?
684 return true;
685
686 return false;
687 }
688
689 /**
690 * Try to store what is the hands.
691 */
692
empty_hands()693 void Actor::empty_hands(
694 ) {
695 Game_object *obj = spots[lhand];
696 Game_object_shared keep;
697 if (!empty_hand(obj, &keep))
698 add(obj, true);
699 obj = spots[rhand];
700 if (!empty_hand(obj, &keep))
701 add(obj, true);
702 }
703
704 /**
705 * Get effective weapon shape, taking casting frames in consideration.
706 * @return The shape to be displayed in-hand.
707 */
708
get_effective_weapon_shape() const709 int Actor::get_effective_weapon_shape(
710 ) const {
711 if (get_casting_mode() == Actor::show_casting_frames)
712 // Casting frames
713 return casting_shape;
714 else {
715 Game_object *weapon = spots[lhand];
716 return weapon->get_shapenum();
717 }
718 }
719
720 /**
721 * Add dirty rectangle(s).
722 * @return Returns false if not on screen.
723 */
add_dirty(bool figure_rect)724 bool Actor::add_dirty(
725 bool figure_rect // Recompute weapon rectangle.
726 ) {
727 if (!gwin->add_dirty(this))
728 return false;
729 if (figure_rect || get_casting_mode() == Actor::show_casting_frames) {
730 int weapon_x;
731 int weapon_y;
732 int weapon_frame;
733 if (figure_weapon_pos(weapon_x, weapon_y, weapon_frame)) {
734 int shnum = get_effective_weapon_shape();
735
736 Shape_frame *wshape = ShapeID(shnum, weapon_frame).get_shape();
737
738 if (wshape) // Set dirty area rel. to NPC.
739 weapon_rect = gwin->get_shape_rect(wshape,
740 weapon_x, weapon_y);
741 else
742 weapon_rect.w = 0;
743 } else
744 weapon_rect.w = 0;
745 }
746 if (weapon_rect.w > 0) { // Repaint weapon area too.
747 TileRect r = weapon_rect;
748 int xoff;
749 int yoff;
750 gwin->get_shape_location(this, xoff, yoff);
751 r.shift(xoff, yoff);
752 r.enlarge(c_tilesize / 2);
753 gwin->add_dirty(gwin->clip_to_win(r));
754 }
755 return true;
756 }
757
758 /**
759 * Change the frame and set to repaint areas.
760 * @param frnum The new frame.
761 */
762
change_frame(int frnum)763 void Actor::change_frame(
764 int frnum
765 ) {
766 add_dirty(); // Set to repaint old area.
767 ShapeID id(get_shapenum(), frnum, get_shapefile());
768 Shape_frame *shape = id.get_shape();
769 if (!shape || shape->is_empty()) {
770 // Swap 1hand <=> 2hand frames.
771 frnum = (frnum & 48) | visible_frames[frnum & 15];
772 id.set_frame(frnum);
773 if (!(shape = id.get_shape()) || shape->is_empty())
774 frnum = (frnum & 48) | Actor::standing;
775 }
776 rest_time = 0;
777 set_frame(frnum);
778 add_dirty(true); // Set to repaint new.
779 }
780
781 /**
782 * See if it's blocked when trying to move to a new tile.
783 * @param t Tile to step to. Tz is possibly updated by this function.
784 * @param f Pointer to tile we are stepping from, or null for current tile.
785 * @param move_flags Additional movement flags to consider for step.
786 * @return Returns true if so, else false.
787 */
788
is_blocked(Tile_coord & t,Tile_coord * f,const int move_flags)789 bool Actor::is_blocked(
790 Tile_coord &t, // Tz possibly updated.
791 Tile_coord *f, // Step from here, or curpos if null.
792 const int move_flags
793 ) {
794 const Shape_info &info = get_info();
795 // Get dim. in tiles.
796 int frame = get_framenum();
797 int xtiles = info.get_3d_xtiles(frame);
798 int ytiles = info.get_3d_ytiles(frame);
799 int ztiles = info.get_3d_height();
800 t.fixme();
801 if (xtiles == 1 && ytiles == 1) { // Simple case?
802 Map_chunk *nlist = gmap->get_chunk(
803 t.tx / c_tiles_per_chunk, t.ty / c_tiles_per_chunk);
804 nlist->setup_cache();
805 int new_lift;
806 bool blocked = nlist->is_blocked(ztiles, t.tz,
807 t.tx % c_tiles_per_chunk, t.ty % c_tiles_per_chunk,
808 new_lift, move_flags | get_type_flags());
809 t.tz = new_lift;
810 return blocked;
811 }
812 return Map_chunk::is_blocked(xtiles, ytiles, ztiles,
813 f ? *f : get_tile(), t, move_flags | get_type_flags());
814 }
815
816 /**
817 * Finds an object which blocks the destination tile.
818 * @param tile The (blocked) tile to check.
819 * @param dir Direction we are stepping from.
820 */
821
find_blocking(Tile_coord const & tile,int dir)822 Game_object *Actor::find_blocking(
823 Tile_coord const &tile,
824 int dir
825 ) {
826 ignore_unused_variable_warning(tile);
827 TileRect footprint = get_footprint();
828 TileRect base = get_footprint();
829 switch (dir) {
830 case north:
831 footprint.shift(0, -1);
832 break;
833 case northeast:
834 footprint.shift(1, -1);
835 break;
836 case east:
837 footprint.shift(1, 0);
838 break;
839 case southeast:
840 footprint.shift(1, 1);
841 break;
842 case south:
843 footprint.shift(0, 1);
844 break;
845 case southwest:
846 footprint.shift(-1, 1);
847 break;
848 case west:
849 footprint.shift(-1, 0);
850 break;
851 case northwest:
852 footprint.shift(-1, -1);
853 break;
854 }
855 Game_object *block;
856 for (int i = footprint.x; i < footprint.x + footprint.w; i++)
857 for (int j = footprint.y; j < footprint.y + footprint.h; j++)
858 if (base.has_world_point(i, j))
859 continue;
860 else if ((block = Game_object::find_blocking(
861 Tile_coord(i, j, get_tile().tz))) != nullptr)
862 return block;
863 return nullptr;
864 }
865
866 /**
867 * Move an object, and possibly change its shape too.
868 * @param old_chunk The actor's old chunk.
869 * @param new_chunk The chunk to which the actor is moving.
870 * @param new_sx New x coordinate.
871 * @param new_sy New y coordinate.
872 * @param new_frame The new frame.
873 * @param new_lift The new z coordinate.
874 */
movef(Map_chunk * old_chunk,Map_chunk * new_chunk,int new_sx,int new_sy,int new_frame,int new_lift)875 inline void Actor::movef(
876 Map_chunk *old_chunk,
877 Map_chunk *new_chunk,
878 int new_sx, int new_sy, int new_frame,
879 int new_lift
880 ) {
881 Game_object_shared keep = shared_from_this();
882 if (old_chunk) // Remove from current chunk.
883 old_chunk->remove(this);
884 set_shape_pos(new_sx, new_sy);
885 if (new_frame >= 0)
886 change_frame(new_frame);
887 if (new_lift >= 0)
888 set_lift(new_lift);
889 new_chunk->add(this);
890 }
891
892 /**
893 * Create character.
894 * @param nm The actor's name.
895 * @param shapenum The initial shape.
896 * @param num The NPC's number from npc.dat.
897 * @param uc The usecofe function to use.
898 */
899
Actor(const std::string & nm,int shapenum,int num,int uc)900 Actor::Actor(
901 const std::string &nm,
902 int shapenum,
903 int num,
904 int uc
905 ) : name(nm), usecode(uc),
906 usecode_assigned(false), unused(false),
907 npc_num(num), face_num(num), party_id(-1), atts(nullptr), temperature(0),
908 shape_save(-1), oppressor(-1),
909 casting_mode(not_casting), casting_shape(-1),
910 target_tile(Tile_coord(-1, -1, 0)), attack_weapon(-1),
911 attack_mode(nearest),
912 schedule_type(Schedule::loiter), next_schedule(255), schedule(nullptr),
913 restored_schedule(-1), dormant(true), hit(false), combat_protected(false),
914 user_set_attack(false), alignment(0), charmalign(0), two_handed(false),
915 two_fingered(false), use_scabbard(false), use_neck(false),
916 light_sources(0), usecode_dir(0), type_flags(0),
917 gear_immunities(0), gear_powers(0), ident(0),
918 skin_color(-1), action(nullptr),
919 frame_time(0), step_index(0), qsteps(0), timers(nullptr),
920 weapon_rect(0, 0, 0, 0), rest_time(0) {
921 set_shape(shapenum, 0);
922 init();
923 frames = &npc_frames[0]; // Default: 5-frame walking.
924 }
925
926 /**
927 * Deletes actor.
928 */
929
~Actor()930 Actor::~Actor(
931 ) {
932 purge_deleted_actions();
933 if (in_queue() && gwin->get_tqueue())
934 gwin->get_tqueue()->remove(this);
935 delete schedule;
936 delete action;
937 delete timers;
938 delete atts;
939 }
940
941 /**
942 * Goes through the actor's readied gear and caches powers
943 * and immunities.
944 */
945
refigure_gear()946 void Actor::refigure_gear() {
947 static Ready_type_Exult locs[] = {head, belt, lhand, lfinger, legs,
948 feet, rfinger, rhand, torso, amulet,
949 earrings, cloak, gloves
950 };
951 int powers = 0;
952 int immune = 0;
953 light_sources = 0;
954 for (auto loc : locs) {
955 Game_object *worn = spots[static_cast<int>(loc)];
956 if (worn) {
957 const Shape_info &info = worn->get_info();
958 char rdy = info.get_ready_type();
959 if (info.is_light_source() && (loc != belt ||
960 (rdy != lhand && rdy != rhand && rdy != both_hands)))
961 add_light_source(info.get_object_light(worn->get_framenum()));
962 powers |= info.get_object_flags(worn->get_framenum(),
963 info.has_quality() ? worn->get_quality() : -1);
964 immune |= info.get_armor_immunity();
965 }
966 }
967 gear_immunities = immune;
968 gear_powers = powers;
969 }
970
say_hunger_message()971 void Actor::say_hunger_message() {
972 int food = get_property(static_cast<int>(food_level));
973 if (food <= 0) { // Really low?
974 if (rand() % 4)
975 say(first_starving, last_starving);
976 } else if (food <= 4) {
977 if (rand() % 3)
978 say(first_needfood, last_needfood);
979 } else { //if (food <= 9)
980 if (rand() % 2)
981 say(first_hunger, last_hunger);
982 }
983 }
984
985 /**
986 * Decrement food level and print complaints if it gets too low.
987 * NOTE: Should be called every hour.
988 */
989
use_food()990 void Actor::use_food(
991 ) {
992 if (get_info().does_not_eat() || (gear_powers & Frame_flags::doesnt_eat))
993 return;
994 int food = get_property(static_cast<int>(food_level));
995 food -= (rand() % 4); // Average 1.5 level/hour.
996 set_property(static_cast<int>(food_level), food);
997 if (food > 9)
998 return;
999 say_hunger_message();
1000 need_timers()->start_hunger(); // minute checks for damage and messages.
1001 }
1002
1003 /**
1004 * Periodic check for freezing.
1005 * @param freeze True if the actor is freezing. This is usually the
1006 * Avatar's freeze flag.
1007 */
1008
check_temperature(bool freeze)1009 void Actor::check_temperature(
1010 bool freeze
1011 ) {
1012 if (!freeze) { // Not in a cold area?
1013 if (!temperature) // 0 means warm.
1014 return; // Nothing to do.
1015 // Warming up.
1016 temperature -= (temperature >= 5 ? 5 : temperature);
1017 if (rand() % 3 == 0) {
1018 if (temperature >= 30)
1019 say(first_warming_up, last_warming_up);
1020 else
1021 say(first_warming_up_2, last_warming_up_2);
1022 }
1023 return;
1024 }
1025 // Immune to cold by nature or an item?
1026 if (get_info().is_cold_immune() || (gear_powers & Frame_flags::cold_immune))
1027 return;
1028 if (get_schedule_type() == Schedule::wait)
1029 return; // Not following leader? Leave alone.
1030 int warmth = figure_warmth(); // (This could be saved for speed.)
1031 if (warmth >= 100) { // Enough clothing?
1032 if (!temperature)
1033 return; // Already warm.
1034 int decr = 1 + (warmth - 100) / 10;
1035 decr = decr > temperature ? temperature : decr;
1036 temperature -= decr;
1037 if (rand() % 3 == 0) {
1038 if (temperature >= 30)
1039 say(first_warming_in_cold, last_warming_in_cold);
1040 else
1041 say(first_warming_in_cold_2, last_warming_in_cold_2);
1042 }
1043 return;
1044 }
1045 int incr = 1 + (100 - warmth) / 20;
1046 temperature += incr;
1047 if (temperature > 63)
1048 temperature = 63;
1049 if (rand() % 3 == 0)
1050 switch (temperature / 10) {
1051 case 0:
1052 say(first_chilly, last_chilly); // A bit chilly.
1053 break;
1054 case 1:
1055 say(first_cold, last_cold); // It's colder.
1056 break;
1057 case 2:
1058 say(first_colder, last_colder);
1059 break;
1060 case 3:
1061 say(first_frostbite, last_frostbite); // Frostbite.
1062 break;
1063 case 4:
1064 say(first_frostbite_2, last_frostbite_2);
1065 break;
1066 case 5:
1067 say(first_frostbite_3, last_frostbite_3);
1068 reduce_health(1, Weapon_data::sonic_damage);
1069 break;
1070 case 6:
1071 say(first_frozen, last_frozen); // Frozen.
1072 reduce_health(1 + rand() % 3, Weapon_data::sonic_damage);
1073 break;
1074 }
1075 }
1076
1077 /*
1078 * Get sequence of frames for an attack.
1079 *
1080 * Output: # of frames stored.
1081 */
1082
get_attack_frames(int weapon,bool projectile,int dir,signed char * frames) const1083 int Actor::get_attack_frames(
1084 int weapon, // Weapon shape, or -1 for innate.
1085 bool projectile, // Shooting/throwing.
1086 int dir, // 0-7 (as in dir.h).
1087 signed char *frames // Frames stored here.
1088 ) const {
1089 const signed char *which;
1090 int cnt = 0;
1091 if (is_slime())
1092 return 0;
1093 else if (get_info().has_strange_movement()) {
1094 which = sea_serpent_attack_frames;
1095 cnt = sizeof(sea_serpent_attack_frames);
1096 } else {
1097 const signed char *reach_attack_frames;
1098 const signed char *raise_attack_frames;
1099 const signed char *fast_swing_attack_frames;
1100 const signed char *slow_swing_attack_frames;
1101 if (two_handed) {
1102 reach_attack_frames = reach_attack_frames2;
1103 raise_attack_frames = raise_attack_frames2;
1104 fast_swing_attack_frames = fast_swing_attack_frames2;
1105 slow_swing_attack_frames = slow_swing_attack_frames2;
1106 } else {
1107 reach_attack_frames = reach_attack_frames1;
1108 raise_attack_frames = raise_attack_frames1;
1109 fast_swing_attack_frames = fast_swing_attack_frames1;
1110 slow_swing_attack_frames = slow_swing_attack_frames1;
1111 }
1112 unsigned char frame_flags; // Get Actor_frame flags.
1113 const Weapon_info *winfo;
1114 if (weapon >= 0 &&
1115 (winfo = ShapeID::get_info(weapon).get_weapon_info()) != nullptr)
1116 frame_flags = winfo->get_actor_frames(projectile);
1117 else // Default to normal swing.
1118 frame_flags = projectile ? Weapon_info::reach : Weapon_info::fast_swing;
1119 switch (frame_flags) {
1120 case Weapon_info::reach:
1121 which = reach_attack_frames;
1122 cnt = sizeof(reach_attack_frames1);
1123 break;
1124 case Weapon_info::raise:
1125 which = raise_attack_frames;
1126 cnt = sizeof(raise_attack_frames1);
1127 break;
1128 case Weapon_info::fast_swing:
1129 which = fast_swing_attack_frames;
1130 cnt = sizeof(fast_swing_attack_frames1);
1131 break;
1132 case Weapon_info::slow_swing:
1133 default:
1134 which = slow_swing_attack_frames;
1135 cnt = sizeof(slow_swing_attack_frames1);
1136 break;
1137 }
1138 }
1139 for (int i = 0; i < cnt; i++) { // Copy frames with correct dir.
1140 int frame = get_dir_framenum(dir, *which++);
1141 // Check for empty shape.
1142 ShapeID id(get_shapenum(), frame, get_shapefile());
1143 Shape_frame *shape = id.get_shape();
1144 if (!shape || shape->is_empty()) {
1145 // Swap 1hand <=> 2hand frames.
1146 frame = get_dir_framenum(dir, visible_frames[frame & 15]);
1147 id.set_frame(frame);
1148 if (!(shape = id.get_shape()) || shape->is_empty())
1149 frame = get_dir_framenum(dir, Actor::standing);
1150 }
1151 *frames++ = frame;
1152 }
1153 return cnt;
1154 }
1155
add_light_source(Game_object * obj)1156 void Actor::add_light_source(Game_object *obj) {
1157 const Shape_info &info = obj->get_info();
1158 add_light_source(info.get_object_light(obj->get_framenum()));
1159 }
1160
remove_light_source(Game_object * obj)1161 void Actor::remove_light_source(Game_object *obj) {
1162 const Shape_info &info = obj->get_info();
1163 remove_light_source(info.get_object_light(obj->get_framenum()));
1164 }
1165
1166 /*
1167 * Set default set of frames.
1168 */
1169
init_default_frames()1170 void Actor::init_default_frames(
1171 ) {
1172 // Set up actor's frame lists.
1173 npc_frames[static_cast<int>(north) / 2] = &npc_north_frames;
1174 npc_frames[static_cast<int>(south) / 2] = &npc_south_frames;
1175 npc_frames[static_cast<int>(east) / 2] = &npc_east_frames;
1176 npc_frames[static_cast<int>(west) / 2] = &npc_west_frames;
1177 avatar_frames[static_cast<int>(north) / 2] = &avatar_north_frames;
1178 avatar_frames[static_cast<int>(south) / 2] = &avatar_south_frames;
1179 avatar_frames[static_cast<int>(east) / 2] = &avatar_east_frames;
1180 avatar_frames[static_cast<int>(west) / 2] = &avatar_west_frames;
1181 }
1182
1183 /*
1184 * This is called for the Avatar to return to a normal standing position
1185 * when not doing anything else.
1186 */
1187
stand_at_rest()1188 void Actor::stand_at_rest(
1189 ) {
1190 rest_time = 0; // Reset timer.
1191 int frame = get_framenum() & 0xf; // Base frame #.
1192 if (frame == standing || frame == sit_frame || frame == sleep_frame)
1193 return; // Already standing/sitting/sleeping.
1194 if (!is_dead() && schedule_type == Schedule::follow_avatar &&
1195 !get_flag(Obj_flags::asleep))
1196 change_frame(get_dir_framenum(standing));
1197 }
1198
1199 /*
1200 * Set new action.
1201 */
1202
set_action(Actor_action * newact)1203 void Actor::set_action(
1204 Actor_action *newact
1205 ) {
1206 if (newact != action) {
1207 Actor_action *todel;
1208 if (action && (todel = action->kill()) != nullptr)
1209 deletedactions.push_back(todel);
1210 action = newact;
1211 }
1212 if (!action) // No action? We're stopped.
1213 frame_time = 0;
1214 }
1215
1216 /*
1217 * Empty deleted action list.
1218 */
1219
purge_deleted_actions()1220 void Actor::purge_deleted_actions() {
1221 while (!deletedactions.empty()) {
1222 Actor_action *act = deletedactions.back();
1223 deletedactions.pop_back();
1224 delete act;
1225 }
1226 }
1227
1228 /*
1229 * Get destination, or current spot if no destination.
1230 */
1231
get_dest() const1232 Tile_coord Actor::get_dest(
1233 ) const {
1234 Tile_coord dest;
1235 if (action && action->get_dest(dest))
1236 return dest;
1237 else
1238 return get_tile();
1239 }
1240
1241 /*
1242 * Walk towards a given tile.
1243 */
1244
walk_to_tile(Tile_coord const & dest,int speed,int delay,int maxblk)1245 void Actor::walk_to_tile(
1246 Tile_coord const &dest, // Destination.
1247 int speed, // Time between frames (msecs).
1248 int delay, // Delay before starting (msecs) (only
1249 // if not already moving).
1250 int maxblk // Max. # retries if blocked.
1251 ) {
1252 if (!action)
1253 action = new Path_walking_actor_action(new Zombie(), maxblk);
1254 set_action(action->walk_to_tile(this, get_tile(), dest));
1255 if (action) // Successful at setting path?
1256 start(speed, delay);
1257 else
1258 frame_time = 0; // Not moving.
1259 }
1260
1261 /*
1262 * Find a path towards a given tile.
1263 *
1264 * Output: 0 if failed.
1265 */
1266
walk_path_to_tile(Tile_coord const & src,Tile_coord const & dest,int speed,int delay,int dist,int maxblk)1267 int Actor::walk_path_to_tile(
1268 Tile_coord const &src, // Our location, or an off-screen
1269 // location to try path from.
1270 Tile_coord const &dest, // Destination.
1271 int speed, // Time between frames (msecs).
1272 int delay, // Delay before starting (msecs) (only
1273 // if not already moving).
1274 int dist, // Distance to get within dest.
1275 int maxblk // Max. # retries if blocked.
1276 ) {
1277 set_action(new Path_walking_actor_action(new Astar(), maxblk));
1278 set_action(action->walk_to_tile(this, src, dest, dist));
1279 if (action) { // Successful at setting path?
1280 start(speed, delay);
1281 return 1;
1282 }
1283 frame_time = 0; // Not moving.
1284 return 0;
1285 }
1286
1287 /*
1288 * Begin animation.
1289 */
1290
start(int speed,int delay)1291 void Actor::start(
1292 int speed, // Time between frames (msecs).
1293 int delay // Delay before starting (msecs) (only
1294 // if not already moving).
1295 ) {
1296 dormant = false; // 14-jan-2001 - JSF.
1297 frame_time = speed;
1298 if (!in_queue() || delay) { // Not already in queue?
1299 if (delay)
1300 gwin->get_tqueue()->remove(this);
1301 uint32 curtime = Game::get_ticks();
1302 gwin->get_tqueue()->add(curtime + delay, this, gwin);
1303 }
1304 }
1305
1306 /*
1307 * Start with standard delay.
1308 */
start_std()1309 void Actor::start_std(
1310 ) {
1311 start(gwin->get_std_delay(), gwin->get_std_delay());
1312 }
1313
1314 /*
1315 * Stop animation.
1316 */
stop()1317 void Actor::stop(
1318 ) {
1319 /* +++ This might cause jerky walking. Needs to be done above? */
1320 if (action) {
1321 action->stop(this);
1322 add_dirty();
1323 }
1324 frame_time = 0;
1325 }
1326
1327 /*
1328 * Want one value to approach another.
1329 */
1330
Approach(int from,int to,int dist)1331 inline int Approach(
1332 int from,
1333 int to,
1334 int dist // Desired distance.
1335 ) {
1336 if (from <= to) // Going forwards?
1337 return to - from <= dist ? from : to - dist;
1338 else // Going backwards.
1339 return from - to <= dist ? from : to + dist;
1340 }
1341
1342 /*
1343 * Follow the leader.
1344 */
1345
follow(const Actor * leader)1346 void Actor::follow(
1347 const Actor *leader
1348 ) {
1349 if (Actor::is_dead() || !can_act())
1350 return; // Not when dead, paralyzed, or asleep.
1351 int delay = 0;
1352 int dist; // How close to aim for.
1353 Tile_coord leaderpos = leader->get_tile();
1354 Tile_coord pos = get_tile();
1355 Tile_coord goal;
1356 if (leader->is_moving()) { // Figure where to aim.
1357 // Aim for leader's dest.
1358 dist = 2 + party_id / 3;
1359 goal = leader->get_dest();
1360 goal.tx = Approach(pos.tx, goal.tx, dist);
1361 goal.ty = Approach(pos.ty, goal.ty, dist);
1362 } else { // Leader stopped?
1363 goal = leaderpos; // Aim for leader.
1364 if (gwin->walk_in_formation && distance(leader) <= 6)
1365 return; // In formation, & close enough.
1366 // cout << "Follow: Leader is stopped" << endl;
1367 // +++++For formation, why not get correct positions?
1368 static int xoffs[10] = { -1, 1, -2, 2, -3, 3, -4, 4, -5, 5};
1369 static int yoffs[10] = {1, -1, 2, -2, 3, -3, 4, -4, 5, -5};
1370 goal.tx += xoffs[party_id] + 1 - rand() % 3;
1371 goal.ty += yoffs[party_id] + 1 - rand() % 3;
1372 dist = 1;
1373 }
1374 // Already aiming along a path?
1375 if (is_moving() && action && action->following_smart_path() &&
1376 // And leader moving, or dest ~= goal?
1377 (leader->is_moving() || goal.distance(get_dest()) <= 5))
1378 return;
1379 // Tiles to goal.
1380 int goaldist = goal.distance(pos);
1381 if (goaldist < dist) { // Already close enough?
1382 if (!leader->is_moving())
1383 stop();
1384 return;
1385 }
1386 // Is leader following a path?
1387 bool leaderpath = leader->action &&
1388 leader->action->following_smart_path();
1389 // Get leader's distance from goal.
1390 int leaderdist = leader->distance(goal);
1391 // Get his speed.
1392 int speed = leader->get_frame_time();
1393 if (!speed) { // Not moving?
1394 speed = 100;
1395 if (goaldist < leaderdist) // Closer than leader?
1396 // Delay a bit IF not moving.
1397 delay = (1 + leaderdist - goaldist) * 100;
1398 }
1399 if (goaldist - leaderdist >= 5)
1400 speed -= 20; // Speed up if too far.
1401 // Get window rect. in tiles.
1402 TileRect wrect = gwin->get_win_tile_rect();
1403 int dist2lead = leader->distance(pos);
1404 // Getting kind of far away?
1405 if (dist2lead > wrect.w + wrect.w / 2 &&
1406 party_id >= 0 && // And a member of the party.
1407 !leaderpath) { // But leader is not following path.
1408 // Approach, or teleport.
1409 // Try to approach from offscreen.
1410 if (approach_another(leader))
1411 return;
1412 // Find a free spot.
1413 goal = Map_chunk::find_spot(
1414 leader->get_tile(), 2, this);
1415 if (goal.tx != -1) {
1416 move(goal.tx, goal.ty, goal.tz);
1417 if (rand() % 2)
1418 say(first_catchup, last_catchup);
1419 gwin->paint();
1420 return;
1421 }
1422 }
1423 // NOTE: Avoid delay when moving,
1424 // as it creates jerkiness. AND,
1425 // 0 retries if blocked.
1426 walk_to_tile(goal, speed, delay, 0);
1427 }
1428
1429 /*
1430 * Approach another actor from offscreen.
1431 *
1432 * Output: 0 if failed.
1433 */
1434
approach_another(const Actor * other,bool wait)1435 int Actor::approach_another(
1436 const Actor *other,
1437 bool wait // If true, game hangs until arrival.
1438 ) {
1439 Tile_coord dest = other->get_tile();
1440 // Look outwards for free spot.
1441 dest = Map_chunk::find_spot(dest, 8, get_shapenum(), get_framenum());
1442 if (dest.tx == -1)
1443 return 0;
1444 // Where are we now?
1445 Tile_coord src = get_tile();
1446 if (!gwin->get_win_tile_rect().has_world_point(src.tx - src.tz / 2,
1447 src.ty - src.tz / 2))
1448 // Off-screen?
1449 src = Tile_coord(-1, -1, 0);
1450 int destmap = other->get_map_num();
1451 int srcmap = get_map_num();
1452 if (destmap != -1 && srcmap != -1 && srcmap != destmap) {
1453 src = Tile_coord(-1, -1, 0);
1454 move(src, destmap);
1455 }
1456 Actor_action *action = new Path_walking_actor_action();
1457 if (!action->walk_to_tile(this, src, dest)) {
1458 delete action;
1459 return 0;
1460 }
1461 set_action(action);
1462 int speed = gwin->get_std_delay() / 2;
1463 start(speed); // Walk fairly fast.
1464 if (wait) // Only wait ~1/5 sec.
1465 Wait_for_arrival(this, dest, 2 * gwin->get_std_delay());
1466 return 1;
1467 }
1468
1469 /*
1470 * Get information about a tile that an actor is about to step onto.
1471 */
1472
get_tile_info(Actor * actor,Game_window * gwin,Map_chunk * nlist,int tx,int ty,bool & water,bool & poison)1473 void Actor::get_tile_info(
1474 Actor *actor, // May be 0 if not known.
1475 Game_window *gwin,
1476 Map_chunk *nlist, // Chunk.
1477 int tx, int ty, // Tile within chunk.
1478 bool &water, // Returns 1 if water.
1479 bool &poison // Returns 1 if poison.
1480 ) {
1481 ignore_unused_variable_warning(gwin);
1482 ShapeID flat = nlist->get_flat(tx, ty);
1483 if (flat.get_shapenum() == -1)
1484 water = poison = false;
1485 else {
1486 const Shape_info &finfo = flat.get_info();
1487 water = finfo.is_water();
1488 poison = finfo.is_poisonous();
1489 // Check for swamp/swamp boots.
1490 if (poison && actor) {
1491 if ((actor->gear_powers &
1492 (Frame_flags::swamp_safe | Frame_flags::poison_safe)) != 0)
1493 poison = false;
1494 else { // Not protected by gear?
1495 // Safe from poisoning?
1496 const Monster_info *minf =
1497 actor->get_info().get_monster_info();
1498 if (minf && minf->poison_safe())
1499 poison = false;
1500 }
1501 }
1502 }
1503 }
1504
1505 /*
1506 * Set combat opponent.
1507 */
1508
set_target(Game_object * obj,bool start_combat)1509 void Actor::set_target(
1510 Game_object *obj,
1511 bool start_combat // If true, set sched. to combat.
1512 ) {
1513 target = weak_from_obj(obj);
1514 bool im_party = is_in_party() || this == gwin->get_main_actor();
1515 if (start_combat && !im_party &&
1516 (schedule_type != Schedule::combat || !schedule))
1517 set_schedule_type(Schedule::combat);
1518 Actor *opponent = obj ? obj->as_actor() : nullptr;
1519 if (opponent)
1520 opponent->set_oppressor(get_npc_num());
1521 // Pure guess.
1522 Actor *oppr = oppressor >= 0 ? gwin->get_npc(oppressor) : nullptr;
1523 if (oppr && (oppr->get_target() != this ||
1524 oppr->get_schedule_type() != Schedule::combat))
1525 oppressor = -1;
1526 }
1527
1528 /*
1529 * Works out if an item can be readied in a spot
1530 *
1531 * Output: true if it does fit, or false if it can't
1532 */
1533
fits_in_spot(Game_object * obj,int spot)1534 bool Actor::fits_in_spot(Game_object *obj, int spot) {
1535 const Shape_info &inf = obj->get_info();
1536 int rtype = inf.get_ready_type();
1537 int alt1 = inf.get_alt_ready1();
1538 int alt2 = inf.get_alt_ready2();
1539 bool can_scabbard = (alt1 == scabbard || alt2 == scabbard);
1540 bool can_neck = (rtype == neck || alt1 == neck || alt2 == neck);
1541 if (spot == both_hands)
1542 spot = lhand;
1543 else if (spot == lrgloves)
1544 spot = lfinger;
1545 else if (spot == neck)
1546 spot = amulet;
1547 else if (spot == scabbard)
1548 spot = belt;
1549
1550 // If occupied, can't place
1551 if (spots[spot])
1552 return false;
1553 // If want to use 2h or a 2h is already equiped, can't go in right
1554 else if ((rtype == both_hands || two_handed) && spot == rhand)
1555 return false;
1556 // If want to use 2f or a 2f is already equiped, can't go in right or gloves
1557 else if ((rtype == lrgloves || two_fingered) &&
1558 (spot == rfinger || spot == gloves))
1559 return false;
1560 // If want to use scabbard or a scabbard is already equiped, can't go in others
1561 else if ((can_scabbard || use_scabbard) &&
1562 (spot == back_2h || spot == back_shield))
1563 return false;
1564 // If want to use neck or neck is already filled, can't go in cloak
1565 else if ((can_neck || use_neck) && spot == cloak)
1566 return false;
1567 // Can't use 2h in left if right occupied
1568 else if (rtype == both_hands && spot == lhand && spots[rhand])
1569 return false;
1570 // Can't use 2f in left if right occupied
1571 else if (rtype == lrgloves && spot == lfinger && spots[rfinger])
1572 return false;
1573 // Can't use scabbard in belt if back 2h or back shield occupied
1574 else if (can_scabbard && spot == belt &&
1575 (spots[back_2h] || spots[back_shield]))
1576 return false;
1577 // Can't use neck in amulet if cloak occupied
1578 else if (can_neck && spot == amulet && spots[cloak])
1579 return false;
1580 // If in left or right hand allow it
1581 else if (spot == lhand || spot == rhand)
1582 return true;
1583 // Special Checks for Belt
1584 else if (spot == belt) {
1585 if (inf.is_spell() || can_scabbard)
1586 return true;
1587 }
1588 // Special Checks for back 2h and back shield
1589 else if (spot == back_2h || spot == back_shield) {
1590 if (can_scabbard)
1591 return true;
1592 }
1593 // Special Checks for amulet and cloak
1594 else if (spot == amulet || spot == cloak) {
1595 if (can_neck)
1596 return true;
1597 }
1598
1599 // Lastly if we have gotten here, check the paperdoll table
1600 return inf.is_object_allowed(obj->get_framenum(), spot);
1601 }
1602
1603 /*
1604 * Find the spot(s) where an item would prefer to be readied
1605 *
1606 * Output: prefered slot, alternative slots
1607 */
1608
get_prefered_slots(Game_object * obj,int & prefered,int & alt1,int & alt2) const1609 void Actor::get_prefered_slots(
1610 Game_object *obj,
1611 int &prefered,
1612 int &alt1,
1613 int &alt2
1614 ) const {
1615 const Shape_info &info = obj->get_info();
1616
1617 // Defaults
1618 prefered = info.get_ready_type();
1619 alt1 = info.get_alt_ready1();
1620 alt2 = info.get_alt_ready2();
1621 if (alt1 == invalid_spot)
1622 alt1 = lhand;
1623 if (alt2 == invalid_spot)
1624 alt2 = lhand;
1625
1626 if (prefered == lhand) {
1627 if (info.is_object_allowed(obj->get_framenum(), rhand))
1628 if (!info.is_object_allowed(obj->get_framenum(), lhand))
1629 prefered = rhand;
1630 else
1631 alt1 = rhand;
1632 else
1633 alt1 = rhand;
1634 }
1635 }
1636
1637
1638 /*
1639 * Find the best spot where an item may be readied.
1640 *
1641 * Output: Index, or -1 if none found.
1642 */
1643
find_best_spot(Game_object * obj)1644 int Actor::find_best_spot(
1645 Game_object *obj
1646 ) {
1647 int prefered;
1648 int alternate1;
1649 int alternate2;
1650
1651 // Get the preferences
1652 get_prefered_slots(obj, prefered, alternate1, alternate2);
1653
1654 // Check Prefered
1655 if (fits_in_spot(obj, prefered)) return prefered;
1656 // Alternate
1657 else if (alternate1 >= 0 && fits_in_spot(obj, alternate1)) return alternate1;
1658 // Second alternate
1659 else if (alternate2 >= 0 && fits_in_spot(obj, alternate2)) return alternate2;
1660 // Belt
1661 else if (fits_in_spot(obj, belt)) return belt;
1662 // Back - required???
1663 else if (fits_in_spot(obj, backpack)) return backpack;
1664 // Back2h
1665 else if (fits_in_spot(obj, back_2h)) return back_2h;
1666 // Sheild Spot
1667 else if (fits_in_spot(obj, back_shield)) return back_shield;
1668 // Left Hand
1669 else if (fits_in_spot(obj, lhand)) return lhand;
1670 // Right Hand
1671 else if (fits_in_spot(obj, rhand)) return rhand;
1672
1673 return -1;
1674 }
1675
1676 /*
1677 * Get previous schedule type.
1678 *
1679 * Output: Prev. schedule #, or -1 if not known.
1680 */
1681
get_prev_schedule_type() const1682 int Actor::get_prev_schedule_type(
1683 ) const {
1684 return schedule ? schedule->get_prev_type() : -1;
1685 }
1686
1687 /*
1688 * Restore actor's schedule after reading. This CANNOT be called from
1689 * a constructor, since it may call virtual methods when setting up
1690 * the schedule.
1691 */
1692
restore_schedule()1693 void Actor::restore_schedule(
1694 ) {
1695 // Make sure it's in valid chunk.
1696 Map_chunk *olist = get_chunk();
1697 // Activate schedule if not in party.
1698 if (olist && !is_in_party()) {
1699 if (next_schedule != 255 &&
1700 schedule_type == Schedule::walk_to_schedule)
1701 set_schedule_and_loc(next_schedule, schedule_loc);
1702 else {
1703 old_schedule_loc = schedule_loc;
1704 restored_schedule = schedule_type;
1705 set_schedule_type(schedule_type);
1706 }
1707 }
1708 }
1709
1710 /*
1711 * Set new schedule by type.
1712 */
1713
set_schedule_type(int new_schedule_type,Schedule * newsched)1714 void Actor::set_schedule_type(
1715 int new_schedule_type,
1716 Schedule *newsched // New sched., or nullptr to create here.
1717 ) {
1718 // Don't stop path_run_usecode unless it is done.
1719 If_else_path_actor_action *act = action ? action->as_usecode_path() : nullptr;
1720 if (!act || act->is_done()) {
1721 stop(); // Stop moving
1722 set_action(nullptr); // Clear out old action.
1723 }
1724 if (schedule) // Finish up old if necessary.
1725 schedule->ending(new_schedule_type);
1726 // Save old for a moment.
1727 auto old_schedule =
1728 static_cast<Schedule::Schedule_types>(schedule_type);
1729 delete schedule; // Done with the old.
1730 schedule = newsched;
1731 if (!schedule)
1732 switch (static_cast<Schedule::Schedule_types>(new_schedule_type)) {
1733 case Schedule::combat:
1734 schedule = new Combat_schedule(this, old_schedule);
1735 break;
1736 case Schedule::horiz_pace:
1737 ready_best_weapon();
1738 schedule = Pace_schedule::create_horiz(this);
1739 break;
1740 case Schedule::vert_pace:
1741 ready_best_weapon();
1742 schedule = Pace_schedule::create_vert(this);
1743 break;
1744 case Schedule::talk:
1745 schedule = new Talk_schedule(this);
1746 break;
1747 case Schedule::dance:
1748 empty_hands();
1749 schedule = new Dance_schedule(this);
1750 break;
1751 case Schedule::farm: // Use a scythe.
1752 schedule = new Farmer_schedule(this);
1753 break;
1754 case Schedule::tend_shop:// For now.
1755 empty_hands();
1756 schedule = new Loiter_schedule(this, 3);
1757 break;
1758 case Schedule::miner: // Use a pick.
1759 schedule = new Miner_schedule(this);
1760 break;
1761 case Schedule::hound:
1762 ready_best_weapon();
1763 schedule = new Hound_schedule(this);
1764 break;
1765 case Schedule::loiter:
1766 schedule = new Loiter_schedule(this);
1767 break;
1768 case Schedule::graze: // For now.
1769 schedule = new Graze_schedule(this);
1770 break;
1771 case Schedule::wander:
1772 schedule = new Wander_schedule(this);
1773 break;
1774 case Schedule::blacksmith:
1775 schedule = new Forge_schedule(this);
1776 break;
1777 case Schedule::sleep:
1778 if (party_id < 0 && npc_num != 0)
1779 empty_hands();
1780 schedule = new Sleep_schedule(this);
1781 break;
1782 case Schedule::wait:
1783 schedule = new Wait_schedule(this);
1784 break;
1785 case Schedule::eat:
1786 empty_hands();
1787 schedule = new Eat_schedule(this);
1788 break;
1789 case Schedule::sit:
1790 empty_hands();
1791 schedule = new Sit_schedule(this);
1792 break;
1793 case Schedule::bake:
1794 schedule = new Bake_schedule(this);
1795 break;
1796 case Schedule::sew:
1797 schedule = new Sew_schedule(this);
1798 break;
1799 case Schedule::shy:
1800 empty_hands();
1801 schedule = new Shy_schedule(this);
1802 break;
1803 case Schedule::lab:
1804 schedule = new Lab_schedule(this);
1805 break;
1806 case Schedule::thief:
1807 empty_hands();
1808 schedule = new Thief_schedule(this);
1809 break;
1810 case Schedule::waiter:
1811 empty_hands();
1812 schedule = new Waiter_schedule(this);
1813 break;
1814 case Schedule::kid_games:
1815 empty_hands();
1816 schedule = new Kid_games_schedule(this);
1817 break;
1818 case Schedule::eat_at_inn:
1819 empty_hands();
1820 schedule = new Eat_at_inn_schedule(this);
1821 break;
1822 case Schedule::duel:
1823 schedule = new Duel_schedule(this);
1824 break;
1825 case Schedule::preach:
1826 ready_best_weapon(); // Fellowship staff.
1827 schedule = new Preach_schedule(this);
1828 break;
1829 case Schedule::patrol:
1830 ready_best_weapon();
1831 schedule = new Patrol_schedule(this);
1832 break;
1833 case Schedule::desk_work:
1834 empty_hands();
1835 schedule = new Desk_schedule(this);
1836 break;
1837 case Schedule::follow_avatar:
1838 schedule = new Follow_avatar_schedule(this);
1839 break;
1840 case Schedule::walk_to_schedule:
1841 cerr << "Attempted to set a \"walk to schedule\" activity for NPC " << get_npc_num() << endl;
1842 break;
1843 case Schedule::arrest_avatar:
1844 schedule = new Arrest_avatar_schedule(this);
1845 break;
1846 default:
1847 if (new_schedule_type >=
1848 Schedule::first_scripted_schedule)
1849 schedule = new Scripted_schedule(this,
1850 new_schedule_type);
1851 break;
1852 }
1853 // Set AFTER creating new schedule.
1854 schedule_type = new_schedule_type;
1855
1856 // Reset Next Schedule
1857 schedule_loc = Tile_coord(0, 0, 0);
1858 next_schedule = 255;
1859
1860 if (!gmap->is_chunk_read(get_cx(), get_cy())) {
1861 dormant = true; // Chunk hasn't been read in yet.
1862 if (schedule)
1863 schedule->im_dormant();
1864 } else if (schedule) { // Try to start it.
1865 dormant = false;
1866 schedule->now_what();
1867 }
1868 }
1869
1870 /*
1871 * Cache out an actor.
1872 * Resets the schedule, and makes the actor dormant
1873 */
cache_out()1874 void Actor::cache_out() {
1875 // This is a bit of a hack, but it works well enough
1876 if (get_schedule_type() != Schedule::walk_to_schedule)
1877 set_schedule_type(get_schedule_type());
1878 }
1879
teleport_offscreen_to_schedule(Tile_coord const & dest,int dist)1880 bool Actor::teleport_offscreen_to_schedule(Tile_coord const &dest, int dist) {
1881 int mapnum = get_map_num();
1882 if (mapnum < 0)
1883 mapnum = gmap->get_num();
1884 if ((mapnum != gmap->get_num()) ||
1885 (!gmap->is_chunk_read(get_cx(), get_cy()) &&
1886 !gmap->is_chunk_read(dest.tx / c_tiles_per_chunk,
1887 dest.ty / c_tiles_per_chunk))) {
1888 // Not on current map, or
1889 // src, dest. are off the screen
1890 // Teleport if more than dist tiles from target
1891 if (distance(dest) > dist) {
1892 move(dest.tx, dest.ty, dest.tz, mapnum);
1893 change_frame(get_dir_framenum(Actor::standing));
1894 }
1895 return true;
1896 }
1897 return false;
1898 }
1899
1900 /*
1901 * Set new schedule by type AND location.
1902 */
1903
set_schedule_and_loc(int new_schedule_type,Tile_coord const & dest,int delay)1904 void Actor::set_schedule_and_loc(int new_schedule_type, Tile_coord const &dest,
1905 int delay) { // -1 for random delay.
1906 stop(); // Stop moving.
1907 if (schedule) // End prev.
1908 schedule->ending(new_schedule_type);
1909 old_schedule_loc = dest;
1910 if (teleport_offscreen_to_schedule(dest, 12)) {
1911 set_schedule_type(new_schedule_type);
1912 return;
1913 }
1914 // Going to walk there.
1915 schedule_loc = dest;
1916 next_schedule = new_schedule_type;
1917 if (schedule_type == Schedule::walk_to_schedule)
1918 set_action(nullptr); // Force NPC to go to the right place.
1919 schedule_type = Schedule::walk_to_schedule;
1920 delete schedule;
1921 schedule = new Walk_to_schedule(this, dest, next_schedule, delay);
1922 dormant = false;
1923 schedule->now_what();
1924 }
1925
in_goblin_village(Actor const * npc)1926 static bool in_goblin_village(Actor const *npc) {
1927 // These boundaries are exact, as far as I can tell; hack-move to the
1928 // rescue.
1929 static const TileRect gobvillage(576, 1200, 256, 336);
1930 Tile_coord loc = npc->get_tile();
1931 return GAME_SI && gobvillage.has_world_point(loc.tx, loc.ty);
1932 }
1933
1934 /*
1935 * Get alignment, taking into account 'charmed' flag.
1936 */
1937
get_effective_alignment() const1938 int Actor::get_effective_alignment(
1939 ) const {
1940 bool avatar = (this == gwin->get_main_actor());
1941 if (!(flags & (1 << Obj_flags::charmed)) ||
1942 (avatar && !Combat::charmed_more_difficult)) {
1943 // Hack warning: there are some neutral goblins in the goblin village.
1944 // Here, we 'fix' their alignments to cause them to attack the avatar.
1945 // The only theory I have to explain why these neutral goblins exist is
1946 // that it *seems* that only neutral NPCs called guards in the original,
1947 // and 'call guards in the goblin' village means 'making everyone nearby
1948 // attack the avatar'.
1949 // Lets not do this for non-goblins, party members (even if goblins),
1950 // the avatar, or if in a dungeon -- the boundaries of 'goblin village'
1951 // overlap some of the surrounding dungeons, and this behavior might not
1952 // be desired there.
1953 if (avatar || party_id >= 0 || !is_goblin() || gwin->is_in_dungeon())
1954 return alignment;
1955
1956 if (in_goblin_village(this))
1957 return evil;
1958 else
1959 return alignment;
1960 } else
1961 return charmalign;
1962 }
1963
1964 /*
1965 * Set effective alignment.
1966 */
1967
set_effective_alignment(int newalign)1968 void Actor::set_effective_alignment(
1969 int newalign
1970 ) {
1971 charmalign = newalign;
1972 if (!(flags & (1 << Obj_flags::charmed)))
1973 alignment = newalign;
1974 else
1975 set_charmed_combat();
1976 }
1977
1978 /*
1979 * Render.
1980 */
1981
paint()1982 void Actor::paint(
1983 ) {
1984 int flag = GAME_BG ? Obj_flags::bg_dont_render : Obj_flags::dont_render;
1985 if (cheat.in_map_editor() || !(flags & (1L << flag))) {
1986 int xoff;
1987 int yoff;
1988 gwin->get_shape_location(this, xoff, yoff);
1989 bool invis = flags & (1L << Obj_flags::invisible);
1990 if (invis && party_id < 0 && npc_num != 0)
1991 return; // Don't render invisible NPCs not in party.
1992 else if (invis)
1993 paint_invisible(xoff, yoff);
1994 else
1995 paint_shape(xoff, yoff, true);
1996
1997 paint_weapon();
1998 if (hit) // Want a momentary red outline.
1999 ShapeID::paint_outline(xoff, yoff, HIT_PIXEL);
2000 else if (flags & ((1L << Obj_flags::protection) |
2001 (1L << Obj_flags::poisoned) | (1 << Obj_flags::cursed) |
2002 (1 << Obj_flags::charmed) | (1 << Obj_flags::paralyzed))) {
2003 if (flags & (1L << Obj_flags::charmed))
2004 ShapeID::paint_outline(xoff, yoff,
2005 CHARMED_PIXEL);
2006 else if (flags & (1L << Obj_flags::paralyzed))
2007 ShapeID::paint_outline(xoff, yoff,
2008 PARALYZE_PIXEL);
2009 else if (flags & (1L << Obj_flags::protection))
2010 ShapeID::paint_outline(xoff, yoff,
2011 PROTECT_PIXEL);
2012 else if (flags & (1L << Obj_flags::cursed))
2013 ShapeID::paint_outline(xoff, yoff, CURSED_PIXEL);
2014 else
2015 ShapeID::paint_outline(xoff, yoff, POISON_PIXEL);
2016 }
2017 }
2018 }
2019 /*
2020 * Draw the weapon in the actor's hand (if any).
2021 */
paint_weapon()2022 void Actor::paint_weapon(
2023 ) {
2024 int weapon_x;
2025 int weapon_y;
2026 int weapon_frame;
2027 if (figure_weapon_pos(weapon_x, weapon_y, weapon_frame)) {
2028 int shnum = get_effective_weapon_shape();
2029 ShapeID wsid(shnum, weapon_frame);
2030 Shape_frame *wshape = wsid.get_shape();
2031 if (!wshape) {
2032 weapon_rect.w = 0;
2033 return;
2034 }
2035 // Set dirty area rel. to NPC.
2036 weapon_rect = gwin->get_shape_rect(wshape, weapon_x, weapon_y);
2037 // Paint the weapon shape using the actor's coordinates
2038 int xoff;
2039 int yoff;
2040 gwin->get_shape_location(this, xoff, yoff);
2041 xoff += weapon_x;
2042 yoff += weapon_y;
2043
2044 if (flags & (1L << Obj_flags::invisible))
2045 wsid.paint_invisible(xoff, yoff);
2046 else
2047 wsid.paint_shape(xoff, yoff);
2048 } else
2049 weapon_rect.w = 0;
2050 }
2051
2052 /*
2053 * Figure weapon drawing info. We need this in advance to set the dirty
2054 * rectangle.
2055 *
2056 * Output: false if don't need to paint weapon.
2057 */
2058 /* Weapon frames:
2059 0 - normal item
2060 1 - in hand, actor facing north/south
2061 2 - attacking (pointing north)
2062 3 - attacking (pointing east)
2063 4 - attacking (pointing south)
2064 */
2065
figure_weapon_pos(int & weapon_x,int & weapon_y,int & weapon_frame)2066 bool Actor::figure_weapon_pos(
2067 int &weapon_x, int &weapon_y, // Pos. rel. to NPC.
2068 int &weapon_frame
2069 ) {
2070 unsigned char actor_x;
2071 unsigned char actor_y;
2072 unsigned char wx;
2073 unsigned char wy;
2074 if ((spots[lhand] == nullptr) && (get_casting_mode() != Actor::show_casting_frames))
2075 return false;
2076 // Get offsets for actor shape
2077 int myframe = get_framenum();
2078 get_info().get_weapon_offset(myframe & 0x1f, actor_x,
2079 actor_y);
2080 // Get weapon frames for actor frame:
2081 switch (myframe & 0x1f) {
2082 case 4:
2083 case 7:
2084 case 22:
2085 case 25:
2086 weapon_frame = 4;
2087 break;
2088 case 5:
2089 case 8:
2090 case 21:
2091 case 24:
2092 weapon_frame = 3;
2093 break;
2094 case 6:
2095 case 9:
2096 case 20:
2097 case 23:
2098 weapon_frame = 2;
2099 break;
2100 //The next cases (before the default) are here to make use of all
2101 //the frames of the "casting frames" shape (shape 859):
2102 case 14:
2103 case 30:
2104 weapon_frame = 5;
2105 break;
2106 case 15:
2107 weapon_frame = 6;
2108 break;
2109 case 31:
2110 weapon_frame = 7;
2111 break;
2112
2113 default:
2114 weapon_frame = 1;
2115 }
2116 weapon_frame |= (myframe & 32);
2117
2118 // Get offsets for weapon shape
2119 int shnum = get_effective_weapon_shape();
2120 const Shape_info &info = ShapeID::get_info(shnum);
2121 info.get_weapon_offset(weapon_frame & 0xf, wx, wy);
2122
2123 // actor_x will be 255 if (for example) the actor is lying down
2124 // wx will be 255 if the actor is not holding a proper weapon
2125 if (actor_x != 255 && wx != 255) {
2126 // Store offsets rel. to NPC.
2127 weapon_x = wx - actor_x;
2128 weapon_y = wy - actor_y;
2129 // Need to swap offsets if actor's shape is reflected
2130 if (myframe & 32)
2131 swap(weapon_x, weapon_y);
2132 // Combat frames are already done.
2133 return true;
2134 } else
2135 return false;
2136 }
2137
2138 /*
2139 * Run usecode when double-clicked.
2140 */
activate(int event)2141 void Actor::activate(
2142 int event
2143 ) {
2144 if (edit())
2145 return;
2146
2147 bool show_party_inv = gumpman->showing_gumps(true) ||
2148 gwin->in_combat();
2149 auto sched =
2150 static_cast<Schedule::Schedule_types>(get_schedule_type());
2151 if (party_id >= 0 && !can_act_charmed() && // if in party, charmed, and charmed more difficult
2152 !cheat.in_pickpocket() && event == 1) // and not pickpocket, return if double click
2153 return;
2154 if (!npc_num || // Avatar
2155 (show_party_inv && party_id >= 0) || // Party
2156 // Pickpocket cheat && double click
2157 (cheat.in_pickpocket() && event == 1))
2158 show_inventory();
2159 // Asleep (but not awakened)?
2160 else if ((sched == Schedule::sleep &&
2161 (get_framenum() & 0xf) == Actor::sleep_frame) ||
2162 get_flag(Obj_flags::asleep))
2163 return;
2164 else if (sched == Schedule::combat && party_id < 0)
2165 return; // Too busy fighting.
2166 // Usecode
2167 // Failed copy-protection?
2168 else if (gwin->failed_copy_protection())
2169 ucmachine->call_usecode(FailCopyProtectionUsecode, this,
2170 static_cast<Usecode_machine::Usecode_events>(event));
2171 else if (usecode == -1)
2172 ucmachine->call_usecode(get_usecode(), this,
2173 static_cast<Usecode_machine::Usecode_events>(event));
2174 else if (party_id >= 0 || !gwin->is_time_stopped())
2175 ucmachine->call_usecode(get_usecode(), this,
2176 static_cast<Usecode_machine::Usecode_events>(event));
2177
2178 }
2179
2180 /*
2181 * Edit in ExultStudio.
2182 *
2183 * Output: True if map-editing & ES is present.
2184 */
2185
edit()2186 bool Actor::edit(
2187 ) {
2188 #ifdef USE_EXULTSTUDIO
2189 if (client_socket >= 0 && // Talking to ExultStudio?
2190 cheat.in_map_editor()) {
2191 editing.reset();
2192 Tile_coord t = get_tile();
2193 int num_schedules; // Set up schedule-change list.
2194 Schedule_change *changes;
2195 get_schedules(changes, num_schedules);
2196 Serial_schedule schedules[8];
2197 for (int i = 0; i < num_schedules; i++) {
2198 schedules[i].time = changes[i].get_time();
2199 schedules[i].type = changes[i].get_type();
2200 Tile_coord p = changes[i].get_pos();
2201 schedules[i].tx = p.tx;
2202 schedules[i].ty = p.ty;
2203 schedules[i].tz = p.tz;
2204 }
2205 if (Npc_actor_out(client_socket, this, t.tx, t.ty, t.tz,
2206 get_shapenum(), get_framenum(), get_face_shapenum(),
2207 name, npc_num, ident, usecode, usecode_name, properties,
2208 attack_mode, alignment, flags, flags2, type_flags,
2209 num_schedules, schedules) != -1) {
2210 cout << "Sent npc data to ExultStudio" << endl;
2211 editing = shared_from_this();
2212 } else
2213 cout << "Error sending npc data to ExultStudio" << endl;
2214 return true;
2215 }
2216 #endif
2217 return false;
2218 }
2219
2220 /*
2221 * Message to update from ExultStudio.
2222 */
2223
update_from_studio(unsigned char * data,int datalen)2224 void Actor::update_from_studio(
2225 unsigned char *data,
2226 int datalen
2227 ) {
2228 #ifdef USE_EXULTSTUDIO
2229 Actor *npc;
2230 int tx;
2231 int ty;
2232 int tz;
2233 int shape;
2234 int frame;
2235 int face;
2236 std::string name;
2237 short npc_num;
2238 short ident;
2239 int usecode;
2240 std::string usecodefun;
2241 int properties[12];
2242 short attack_mode;
2243 short alignment;
2244 unsigned long oflags; // Object flags.
2245 unsigned long xflags; // Extra object flags.
2246 unsigned long type_flags; // Movement flags.
2247 short num_schedules;
2248 Serial_schedule schedules[8];
2249 if (!Npc_actor_in(data, datalen, npc, tx, ty, tz, shape, frame,
2250 face, name, npc_num, ident, usecode, usecodefun,
2251 properties, attack_mode, alignment,
2252 oflags, xflags, type_flags, num_schedules, schedules)) {
2253 cout << "Error decoding npc" << endl;
2254 return;
2255 }
2256 if (npc && npc != editing.get()) {
2257 cout << "Npc from ExultStudio is not being edited" << endl;
2258 return;
2259 }
2260 // Keeps NPC alive until end of function
2261 Game_object_shared keep = std::move(editing);
2262 if (!npc) { // Create a new one?
2263 int x;
2264 int y;
2265 if (!Get_click(x, y, Mouse::hand, nullptr)) {
2266 if (client_socket >= 0)
2267 Exult_server::Send_data(client_socket, Exult_server::cancel);
2268 return;
2269 }
2270 // Create. Gets initialized below.
2271 Actor_shared act = std::make_shared<Npc_actor>(name, shape, npc_num, usecode);
2272 npc = act.get();
2273 keep = std::move(act);
2274 npc->usecode_name = usecodefun;
2275 if (!usecodefun.empty())
2276 npc->usecode = ucmachine->find_function(usecodefun.c_str(), true);
2277 npc->usecode_assigned = npc_num >= 256 && npc->usecode != -1 &&
2278
2279 npc->usecode != 0x400 + npc_num;
2280
2281 npc->set_invalid(); // Set to invalid position.
2282 int lift; // Try to drop at increasing hts.
2283 for (lift = 0; lift < 12; lift++)
2284 if (gwin->drop_at_lift(npc, x, y, lift))
2285 break;
2286 if (lift == 12) {
2287 if (client_socket >= 0)
2288 Exult_server::Send_data(client_socket, Exult_server::cancel);
2289 delete npc;
2290 return;
2291 }
2292 gwin->add_npc(npc, npc_num);
2293 if (client_socket >= 0)
2294 Exult_server::Send_data(client_socket, Exult_server::user_responded);
2295 } else { // Old.
2296 npc->add_dirty();
2297 npc->usecode_name = usecodefun;
2298 if (!usecodefun.empty())
2299 npc->usecode = ucmachine->find_function(usecodefun.c_str(), true);
2300 else
2301 npc->usecode = usecode;
2302 npc->usecode_assigned = npc_num >= 256 && npc->usecode != -1 &&
2303
2304 npc->usecode != 0x400 + npc_num;
2305
2306 npc->set_npc_name(name.c_str());
2307 }
2308 // Ensure proper initialization of frame #:
2309 npc->set_shape(shape, frame);
2310 npc->add_dirty();
2311 npc->face_num = face;
2312 npc->set_ident(ident);
2313 int i;
2314 for (i = 0; i < 12; i++)
2315 npc->set_property(i, properties[i]);
2316 npc->set_attack_mode(static_cast<Actor::Attack_mode>(attack_mode));
2317 npc->set_alignment(alignment);
2318 if (!(npc->flags & (1 << Obj_flags::charmed)))
2319 npc->charmalign = alignment;
2320 npc->flags = oflags;
2321 npc->flags2 = xflags;
2322 npc->type_flags = type_flags;
2323 npc->set_actor_shape();
2324 Schedule_change *scheds = num_schedules ?
2325 new Schedule_change[num_schedules] : nullptr;
2326 for (i = 0; i < num_schedules; i++)
2327 scheds[i].set(schedules[i].tx, schedules[i].ty,
2328 schedules[i].tz,
2329 schedules[i].type, schedules[i].time);
2330 npc->set_schedules(scheds, num_schedules);
2331 // Force Avatar and party members to be good
2332 if (npc_num == 0 || npc->get_flag(Obj_flags::in_party))
2333 npc->set_alignment(good);
2334 cout << "Npc updated" << endl;
2335 #else
2336 ignore_unused_variable_warning(data, datalen);
2337 #endif
2338 }
2339
2340
show_inventory()2341 void Actor::show_inventory() {
2342 Gump_manager *gump_man = gumpman;
2343
2344 int shapenum = inventory_shapenum();
2345 if (shapenum >= 0)
2346 gump_man->add_gump(this, shapenum, true);
2347 }
2348
inventory_shapenum()2349 int Actor::inventory_shapenum() {
2350 // We are serpent if we can use serpent isle paperdolls
2351 bool serpent = (sman->can_use_paperdolls() && sman->are_paperdolls_enabled());
2352
2353 if (!serpent) {
2354 // Can't display paperdolls (or they are disabled)
2355 // Use BG gumps
2356 int gump = get_info().get_gump_shape();
2357 if (gump < 0)
2358 gump = ShapeID::get_info(get_sexed_coloured_shape()).get_gump_shape();
2359 if (gump < 0)
2360 gump = ShapeID::get_info(get_shape_real()).get_gump_shape();
2361 if (gump < 0) {
2362 int shape = get_type_flag(Actor::tf_sex) ?
2363 Shapeinfo_lookup::GetFemaleAvShape() :
2364 Shapeinfo_lookup::GetMaleAvShape();
2365 gump = ShapeID::get_info(shape).get_gump_shape();
2366 }
2367 if (gump < 0)
2368 // No gump at ALL; should never happen...
2369 return 65; // Default to male (Pickpocket Cheat)
2370
2371 return gump;
2372 } else /* if (serpent) */
2373 return 123; // Show paperdolls
2374 }
2375
2376
2377 /*
2378 * Drop another onto this.
2379 *
2380 * Output: false to reject, true to accept.
2381 */
2382
drop(Game_object * obj)2383 bool Actor::drop(
2384 Game_object *obj // MAY be deleted (if combined).
2385 ) {
2386 if (is_in_party()) { // In party?
2387 bool res = add(obj, false, true);// We'll take it, and combine.
2388 int ind = find_readied(obj);
2389 if (ind >= 0)
2390 call_readied_usecode(ind, obj, Usecode_machine::readied);
2391 return res;
2392 } else
2393 return false;
2394 }
2395
2396 /*
2397 * Get name.
2398 */
2399
get_name() const2400 string Actor::get_name(
2401 ) const {
2402 return !get_flag(Obj_flags::met) ? Game_object::get_name() : get_npc_name();
2403 }
2404
2405 /*
2406 * Get npc name.
2407 */
2408
get_npc_name() const2409 string Actor::get_npc_name(
2410 ) const {
2411 return name.empty() ? Game_object::get_name() : name;
2412 }
2413
2414 /*
2415 * Set npc name.
2416 */
2417
set_npc_name(const char * n)2418 void Actor::set_npc_name(const char *n) {
2419 name = n;
2420 }
2421
2422 /*
2423 * Set property.
2424 */
set_property(int prop,int val)2425 void Actor::set_property(
2426 int prop,
2427 int val
2428 ) {
2429 if (prop == health && ((party_id != -1) || (npc_num == 0)) &&
2430 cheat.in_god_mode() && val < properties[prop])
2431 return;
2432 switch (static_cast<Item_properties>(prop)) {
2433 case exp: {
2434 // Experience? Check for new level.
2435 int old_level = get_level();
2436 properties[static_cast<int>(exp)] = val;
2437 int delta = get_level() - old_level;
2438 if (delta > 0)
2439 properties[static_cast<int>(training)] += 3 * delta;
2440 break;
2441 }
2442 case food_level:
2443 if (val > 31) // Never seems to get above this.
2444 val = 31;
2445 else if (val < 0)
2446 val = 0;
2447 properties[prop] = val;
2448 break;
2449 case combat: // limited to 30.
2450 properties[prop] = val > 30 ? 30 : val;
2451 break;
2452 case magic: {
2453 int old_val = properties[prop];
2454 properties[prop] = val > 30 ? 30 : val; // limited to 30.
2455 // check if magic changes to and from 0
2456 if(is_in_party() && old_val != val && (old_val == 0 || val == 0))
2457 Face_stats::UpdateButtons();
2458 break;
2459 } case training: // Don't let this go negative.
2460 properties[prop] = val < 0 ? 0 : val;
2461 break;
2462 case sex_flag:
2463 // Doesn't seem to be settable in original BG except by hex-editing
2464 // the save game, but there is no problem in allowing it in Exult.
2465 if (val != 0)
2466 set_type_flag(tf_sex);
2467 else
2468 clear_type_flag(tf_sex);
2469 break;
2470 default:
2471 if (prop >= 0 && prop < missile_weapon)
2472 properties[prop] = val;
2473 break;
2474 }
2475 if (gumpman->showing_gumps())
2476 gwin->set_all_dirty();
2477 }
2478
2479 /*
2480 * A class whose whole purpose is to stop casting mode.
2481 */
2482 class Clear_casting : public Time_sensitive {
2483 Game_object_weak actor;
2484 public:
Clear_casting(Actor * a)2485 Clear_casting(Actor *a) : actor(weak_from_obj(a))
2486 { }
2487 void handle_event(unsigned long curtime, uintptr udata) override;
2488 };
2489
handle_event(unsigned long curtime,uintptr)2490 void Clear_casting::handle_event(unsigned long curtime, uintptr) {
2491 ignore_unused_variable_warning(curtime);
2492 Actor_shared a = std::static_pointer_cast<Actor>(actor.lock());
2493 if (a) {
2494 a->add_dirty();
2495 a->hide_casting_frames();
2496 a->add_dirty();
2497 }
2498 delete this;
2499 }
2500
end_casting_mode(int delay)2501 void Actor::end_casting_mode(int delay) {
2502 auto *c = new Clear_casting(this);
2503 gwin->get_tqueue()->add(Game::get_ticks() + 2 * delay, c, this);
2504 }
2505
2506 /*
2507 * A class whose whole purpose is to clear the 'hit' flag.
2508 */
2509 class Clear_hit : public Time_sensitive {
2510 Game_object_weak actor;
2511 public:
Clear_hit(Actor * a)2512 Clear_hit(Actor *a) : actor(weak_from_obj(a))
2513 { }
2514 void handle_event(unsigned long curtime, uintptr udata) override;
2515 };
2516
handle_event(unsigned long curtime,uintptr)2517 void Clear_hit::handle_event(unsigned long curtime, uintptr) {
2518 ignore_unused_variable_warning(curtime);
2519 Actor_shared a = std::static_pointer_cast<Actor>(actor.lock());
2520 if (a) {
2521 a->hit = false;
2522 a->add_dirty();
2523 }
2524 delete this;
2525 }
2526
can_act()2527 bool Actor::can_act() {
2528 return !(get_flag(Obj_flags::paralyzed) || get_flag(Obj_flags::asleep)
2529 || is_dead() || is_knocked_out());
2530 }
2531
can_act_charmed()2532 bool Actor::can_act_charmed() {
2533 return !(Combat::charmed_more_difficult && get_effective_alignment() != good);
2534 }
2535
2536 /*
2537 * Have charmed party members attack if charmed_more_difficult and party member is hostile
2538 */
2539
set_charmed_combat()2540 void Actor::set_charmed_combat() {
2541 if (Combat::charmed_more_difficult &&
2542 (is_in_party() || this == gwin->get_main_actor()) &&
2543 get_effective_alignment() != good) {
2544 set_schedule_type(Schedule::combat);
2545 if (get_attack_mode() == flee)
2546 set_attack_mode(nearest);
2547 }
2548 }
2549
fight_back(Game_object * attacker)2550 void Actor::fight_back(
2551 Game_object *attacker
2552 ) {
2553 // ++++ TODO: I think that nearby NPCs will help NPCs (or party members,
2554 // as the case may be) of the same alignment when attacked by other NPCs,
2555 // not just when the avatar & party attack. Although this is tricky to
2556 // test (except, maybe, by exploiting the agressive U7 & SI duel schedule.
2557 Actor *npc = attacker ? attacker->as_actor() : nullptr;
2558 // No attacker, or friendly fire, should not cause a fight.
2559 if (!npc || get_effective_alignment() == npc->get_effective_alignment())
2560 return;
2561 if (is_in_party() && (gwin->in_combat() || !gwin->main_actor_can_act())) {
2562 if (!gwin->in_combat())
2563 gwin->toggle_combat();
2564 Actor *party[9]; // Get entire party, including Avatar.
2565 int cnt = gwin->get_party(party, 1);
2566 for (int i = 0; i < cnt; i++) {
2567 int sched = party[i]->get_schedule_type();
2568 if (sched != Schedule::combat && sched != Schedule::wait
2569 && sched != Schedule::loiter)
2570 party[i]->set_schedule_type(Schedule::combat);
2571 }
2572 }
2573 if (!target.lock() && !is_in_party())
2574 set_target(npc, npc->get_schedule_type() != Schedule::duel);
2575 // Being a bully?
2576 if (npc->is_in_party() && !is_in_party() && is_sentient()) {
2577 Actor *witness = this;
2578 Actor *closest = nullptr;
2579 int align = get_effective_alignment();
2580 // Attack avatar if the NPC is not disabled...
2581 if (can_act() ||
2582 // ... or if there is a sympathetic witness or local guard...
2583 (witness = gwin->find_witness(closest, align)) != nullptr ||
2584 // ... or if there is someone sympathetic nearby who heard it.
2585 ((witness = closest) != nullptr && rand() % 10 == 0)) {
2586 static long lastcall = 0L; // Last time yelled.
2587 long curtime = SDL_GetTicks();
2588 long delta = curtime - lastcall;
2589 // Call if 10 secs. has passed or by the luck of the die.
2590 if ((delta > 10000) || (rand() % 20 == 0)) {
2591 int numguards = 0;
2592 int gshape = Game_window::get_guard_shape();
2593 // No guards in dungeons or if gshape < 0.
2594 if (!gwin->is_in_dungeon() && gshape >= 0 &&
2595 // And only neutral NPCs and guards call more guards.
2596 (witness->get_shapenum() == gshape ||
2597 align == Actor::neutral))
2598 numguards = 1 + rand() % 2;
2599
2600 eman->remove_text_effect(this);
2601 if (numguards > 0) {
2602 // Call guards.
2603 if (witness->is_goblin())
2604 witness->say(first_goblin_call_police, last_goblin_call_police);
2605 else if (witness->can_speak())
2606 witness->say(first_call_police, last_call_police);
2607 } else {
2608 // Cry for help.
2609 if (witness->is_goblin())
2610 witness->say(goblin_need_help);
2611 else if (witness->can_speak())
2612 witness->say(first_need_help, last_need_help);
2613 }
2614 // To reduce the guard pile-up.
2615 lastcall = curtime;
2616 gwin->attack_avatar(numguards, align);
2617 }
2618 }
2619 }
2620 }
2621
2622 /*
2623 * This method should be called to cause damage from traps, attacks.
2624 *
2625 * Output: Hits taken. If exp is nonzero, experience value if defeated.
2626 */
2627
apply_damage(Game_object * attacker,int str,int wpoints,int type,int bias,int * exp)2628 int Actor::apply_damage(
2629 Game_object *attacker, // Attacker, or null.
2630 int str, // Attack strength.
2631 int wpoints, // Weapon bonus.
2632 int type, // Damage type.
2633 int bias, // Different combat difficulty.
2634 int *exp
2635 ) {
2636 if (exp)
2637 *exp = 0;
2638 int damage = bias;
2639 str /= 3;
2640
2641 // In the original, wpoints == 127 does fixed 127 damage.
2642 // Allowing for >= 127 in Exult, as the original seems to
2643 // use only a byte for damage/health.
2644 if (wpoints >= 127)
2645 damage = 127;
2646 else {
2647 // Lightning damage ignores strength.
2648 if (type != Weapon_data::lightning_damage && str > 0)
2649 damage += (1 + rand() % str);
2650 if (wpoints > 0)
2651 damage += (1 + rand() % wpoints);
2652 }
2653
2654 int armor = -bias;
2655 const Monster_info *minf = get_info().get_monster_info();
2656 // Monster armor protects only in UI_apply_damage.
2657 if (minf)
2658 armor += minf->get_armor();
2659
2660 // Armor defense and immunities only affect UI_apply_damage.
2661 const int num_spots = array_size(spots);
2662 for (int i = 0; i < num_spots; i++) {
2663 Game_object *obj = spots[i];
2664 if (obj) {
2665 const Shape_info &info = obj->get_info();
2666 armor += info.get_armor();
2667 if ((info.get_armor_immunity() & (1 << type)) != 0) {
2668 // Armor gives immunity.
2669 // Metal clang.
2670 Object_sfx::Play(this, Audio::game_sfx(5));
2671 // Attack back anyway.
2672 fight_back(attacker);
2673 return 0; // No damage == no powers.
2674 }
2675 }
2676 }
2677
2678 // Some attacks ignore armor (unless the armor gives immunity).
2679 if (wpoints == 127 || type == Weapon_data::lightning_damage ||
2680 type == Weapon_data::ethereal_damage ||
2681 type == Weapon_data::sonic_damage ||
2682 armor < 0) // Armor should never help the attacker.
2683 armor = 0;
2684
2685 if (armor)
2686 damage -= (1 + rand() % armor);
2687
2688 // Paralyzed/defenseless foes may take damage even if
2689 // the armor protects them. This code is guesswork,
2690 // but it matches statistical tests.
2691 if (damage <= 0 && !can_act()) {
2692 if (str > 0)
2693 damage = 1 + rand() % str;
2694 else
2695 damage = 0;
2696 }
2697
2698 if (damage <= 0) {
2699 // No damage caused.
2700 Object_sfx::Play(this, Audio::game_sfx(5));
2701
2702 // Flash red outline.
2703 hit = true;
2704 add_dirty();
2705 auto *c = new Clear_hit(this);
2706 gwin->get_tqueue()->add(Game::get_ticks() + 200, c, this);
2707 // Attack back.
2708 fight_back(attacker);
2709 return 0; // No damage == no powers (usually).
2710 }
2711
2712 return reduce_health(damage, type, attacker, exp);
2713 }
2714
2715 /*
2716 * This method should be called to decrement health directly.
2717 *
2718 * Output: Hits taken. If exp is nonzero, experience value if defeated.
2719 */
2720
reduce_health(int delta,int type,Game_object * attacker,int * exp)2721 int Actor::reduce_health(
2722 int delta, // # points to lose.
2723 int type, // Type of damage
2724 Game_object *attacker, // Attacker, or null.
2725 int *exp
2726 ) {
2727 if (exp)
2728 *exp = 0;
2729 // Cheater, cheater.
2730 if (is_dead() || (cheat.in_god_mode() && ((party_id != -1) || (npc_num == 0))))
2731 return 0;
2732
2733 const Monster_info *minf = get_info().get_monster_info_safe();
2734 Actor *npc = attacker ? attacker->as_actor() : nullptr;
2735
2736 // Monster immunities DO affect UI_reduce_health, unlike
2737 // armor immunities.
2738 if (is_dead() || minf->cant_die() ||
2739 (minf->get_immune() & (1 << type)) != 0) {
2740 // Monster data gives immunity to damage.
2741 // Attack back.
2742 fight_back(attacker);
2743 return 0;
2744 }
2745
2746 // Monsters vulnerable to a damage type take 2x the damage.
2747 // The originals seem to limit damage to 127 points; we
2748 // set a lower bound on final health below.
2749 if ((minf->get_vulnerable() & (1 << type)) != 0)
2750 delta *= 2;
2751
2752 int oldhp = properties[static_cast<int>(health)];
2753 int maxhp = properties[static_cast<int>(strength)];
2754 int val = oldhp - delta;
2755 if (val < -50) {
2756 // Limit how low it goes for safety.
2757 val = -50;
2758 delta = oldhp + 50;
2759 }
2760 // Don't set health yet!! (see tournament below for why)
2761 // The following thresholds are exact.
2762 if (this == gwin->get_main_actor() &&
2763 // Flash red if Avatar badly hurt.
2764 (delta >= maxhp / 3 || oldhp < maxhp / 4 ||
2765 // Or if lightning damage.
2766 type == Weapon_data::lightning_damage))
2767 gwin->get_pal()->flash_red();
2768 else {
2769 hit = true; // Flash red outline.
2770 add_dirty();
2771 auto *c = new Clear_hit(this);
2772 gwin->get_tqueue()->add(Game::get_ticks() + 200, c, this);
2773 }
2774 if (oldhp >= maxhp / 2 && val < maxhp / 2 && rand() % 2 != 0) {
2775 // A little oomph.
2776 if (is_goblin()) // Goblin?
2777 say(goblin_ouch);
2778 else if (can_speak())
2779 say(first_ouch, last_ouch);
2780 }
2781 Game_object_vector vec; // Create blood.
2782 const int blood = 912; // TODO: de-hard-code this.
2783 // Bleed only for normal damage.
2784 if (type == Weapon_data::normal_damage && !minf->cant_bleed()
2785 // Trying something new. Seems to match originals better, but
2786 // it is hard to judge accurately (although 10 or more hits
2787 // *always* cause bleeding).
2788 && rand() % 10 < delta
2789 && find_nearby(vec, blood, 1, 0) < 2) {
2790 // Create blood where actor stands.
2791 Game_object_shared bobj = gmap->create_ireg_object(blood, 0);
2792 bobj->set_flag(Obj_flags::is_temporary);
2793 bobj->move(get_tile());
2794 }
2795 if (val <= 0 && oldhp > 0 && get_flag(Obj_flags::tournament)) {
2796 // HPs are never reduced before tournament usecode
2797 // (this can be checked on weapon usecode, tournament
2798 // usecode or even UI_reduce_health directly followed
2799 // by UI_get_npc_prop).
2800 // THIS is why we haven't reduced health yet.
2801 // This makes foes with tournament flag EXTREMELLY
2802 // tough, particularly if they have high hit points
2803 // to begin with!
2804 // No more pushover banes!
2805 if (npc) // Just to be sure.
2806 set_oppressor(npc->get_npc_num());
2807 ucmachine->call_usecode(get_usecode(), this,
2808 Usecode_machine::died);
2809 return 0; // If needed, NPC usecode does the killing (possibly
2810 // by calling this function again).
2811 }
2812
2813 // We do slimes here; they DO split through reduce_health intrinsic.
2814 // They also do *not* split if hit by damage they are vulnerable to.
2815 if (minf->splits() && val > 0 &&
2816 (minf->get_vulnerable() & (1 << type)) == 0 && rand() % 2 == 0)
2817 clone();
2818
2819 // Doing this here simplifies the tournament code, above.
2820 properties[static_cast<int>(health)] = val;
2821 bool defeated = is_dying() || (val <= 0 && oldhp > 0);
2822
2823 if (defeated && exp) {
2824 // Verified: No experience for killing sleeping people.
2825 if (!get_flag(Obj_flags::asleep)) {
2826 int expval = 0;
2827 // Except for 2 details mentioned below, this formula
2828 // is an exact match to what the originals give.
2829 // We also have to do this *here*, before we kill the
2830 // NPC, because the equipment is deleted (spells) or
2831 // transferred to the dead body it leaves.
2832 int combval = properties[static_cast<int>(combat)];
2833 expval = properties[static_cast<int>(strength)] + combval +
2834 (properties[static_cast<int>(dexterity)] + 1) / 3 +
2835 properties[static_cast<int>(intelligence)] / 5;
2836 const Monster_info *minf = get_info().get_monster_info();
2837 int immune = minf ? minf->get_immune() : 0;
2838 int vuln = minf ? minf->get_vulnerable() : 0;
2839 if (minf)
2840 expval += minf->get_base_xp_value();
2841
2842 if (!objects.is_empty()) {
2843 Game_object_vector vec; // Get list of all possessions.
2844 vec.reserve(50);
2845 get_objects(vec, c_any_shapenum, c_any_qual, c_any_framenum);
2846 for (auto *obj : vec) {
2847 // This matches the original, but maybe
2848 // we should iterate through all items.
2849 // After all, a death bolt in the backpack
2850 // can still be dangerous...
2851 if (obj->get_owner() != this)
2852 continue;
2853 const Shape_info &inf = obj->get_info();
2854 expval += inf.get_armor();
2855 // Strictly speaking, the original does not give
2856 // XP for armor immunities; but I guess this is
2857 // mostly because very few armors give immunities
2858 // (ethereal ring, cadellite helm) and no monsters
2859 // use them anyway.
2860 // I decided to have them give a (non-cumulative)
2861 // increase in experience.
2862 immune |= inf.get_armor_immunity();
2863 const Weapon_info *winf = inf.get_weapon_info();
2864 if (!winf)
2865 continue;
2866 expval += winf->get_base_xp_value();
2867 // This was tough to figure out, but figured out it was;
2868 // it is a perfect match to what the original does.
2869 switch (winf->get_uses()) {
2870 case Weapon_info::melee: {
2871 int range = winf->get_range();
2872 expval += range > 5 ? 2 : (range > 3 ? 1 : 0);
2873 break;
2874 }
2875 case Weapon_info::poor_thrown:
2876 expval += combval / 5;
2877 break;
2878 case Weapon_info::good_thrown:
2879 expval += combval / 3;
2880 break;
2881 case Weapon_info::ranged:
2882 expval += winf->get_range() / 2;
2883 break;
2884 }
2885 }
2886 }
2887 // Originals don't do this, but hey... they *should*.
2888 // Also, being vulnerable to something you are immune
2889 // should not matter because immunities are checked first;
2890 // the originals don't do this check, but neither do they
2891 // have a monster vulnerable and immune to the same thing.
2892 vuln &= ~immune;
2893 expval += bitcount(immune);
2894 expval -= bitcount(vuln);
2895 // And the final touch (verified).
2896 expval /= 2;
2897 *exp = expval;
2898 }
2899 }
2900
2901 // query this here because die() will reset is_in_party.
2902 bool in_party = is_in_party();
2903
2904 if (is_dying())
2905 die(attacker);
2906 else if (val <= 0 && !get_flag(Obj_flags::asleep)) {
2907 Combat_schedule::stop_attacking_npc(this);
2908 set_flag(Obj_flags::asleep);
2909 } else if (npc && !target.lock() && !in_party) {
2910 set_target(npc, npc->get_schedule_type() != Schedule::duel);
2911 set_oppressor(npc->get_npc_num());
2912 }
2913
2914 // Dead people caused attacks on the avatar back in Actor::die, so don't do
2915 // it again here.
2916 if (!is_dead())
2917 fight_back(attacker);
2918 return delta;
2919 }
2920
2921 /*
2922 * Causes the actor to fall to the ground and take damage.
2923 */
2924
fall_down()2925 void Actor::fall_down() {
2926 if (!get_type_flag(tf_fly))
2927 return;
2928 int savetz = get_lift();
2929 Tile_coord start = get_tile();
2930 if (!Map_chunk::is_blocked(start, 1, MOVE_WALK, 100) &&
2931 start.tz < savetz) {
2932 move(start.tx, start.ty, start.tz);
2933 reduce_health(1 + rand() % 5, Weapon_data::normal_damage);
2934 }
2935 }
2936
2937 /*
2938 * Causes the actor to lie down to sleep (or die).
2939 */
2940
lay_down(bool die)2941 void Actor::lay_down(bool die) {
2942 if (!die && get_flag(Obj_flags::asleep))
2943 return;
2944 // Fall to the ground.
2945 fall_down();
2946 bool frost_serp = GAME_SI && get_shapenum() == 832;
2947 // Don't do it if already in sleeping frame.
2948 if (frost_serp && (get_framenum() & 0xf) == Actor::sit_frame)
2949 return; // SI Frost serpents are weird.
2950 else if ((get_framenum() & 0xf) == Actor::sleep_frame)
2951 return;
2952
2953 set_action(nullptr);
2954 auto *scr = new Usecode_script(this);
2955 (*scr) << Ucscript::finish << (Ucscript::npc_frame + Actor::standing);
2956 if (GAME_SI && get_shapenum() == 832) { // SI Frost serpent
2957 // Frames are in reversed order. This results in a
2958 // strangeanimation in the original, which we fix here.
2959 (*scr) << (Ucscript::npc_frame + Actor::sleep_frame)
2960 << (Ucscript::npc_frame + Actor::kneel_frame)
2961 << (Ucscript::npc_frame + Actor::bow_frame)
2962 << (Ucscript::npc_frame + Actor::sit_frame);
2963 } else if (get_info().has_strange_movement()) {
2964 // BG Sea serpent; slimes are done elsewhere.
2965 (*scr) << (Ucscript::npc_frame + Actor::bow_frame)
2966 << (Ucscript::npc_frame + Actor::kneel_frame)
2967 << (Ucscript::npc_frame + Actor::sleep_frame);
2968 } else {
2969 (*scr) << (Ucscript::npc_frame + Actor::kneel_frame)
2970 << Ucscript::sfx << Audio::game_sfx(86);
2971 if (!die)
2972 (*scr) << (Ucscript::npc_frame + Actor::sleep_frame);
2973 }
2974 if (die) // If dying, remove.
2975 (*scr) << Ucscript::remove;
2976 scr->start();
2977 }
2978
2979 /*
2980 * Get a property.
2981 */
2982
get_property(int prop) const2983 int Actor::get_property(int prop) const {
2984 if (prop == Actor::sex_flag)
2985 // Correct in BG and SI, but the flag is never normally set
2986 // for anyone but avatar in BG.
2987 return get_type_flag(Actor::tf_sex);
2988 else if (prop == Actor::missile_weapon) {
2989 // Seems to give the same results as in the originals.
2990 Game_object *weapon = get_readied(lhand);
2991 const Weapon_info *winf = weapon ? weapon->get_info().get_weapon_info() : nullptr;
2992 if (!winf)
2993 return 0;
2994 return winf->get_uses() >= 2;
2995 }
2996 return (prop >= 0 && prop < Actor::sex_flag) ? properties[prop] : 0;
2997 }
2998
2999 /*
3000 * Get a property, modified by flags.
3001 */
3002
get_effective_prop(int prop) const3003 int Actor::get_effective_prop(
3004 int prop // Property #.
3005 ) const {
3006 int val = get_property(prop);
3007 switch (prop) {
3008 case Actor::dexterity:
3009 case Actor::combat:
3010 if (get_flag(Obj_flags::paralyzed) || get_flag(Obj_flags::asleep) ||
3011 is_knocked_out())
3012 return prop == Actor::dexterity ? 0 : 1;
3013 // FALL THROUGH
3014 case Actor::intelligence:
3015 if (is_dead())
3016 return prop == Actor::dexterity ? 0 : 1;
3017 else if (get_flag(Obj_flags::charmed) || get_flag(Obj_flags::asleep))
3018 val--;
3019 // FALL THROUGH
3020 case Actor::strength:
3021 if (get_flag(Obj_flags::might))
3022 val += (val < 15 ? val : 15); // Add up to 15.
3023 if (get_flag(Obj_flags::cursed))
3024 val -= 3; // Matches originals.
3025 break;
3026 }
3027 return val;
3028 }
3029
3030 /*
3031 * For mods and new games: Set generic attribute keyed by a name.
3032 */
3033
set_attribute(const char * nm,int val)3034 void Actor::set_attribute(
3035 const char *nm,
3036 int val
3037 ) {
3038 if (!atts)
3039 atts = new Actor_attributes;
3040 atts->set(nm, val);
3041 }
3042
3043 /*
3044 * Get generic attribute. Returns 0 if not set.
3045 */
3046
get_attribute(const char * nm) const3047 int Actor::get_attribute(
3048 const char *nm
3049 ) const {
3050 return atts ? atts->get(nm) : 0;
3051 }
3052
3053 /*
3054 * Get them all.
3055 */
3056
get_attributes(Atts_vector & attlist) const3057 void Actor::get_attributes(
3058 Atts_vector &attlist
3059 ) const {
3060 attlist.resize(0);
3061 if (atts)
3062 atts->get_all(attlist);
3063 }
3064
3065 /*
3066 * Read in attributes (from savegame file).
3067 */
3068
read_attributes(const unsigned char * buf,int len)3069 void Actor::read_attributes(
3070 const unsigned char *buf, // Attribute/value pairs.
3071 int len
3072 ) {
3073 const unsigned char *ptr = buf;
3074 const unsigned char *endbuf = buf + len;
3075 while (ptr < endbuf) {
3076 const char *att = reinterpret_cast<const char *>(ptr);
3077 ptr += strlen(att) + 1;
3078 assert(ptr + 2 <= endbuf);
3079 int val = Read2(ptr);
3080 set_attribute(att, val);
3081 }
3082 }
3083
3084 /*
3085 * Force actor to sleep.
3086 */
3087
force_sleep()3088 void Actor::force_sleep() {
3089 flags |= (static_cast<uint32>(1) << Obj_flags::asleep);
3090 need_timers()->start_sleep();
3091 set_action(nullptr); // Stop what you're doing.
3092 lay_down(false); // Lie down.
3093 }
3094
3095 // Want to avoid full include.
3096 extern bool Bg_dont_wake(Game_window *gwin, Actor *npc);
3097
3098 /*
3099 * Set flag.
3100 */
3101
set_flag(int flag)3102 void Actor::set_flag(
3103 int flag
3104 ) {
3105 // cout << "Set flag for NPC " << get_npc_num() << " = " << flag << endl;
3106 const Monster_info *minf = get_info().get_monster_info_safe();
3107 Actor *avatar = gwin->get_main_actor();
3108 switch (flag) {
3109 case Obj_flags::asleep:
3110 if (minf->sleep_safe() || minf->power_safe() ||
3111 (gear_powers & (Frame_flags::power_safe | Frame_flags::sleep_safe)))
3112 return; // Don't do anything.
3113 // Avoid waking Penumbra.
3114 if (schedule_type == Schedule::sleep && Bg_dont_wake(gwin, this))
3115 break;
3116 // Set timer to wake in a few secs.
3117 if (this != avatar && avatar->get_target() == this)
3118 avatar->set_target(nullptr);
3119 need_timers()->start_sleep();
3120 set_action(nullptr); // Stop what you're doing.
3121 lay_down(false); // Lie down.
3122 break;
3123 case Obj_flags::poisoned:
3124 if (minf->poison_safe() || (gear_powers & Frame_flags::poison_safe))
3125 return; // Don't do anything.
3126 need_timers()->start_poison();
3127 break;
3128 case Obj_flags::protection:
3129 need_timers()->start_protection();
3130 break;
3131 case Obj_flags::might:
3132 need_timers()->start_might();
3133 break;
3134 case Obj_flags::cursed:
3135 if (minf->curse_safe() || minf->power_safe() ||
3136 (gear_powers & (Frame_flags::power_safe | Frame_flags::curse_safe)))
3137 return; // Don't do anything.
3138 need_timers()->start_curse();
3139 break;
3140 case Obj_flags::charmed:
3141 if (minf->charm_safe() || minf->power_safe() ||
3142 (gear_powers & (Frame_flags::power_safe | Frame_flags::charm_safe)))
3143 return; // Don't do anything.
3144 need_timers()->start_charm();
3145 // Actual alignment shift must be done elsewhere.
3146 Combat_schedule::stop_attacking_npc(this);
3147 set_target(nullptr); // Need new opponent if in combat.
3148 break;
3149 case Obj_flags::paralyzed:
3150 if (minf->paralysis_safe() || minf->power_safe() ||
3151 (gear_powers & (Frame_flags::power_safe | Frame_flags::paralysis_safe)))
3152 return; // Don't do anything.
3153 fall_down();
3154 need_timers()->start_paralyze();
3155 break;
3156 case Obj_flags::invisible:
3157 flags |= (static_cast<uint32>(1) << flag);
3158 need_timers()->start_invisibility();
3159 Combat_schedule::stop_attacking_invisible(this);
3160 gclock->set_palette();
3161 break;
3162 case Obj_flags::dont_move:
3163 case Obj_flags::bg_dont_move:
3164 stop(); // Added 7/6/03.
3165 set_action(nullptr); // Force actor to stop current action.
3166 break;
3167 case Obj_flags::naked: {
3168 // set_polymorph needs this, and there are no problems
3169 // in setting this twice.
3170 flags2 |= (static_cast<uint32>(1) << (flag - 32));
3171 if (get_npc_num() != 0) // Ignore for all but avatar.
3172 break;
3173 int sn;
3174 int female = get_type_flag(tf_sex) ? 1 : 0;
3175 Skin_data *skin = Shapeinfo_lookup::GetSkinInfoSafe(this);
3176
3177 if (!skin || // Should never happen, but hey...
3178 (!sman->have_si_shapes() &&
3179 Shapeinfo_lookup::IsSkinImported(skin->naked_shape)))
3180 sn = Shapeinfo_lookup::GetBaseAvInfo(female != 0)->shape_num;
3181 else
3182 sn = skin->naked_shape;
3183 set_polymorph(sn);
3184 break;
3185 }
3186 }
3187
3188 // Doing it here to prevent problems with immunities.
3189 if (flag >= 0 && flag < 32)
3190 flags |= (static_cast<uint32>(1) << flag);
3191 else if (flag >= 32 && flag < 64)
3192 flags2 |= (static_cast<uint32>(1) << (flag - 32));
3193 // Update stats if open.
3194 if (gumpman->showing_gumps())
3195 gwin->set_all_dirty();
3196 set_actor_shape();
3197 }
3198
set_type_flag(int flag)3199 void Actor::set_type_flag(
3200 int flag
3201 ) {
3202 if (flag >= 0 && flag < 16)
3203 type_flags |= (static_cast<uint32>(1) << flag);
3204
3205 set_actor_shape();
3206 }
3207
3208 /*
3209 * Clear flag.
3210 */
3211
clear_flag(int flag)3212 void Actor::clear_flag(
3213 int flag
3214 ) {
3215 // cout << "Clear flag for NPC " << get_npc_num() << " = " << flag << endl;
3216 if (flag >= 0 && flag < 32)
3217 flags &= ~(static_cast<uint32>(1) << flag);
3218 else if (flag >= 32 && flag < 64)
3219 flags2 &= ~(static_cast<uint32>(1) << (flag - 32));
3220 if (flag == Obj_flags::invisible) // Restore normal palette.
3221 gclock->set_palette();
3222 else if (flag == Obj_flags::asleep) {
3223 if (schedule_type == Schedule::sleep)
3224 set_schedule_type(Schedule::stand);
3225 else if ((get_framenum() & 0xf) == Actor::sleep_frame) {
3226 // Find spot to stand.
3227 Tile_coord pos = get_tile();
3228 pos.tz -= pos.tz % 5; // Want floor level.
3229 pos = Map_chunk::find_spot(pos, 6, get_shapenum(),
3230 Actor::standing, 0);
3231 if (pos.tx >= 0)
3232 move(pos);
3233 change_frame(Actor::standing);
3234 }
3235 Usecode_script::terminate(this);
3236 } else if (flag == Obj_flags::charmed) {
3237 reset_effective_alignment();
3238 Combat_schedule::stop_attacking_npc(this);
3239 set_target(nullptr); // Need new opponent.
3240 } else if (flag == Obj_flags::bg_dont_move || flag == Obj_flags::dont_move)
3241 // Start again after a little while
3242 start_std();
3243 else if (flag == Obj_flags::polymorph && get_flag(Obj_flags::naked))
3244 clear_flag(Obj_flags::naked);
3245 else if (flag == Obj_flags::naked && get_flag(Obj_flags::polymorph))
3246 clear_flag(Obj_flags::polymorph);
3247
3248 set_actor_shape();
3249 }
3250
clear_type_flag(int flag)3251 void Actor::clear_type_flag(
3252 int flag
3253 ) {
3254 if (flag >= 0 && flag < 16)
3255 type_flags &= ~(static_cast<uint32>(1) << flag);
3256
3257 set_actor_shape();
3258 }
3259
3260 /*
3261 * Get flags.
3262 */
3263
get_type_flag(int flag) const3264 bool Actor::get_type_flag(
3265 int flag
3266 ) const {
3267 return (flag >= 0 && flag < 16) ? (type_flags & (static_cast<uint32>(1) << flag))
3268 != 0 : false;
3269 }
3270 /*
3271 * SetFlags
3272 */
3273
set_type_flags(unsigned short tflags)3274 void Actor::set_type_flags(
3275 unsigned short tflags
3276 ) {
3277 type_flags = tflags;
3278 set_actor_shape();
3279 }
3280
3281 /*
3282 * Set temperature.
3283 */
3284
set_temperature(int v)3285 void Actor::set_temperature(
3286 int v // Should be 0-63.
3287 ) {
3288 if (v < 0)
3289 v = 0;
3290 else if (v > 63)
3291 v = 63;
3292 temperature = v;
3293 }
3294
3295 /*
3296 * Figure warmth based on what's worn. In trying to mimic the original
3297 * SI, the base value is -75.
3298 */
3299
figure_warmth()3300 int Actor::figure_warmth(
3301 ) {
3302 int warmth = -75; // Base value.
3303
3304 static Ready_type_Exult locs[] = {head, cloak, feet, torso, gloves, legs};
3305 for (auto loc : locs) {
3306 Game_object *worn = spots[static_cast<int>(loc)];
3307 if (worn)
3308 warmth += worn->get_info().get_object_warmth(worn->get_framenum());
3309 }
3310 return warmth;
3311 }
3312
3313 /*
3314 * Get maximum weight in stones that can be held.
3315 *
3316 * Output: Max. allowed, or 0 if no limit (i.e., not carried by an NPC).
3317 */
3318
get_max_weight() const3319 int Actor::get_max_weight(
3320 ) const {
3321 return 2 * get_effective_prop(static_cast<int>(Actor::strength));
3322 }
3323
3324 /*
3325 * Call usecode function for an object that's readied/unreadied.
3326 */
3327
call_readied_usecode(int index,Game_object * obj,int eventid)3328 void Actor::call_readied_usecode(
3329 int index,
3330 Game_object *obj,
3331 int eventid
3332 ) {
3333 ignore_unused_variable_warning(index);
3334 // Limit to certain types.
3335 if (!obj->get_info().has_usecode_events())
3336 return;
3337
3338 const Shape_info &info = obj->get_info();
3339 if (info.get_shape_class() != Shape_info::container)
3340 ucmachine->call_usecode(obj->get_usecode(),
3341 obj, static_cast<Usecode_machine::Usecode_events>(eventid));
3342 }
3343
3344 /*
3345 * Returns true if NPC is in a non-no_halt usecode script or if
3346 * dont_move flag is set.
3347 */
in_usecode_control() const3348 bool Actor::in_usecode_control() const {
3349 if (get_flag(Obj_flags::dont_render) || get_flag(Obj_flags::dont_move))
3350 return true;
3351 Usecode_script *scr = nullptr;
3352 while ((scr = Usecode_script::find_active(this, scr)) != nullptr)
3353 // no_halt scripts seem not to prevent movement.
3354 if (!scr->is_no_halt())
3355 return true;
3356 return false;
3357 }
3358
3359 /*
3360 * Attack preset target/tile using preset weapon shape.
3361 *
3362 * Output: True if attack was realized and hit target (or is
3363 * a missile flying towards target), false otherwise
3364 */
usecode_attack()3365 bool Actor::usecode_attack() {
3366 Game_object_shared tobj = target_object.lock();
3367 return Combat_schedule::attack_target(
3368 this, tobj.get(), target_tile, attack_weapon);
3369 }
3370
3371 /*
3372 * Should be called after actors and usecode are initialized.
3373 */
3374
init_readied()3375 void Actor::init_readied(
3376 ) {
3377 for (size_t i = 0; i < array_size(spots); i++)
3378 if (spots[i])
3379 call_readied_usecode(i, spots[i],
3380 Usecode_machine::readied);
3381 }
3382
3383 /*
3384 * Remove an object.
3385 */
3386
remove(Game_object * obj)3387 void Actor::remove(
3388 Game_object *obj
3389 ) {
3390 int index = Actor::find_readied(obj); // Remove from spot.
3391 // Note: gwin->drop() also does this,
3392 // but it needs to be done before
3393 // removal too.
3394 // Definitely DO NOT call if dead!
3395 if (!is_dead()
3396 && !ucmachine->in_usecode_for(obj, Usecode_machine::unreadied)
3397 && !(GAME_SI && ucmachine->in_usecode_for(gwin->get_main_actor(), Usecode_machine::died))) // Fix for #1887 - Hang when leaving SI dream world
3398 call_readied_usecode(index, obj, Usecode_machine::unreadied);
3399 Container_game_object::remove(obj);
3400 if (index >= 0) {
3401 spots[index] = nullptr;
3402 if (index == rhand || index == lhand)
3403 two_handed = false;
3404 if (index == rfinger || index == lfinger)
3405 two_fingered = false;
3406 if (index == belt || index == back_2h || index == back_shield)
3407 use_scabbard = false;
3408 if (index == amulet || index == cloak)
3409 use_neck = false;
3410 if (index == lhand && schedule)
3411 schedule->set_weapon(true);
3412 // Recheck armor immunities and frame powers.
3413 refigure_gear();
3414 }
3415 }
3416
3417 /*
3418 * Add an object.
3419 *
3420 * Output: 1, meaning object is completely contained in this,
3421 * 0 if not enough space.
3422 */
3423
add(Game_object * obj,bool dont_check,bool combine,bool noset)3424 bool Actor::add(
3425 Game_object *obj,
3426 bool dont_check, // 1 to skip volume check (AND also
3427 // to skip usecode call).
3428 bool combine, // True to try to combine obj. MAY
3429 // cause obj to be deleted.
3430 bool noset // True to prevent actors from setting sched. weapon.
3431 ) {
3432
3433 int index = find_best_spot(obj);// Where should it go?
3434
3435 if (index < 0) { // No free spot? Look for a bag.
3436 if (spots[backpack] && spots[backpack]->add(obj, false, combine))
3437 return true;
3438 if (spots[belt] && spots[belt]->add(obj, false, combine))
3439 return true;
3440 if (spots[lhand] && spots[lhand]->add(obj, false, combine))
3441 return true;
3442 if (spots[rhand] && spots[rhand]->add(obj, false, combine))
3443 return true;
3444 if (!dont_check)
3445 return false;
3446
3447 // try again without checking volume/weight
3448 if (spots[backpack] && spots[backpack]->add(obj, true, combine))
3449 return true;
3450 if (spots[belt] && spots[belt]->add(obj, true, combine))
3451 return true;
3452 if (spots[lhand] && spots[lhand]->add(obj, true, combine))
3453 return true;
3454 if (spots[rhand] && spots[rhand]->add(obj, true, combine))
3455 return true;
3456
3457 if (party_id != -1 || npc_num == 0) {
3458 CERR("Warning: adding object (" << obj << ", sh. " << obj->get_shapenum() << ", " << obj->get_name() << ") to actor container (npc " << npc_num << ")");
3459 }
3460 return Container_game_object::add(obj, dont_check, combine);
3461 }
3462 // Add to ourself (DON'T combine).
3463 if (!Container_game_object::add(obj, true))
3464 return false;
3465
3466 if (index == both_hands) { // Two-handed?
3467 two_handed = true;
3468 index = lhand;
3469 } else if (index == lrgloves) { // BG Gloves?
3470 two_fingered = true;
3471 index = lfinger;
3472 } else if (index == scabbard) { // Use scabbard?
3473 use_scabbard = true;
3474 index = belt;
3475 } else if (index == neck) { // Use neck?
3476 use_neck = true;
3477 index = amulet;
3478 }
3479
3480 spots[index] = obj; // Store in correct spot.
3481 if (index == lhand && schedule && !noset)
3482 schedule->set_weapon(); // Tell combat-schedule about it.
3483 obj->set_shape_pos(0, 0); // Clear coords. (set by gump).
3484 if (!dont_check)
3485 call_readied_usecode(index, obj, Usecode_machine::readied);
3486 // (Readied usecode now in drop().)
3487
3488 const Shape_info &info = obj->get_info();
3489
3490 if (info.is_light_source() &&
3491 (index == lhand || index == rhand))
3492 add_light_source(info.get_object_light(obj->get_framenum()));
3493
3494 // Refigure granted immunities.
3495 gear_immunities |= info.get_armor_immunity();
3496 gear_powers |= info.get_object_flags(obj->get_framenum(),
3497 info.has_quality() ? obj->get_quality() : -1);
3498 return true;
3499 }
3500
3501 /*
3502 * Add to given spot.
3503 *
3504 * Output: true if successful, else false.
3505 */
3506
add_readied(Game_object * obj,int index,bool dont_check,bool force_pos,bool noset)3507 bool Actor::add_readied(
3508 Game_object *obj,
3509 int index, // Spot #.
3510 bool dont_check,
3511 bool force_pos,
3512 bool noset
3513 ) {
3514 // Is Out of range?
3515 if (index < 0 || index >= static_cast<int>(array_size(spots)))
3516 return false;
3517
3518 // Already something there? Try to drop into it.
3519 // +++++Danger: drop() can potentially delete the object.
3520 // if (spots[index]) return spots[index]->drop(obj);
3521 if (spots[index]) return spots[index]->add(obj, dont_check);
3522
3523 int prefered;
3524 int alt1;
3525 int alt2;
3526
3527 // Get the preferences
3528 get_prefered_slots(obj, prefered, alt1, alt2);
3529
3530 // Check Prefered
3531 if (!fits_in_spot(obj, index) && !force_pos) return false;
3532
3533 // No room, or too heavy.
3534 if (!Container_game_object::add(obj, true)) return false;
3535
3536 // Set the spot to this object
3537 spots[index] = obj;
3538
3539 // Clear coords. (set by gump).
3540 obj->set_shape_pos(0, 0);
3541
3542 // Must be a two-handed weapon.
3543 if (prefered == both_hands && index == lhand)
3544 two_handed = true;
3545 // Must be gloves
3546 else if (prefered == lrgloves && index == lfinger)
3547 two_fingered = true;
3548 // Must be in scabbard
3549 else if ((alt1 == scabbard || alt2 == scabbard) && index == belt)
3550 use_scabbard = true;
3551 // Must use neck entirely
3552 else if (prefered == neck && index == amulet)
3553 use_neck = true;
3554
3555 if (!dont_check)
3556 call_readied_usecode(index, obj, Usecode_machine::readied);
3557
3558 const Shape_info &info = obj->get_info();
3559
3560 if (info.is_light_source() &&
3561 (index == lhand || index == rhand))
3562 add_light_source(info.get_object_light(obj->get_framenum()));
3563
3564 // Refigure granted immunities.
3565 gear_immunities |= info.get_armor_immunity();
3566 gear_powers |= info.get_object_flags(obj->get_framenum(),
3567 info.has_quality() ? obj->get_quality() : -1);
3568
3569 if (index == lhand && schedule && !noset)
3570 schedule->set_weapon(); // Tell combat-schedule about it.
3571 return true;
3572 }
3573
3574 /*
3575 * Find index of spot where an object is readied.
3576 *
3577 * Output: Index, or -1 if not found.
3578 */
3579
find_readied(Game_object * obj)3580 int Actor::find_readied(
3581 Game_object *obj
3582 ) {
3583 for (size_t i = 0; i < array_size(spots); i++)
3584 if (spots[i] == obj)
3585 return i;
3586 return -1;
3587 }
3588
3589 /*
3590 * Get object readied at given slot index.
3591 *
3592 * Output: Object pointer, or null if invalid slot ID given.
3593 */
3594
get_readied(int index) const3595 Game_object *Actor::get_readied(int index) const {
3596 return index >= 0 &&
3597 index < static_cast<int>(array_size(spots)) ?
3598 spots[index] : nullptr;
3599 }
3600
3601 /*
3602 * Change shape of a member.
3603 */
3604
change_member_shape(Game_object * obj,int newshape)3605 void Actor::change_member_shape(
3606 Game_object *obj,
3607 int newshape
3608 ) {
3609 Container_game_object::change_member_shape(obj, newshape);
3610 refigure_gear();
3611 }
3612
3613 /*
3614 * Step aside to a free tile, or try to swap places.
3615 *
3616 * Output: true if successful, else false.
3617 */
3618
move_aside(Actor * for_actor,int dir)3619 bool Actor::move_aside(
3620 Actor *for_actor, // Moving aside for this one.
3621 int dir // Direction to avoid (0-7).
3622 ) {
3623 // ++++ FIXME: Ugly workaround: preventing stepping aside in combat
3624 // also prevents some cases of double-moving aside that result in
3625 // walking through walls or doors.
3626 // Also, don't move if the other actor is moving, as this may break
3627 // pathfinding.
3628 if (get_schedule_type() == Schedule::combat || get_frame_time())
3629 return false;
3630 // Do not move aside if sitting, bending over, kneeling or sleeping.
3631 int frnum = get_framenum() & 0xf;
3632 if (frnum >= sit_frame && frnum <= sleep_frame)
3633 return false;
3634
3635 Tile_coord cur = get_tile();
3636 Tile_coord to(-1, -1, -1);
3637 int d = 8;
3638 // Try orthogonal directions first.
3639 to = cur.get_neighbor((dir + 2) % 8);
3640 if (!is_blocked(to, nullptr, get_type_flags()))
3641 d = (dir + 2) % 8;
3642 else {
3643 to = cur.get_neighbor((dir + 6) % 8);
3644 if (!is_blocked(to, nullptr, get_type_flags()))
3645 d = (dir + 6) % 8;
3646 else {
3647 for (int i = 0; i < 4; i++) { // Try diagonals now.
3648 to = cur.get_neighbor(2 * i + 1);
3649 if (!is_blocked(to, nullptr, get_type_flags())) {
3650 d = 2 * i + 1;
3651 break;
3652 }
3653 }
3654 }
3655 }
3656
3657 int stepdir = d; // This is the direction.
3658 if (d == 8 || to.tx < 0) // Failed? Try to swap places.
3659 return swap_positions(for_actor);
3660 // Step, and face direction.
3661 step(to, get_dir_framenum(stepdir, static_cast<int>(Actor::standing)));
3662 Tile_coord newpos = get_tile();
3663 return newpos.tx == to.tx && newpos.ty == to.ty;
3664 }
3665
3666 /*
3667 * Get frame if rotated 1, 2, or 3 quadrants clockwise.
3668 */
3669
get_rotated_frame(int quads) const3670 int Actor::get_rotated_frame(
3671 int quads // 1=90, 2=180, 3=270.
3672 ) const {
3673 int curframe = get_framenum();
3674 // Bit 4=rotate180, 5=rotate-90.
3675 int curdir = (4 + 2 * ((curframe >> 4) & 1) - ((curframe >> 5) & 1)) % 4;
3676 int newdir = (curdir + quads) % 4;
3677 // Convert to 8-value dir & get frame.
3678 return get_dir_framenum(2 * newdir, curframe);
3679 }
3680
3681 /*
3682 * Get total value of armor being worn.
3683 */
3684
get_armor_points() const3685 int Actor::get_armor_points(
3686 ) const {
3687 int points = 0;
3688 static Ready_type_Exult aspots[] = {head, amulet, torso, cloak, belt,
3689 lhand, rhand, lfinger, rfinger, legs, feet, earrings,
3690 gloves
3691 };
3692 for (auto aspot : aspots) {
3693 Game_object *armor = spots[static_cast<int>(aspot)];
3694 if (armor)
3695 points += armor->get_info().get_armor();
3696 }
3697 return points;
3698 }
3699
3700 /*
3701 * Get whether or not the actor is immune or vulnerable to a form of damage.
3702 *
3703 * Input is damage_type for a weapon.
3704 *
3705 * Returns 1 if the actor is immune, -1 if vulnerable or 0 otherwise.
3706 */
3707
is_immune(int type) const3708 int Actor::is_immune(
3709 int type
3710 ) const {
3711 if (gear_immunities & (1 << type))
3712 return 1;
3713 const Monster_info *minf = get_info().get_monster_info();
3714 if (minf && minf->get_immune() & (1 << type))
3715 return 1;
3716 if (minf && minf->get_vulnerable() & (1 << type))
3717 return -1;
3718 else
3719 return 0;
3720 }
3721
is_goblin() const3722 bool Actor::is_goblin() const {
3723 return get_info().is_goblin();
3724 }
3725
can_see_invisible() const3726 bool Actor::can_see_invisible() const {
3727 const Monster_info *minf = get_info().get_monster_info_safe();
3728 return (minf->get_flags() & (1 << Monster_info::see_invisible)) != 0;
3729 }
3730
can_speak() const3731 bool Actor::can_speak() const {
3732 const Monster_info *minf = get_info().get_monster_info();
3733 // TODO: Check for SI monks that don't speak (vows of silence, deafness).
3734 return !minf || !minf->cant_yell();
3735 }
3736
is_sentient() const3737 bool Actor::is_sentient() const {
3738 // Try based on average monster intelligence (prevents some random animals
3739 // from opening doors or assisting in battle).
3740 const Monster_info *minf = get_info().get_monster_info_safe();
3741 return minf->get_intelligence() >= 6;
3742 }
3743
3744 /*
3745 * Get weapon value.
3746 */
3747
get_weapon(int & points,int & shape,Game_object * & obj) const3748 const Weapon_info *Actor::get_weapon(
3749 int &points,
3750 int &shape,
3751 Game_object *&obj // ->weapon itself returned, or nullptr.
3752 ) const {
3753 points = 1; // Bare hands = 1.
3754 shape = -1; // Bare hands.
3755 const Weapon_info *winf = nullptr;
3756 Game_object *weapon = spots[static_cast<int>(lhand)];
3757 obj = weapon;
3758 if (weapon) {
3759 if ((winf = weapon->get_info().get_weapon_info()) != nullptr) {
3760 points = winf->get_damage();
3761 shape = weapon->get_shapenum();
3762 return winf;
3763 }
3764 }
3765 return winf;
3766 }
3767
3768 /*
3769 * Roll a 25-sided die to determine a win-lose outcome, adding a
3770 * bias for the attacker and for the defender.
3771 */
3772
roll_to_win(int attacker,int defender)3773 bool Actor::roll_to_win(
3774 int attacker, // Points added.
3775 int defender // Points subtracted.
3776 ) {
3777 const int sides = 30;
3778 int roll = rand() % sides;
3779 if (roll == 0) // Always lose.
3780 return false;
3781 else if (roll == sides - 1) // High? Always win.
3782 return true;
3783 else
3784 return roll + attacker - defender >= sides / 2 - 1;
3785 }
3786
3787 /*
3788 * Get effective property, or default value.
3789 */
3790
Get_effective_prop(Actor * npc,Actor::Item_properties prop,int defval=0)3791 inline int Get_effective_prop(
3792 Actor *npc, // ...or nullptr.
3793 Actor::Item_properties prop, // Property #.
3794 int defval = 0 // Default val if npc==0.
3795 ) {
3796 return npc ? npc->get_effective_prop(prop) : defval;
3797 }
3798
3799 /*
3800 * Figure hit points lost from an attack, and subtract from total.
3801 *
3802 * Output: Hits taken or < 0 for explosion.
3803 */
3804
figure_hit_points(Game_object * attacker,int weapon_shape,int ammo_shape,bool explosion)3805 int Actor::figure_hit_points(
3806 Game_object *attacker,
3807 int weapon_shape, // < 0 for readied weapon.
3808 int ammo_shape, // < 0 for no ammo shape.
3809 bool explosion // If this is an explosion attacking.
3810 ) {
3811 bool were_party = party_id != -1 || npc_num == 0;
3812 // godmode effects:
3813 if (were_party && cheat.in_god_mode())
3814 return 0;
3815 Actor *npc = attacker ? attacker->as_actor() : nullptr;
3816 bool theyre_party = npc &&
3817 (npc->party_id != -1 || npc->npc_num == 0);
3818 bool instant_death = (cheat.in_god_mode() && theyre_party);
3819 // Modify using combat difficulty.
3820 int bias = were_party ? Combat::difficulty :
3821 (theyre_party ? -Combat::difficulty : 0);
3822
3823 const Weapon_info *winf;
3824 const Ammo_info *ainf;
3825
3826 int wpoints = 0;
3827 if (weapon_shape >= 0)
3828 winf = ShapeID::get_info(weapon_shape).get_weapon_info();
3829 else
3830 winf = nullptr;
3831 if (ammo_shape >= 0)
3832 ainf = ShapeID::get_info(ammo_shape).get_ammo_info();
3833 else
3834 ainf = nullptr;
3835 if (!winf && weapon_shape < 0)
3836 winf = npc ? npc->get_weapon(wpoints) : nullptr;
3837
3838 int usefun = -1;
3839 int powers = 0;
3840 int type = Weapon_data::normal_damage;
3841 bool explodes = false;
3842
3843 if (winf) {
3844 wpoints = winf->get_damage();
3845 usefun = winf->get_usecode();
3846 type = winf->get_damage_type();
3847 powers = winf->get_powers();
3848 explodes = winf->explodes();
3849 } else
3850 wpoints = 1; // Give at least one, but only if there's no weapon
3851 if (ainf) {
3852 wpoints += ainf->get_damage();
3853 // Replace damage type.
3854 if (ainf->get_damage_type() != Weapon_data::normal_damage)
3855 type = ainf->get_damage_type();
3856 powers |= ainf->get_powers();
3857 explodes = explodes || ainf->explodes();
3858 }
3859
3860 if (explodes && !explosion) { // Explosions shouldn't explode again.
3861 // Time to explode.
3862 Tile_coord offset(0, 0, get_info().get_3d_height() / 2);
3863 eman->add_effect(std::make_unique<Explosion_effect>(get_tile() + offset,
3864 nullptr, 0, weapon_shape, ammo_shape, attacker));
3865 // The explosion will handle the damage.
3866 return -1;
3867 }
3868
3869 int expval = 0;
3870 int hits = 0;
3871 bool nodamage = (powers & (Weapon_data::no_damage)) != 0;
3872 if (wpoints && instant_death)
3873 wpoints = 127;
3874 if (wpoints && !nodamage)
3875 // This may kill the NPC; this comes before powers because no
3876 // damage means no powers -- except for the no_damage flag.
3877 hits = apply_damage(attacker, Get_effective_prop(npc, Actor::strength, 0),
3878 wpoints, type, bias, &expval);
3879 // Apply weapon powers if needed.
3880 // wpoints == 0 ==> some spells that don't hurt (but need to apply powers).
3881 if (powers && (hits || !wpoints || nodamage)) {
3882 // Protection prevents powers.
3883 if (!get_flag(Obj_flags::protection)) {
3884 int attint = Get_effective_prop(npc, Actor::intelligence, 16);
3885 int defstr = Get_effective_prop(this, Actor::strength);
3886 int defint = Get_effective_prop(this, Actor::intelligence);
3887
3888 // These rolls are bourne from statistical analisys and are,
3889 // as far as I can tell, how the game works.
3890 if ((powers & Weapon_data::poison) && roll_to_win(attint, defstr))
3891 set_flag(Obj_flags::poisoned);
3892 if ((powers & Weapon_data::curse) && roll_to_win(attint, defint))
3893 set_flag(Obj_flags::cursed);
3894 if ((powers & Weapon_data::charm) && roll_to_win(attint, defint)) {
3895 set_flag(Obj_flags::charmed);
3896 if (npc)
3897 charmalign = npc->get_effective_alignment();
3898 else
3899 charmalign = chaotic; // Verified.
3900 set_charmed_combat();
3901 }
3902 if ((powers & Weapon_data::sleep) && roll_to_win(attint, defint))
3903 set_flag(Obj_flags::asleep);
3904 if ((powers & Weapon_data::paralyze) && roll_to_win(attint, defstr))
3905 set_flag(Obj_flags::paralyzed);
3906 if (powers & Weapon_data::magebane) {
3907 // Magebane weapons (magebane sword, death scythe).
3908 // Take away all mana.
3909 set_property(static_cast<int>(Actor::mana), 0);
3910 int num_spells = 0;
3911 Game_object_vector vec;
3912 Game_object_vector spells;
3913 vec.reserve(50);
3914 spells.reserve(50);
3915 get_objects(vec, c_any_shapenum, c_any_qual, c_any_framenum);
3916 // Gather all spells...
3917 for (auto *obj : vec)
3918 if (obj->get_info().is_spell()) // Seems to be right.
3919 spells.push_back(obj);
3920 vec.clear();
3921 // ... and take them all away.
3922 while (!spells.empty()) {
3923 ++num_spells;
3924 Game_object *obj = spells.back();
3925 spells.pop_back();
3926 obj->remove_this();
3927 }
3928 if (num_spells) {
3929 // Display magebane struck string and set
3930 // no_spell_casting flag. This is only done
3931 // to prevent monsters from teleporting or
3932 // doing other such things.
3933 set_flag(Obj_flags::no_spell_casting);
3934 if(can_speak()) {
3935 eman->remove_text_effect(this);
3936 say(first_magebane_struck, last_magebane_struck);
3937 }
3938 // Tell schedule we need a new weapon.
3939 if (schedule && spots[lhand] == nullptr)
3940 schedule->set_weapon();
3941 }
3942 }
3943 }
3944 if (nodamage && ammo_shape == 568) {
3945 // This is *only* done for SI sleep arrows, and all other
3946 // powers have had their effect by now (as can be verified
3947 // by using the called usecode function).
3948 if (npc) // Just to be sure.
3949 set_oppressor(npc->get_npc_num());
3950 // Allowing for BG too, as it doesn't have a function 0x7e1.
3951 ucmachine->call_usecode(SleepArrowsUsecode, this,
3952 Usecode_machine::weapon);
3953 }
3954 }
3955
3956 if (expval > 0 && npc) // Give experience.
3957 npc->set_property(static_cast<int>(exp),
3958 npc->get_property(static_cast<int>(exp)) + expval);
3959
3960 // Weapon usecode comes last of all.
3961 if (usefun > 0) {
3962 if (npc) // Just to be sure.
3963 set_oppressor(npc->get_npc_num());
3964 ucmachine->call_usecode(usefun, this,
3965 Usecode_machine::weapon);
3966 }
3967 return hits;
3968 }
3969
3970 /*
3971 * Trying to hit NPC with an attack.
3972 *
3973 * Output: true if attack hit, false otherwise.
3974 */
3975
try_to_hit(Game_object * attacker,int attval)3976 bool Actor::try_to_hit(
3977 Game_object *attacker,
3978 int attval
3979 ) {
3980 int defval = get_effective_prop(static_cast<int>(combat)) +
3981 (get_flag(Obj_flags::protection) ? 3 : 0);
3982 if (combat_trace) {
3983 string name = "<trap>";
3984 if (attacker)
3985 name = attacker->get_name();
3986 int prob = 30 - (15 + defval - attval) + 1;
3987 if (prob >= 30)
3988 prob = 29; // 1 always misses.
3989 else if (prob <= 1)
3990 prob = 1; // 30 always hits.
3991 prob *= 100;
3992 cout << name << " is attacking " << get_name()
3993 << " with hit probability " << static_cast<float>(prob) / 30 << "%" << endl;
3994 }
3995
3996 return Actor::roll_to_win(attval, defval);
3997 }
3998
3999 /*
4000 * Being attacked.
4001 *
4002 * Output: 0 if defeated, else object itself.
4003 */
4004
attacked(Game_object * attacker,int weapon_shape,int ammo_shape,bool explosion)4005 Game_object *Actor::attacked(
4006 Game_object *attacker,
4007 int weapon_shape, // < 0 for readied weapon.
4008 int ammo_shape, // < 0 for no ammo shape.
4009 bool explosion // If this is an explosion attacking.
4010 ) {
4011 if (is_dead() || // Already dead?
4012 // Or party member of dead Avatar?
4013 (party_id >= 0 && gwin->get_main_actor()->is_dead()))
4014 return nullptr;
4015 Actor *npc = attacker ? attacker->as_actor() : nullptr;
4016 if (npc)
4017 set_oppressor(npc->get_npc_num());
4018 if (npc && npc->get_schedule_type() == Schedule::duel)
4019 return this; // Just play-fighting.
4020
4021 int oldhp = properties[static_cast<int>(health)];
4022 int delta = figure_hit_points(attacker, weapon_shape, ammo_shape, explosion);
4023
4024 if (Combat::show_hits && !is_dead() && delta >= 0) {
4025 eman->remove_text_effect(this);
4026 char hpmsg[50];
4027 sprintf(hpmsg, "-%d(%d)", delta, oldhp - delta);
4028 eman->add_text(hpmsg, this);
4029 }
4030 if (combat_trace) {
4031 string name = "<trap>";
4032 if (attacker)
4033 name = attacker->get_name();
4034 cout << name << " hits " << get_name();
4035 if (delta > 0) {
4036 cout << " for " << delta << " hit points; ";
4037 if (oldhp > 0 && oldhp < delta)
4038 cout << get_name() << " is defeated." << endl;
4039 else
4040 cout << oldhp - delta << " hit points are left." << endl;
4041 } else if (!delta)
4042 cout << " to no damage." << endl;
4043 else
4044 cout << " causing an explosion." << endl;
4045 }
4046
4047 if (attacker && (is_dead() || properties[static_cast<int>(health)] < 0))
4048 return nullptr;
4049 return this;
4050 }
4051
4052 /*
4053 * There's probably a smarter way to do this, but this routine checks
4054 * for the dragon Draco.
4055 */
4056
Is_draco(Actor * dragon)4057 static bool Is_draco(
4058 Actor *dragon
4059 ) {
4060 Game_object_vector vec; // Gets list.
4061 // Should have a special scroll.
4062 int cnt = dragon->get_objects(vec, 797, 241, 4);
4063 return cnt > 0;
4064 }
4065
4066 /*
4067 * We're dead. We're removed from the world, but not deleted.
4068 */
4069
die(Game_object * attacker)4070 void Actor::die(
4071 Game_object *attacker
4072 ) {
4073 // If the actor is already dead, we shouldn't do anything
4074 //(fixes a resurrection bug).
4075 if (is_dead())
4076 return;
4077 set_action(nullptr);
4078 delete schedule;
4079 schedule = nullptr;
4080 gwin->get_tqueue()->remove(this);// Remove from time queue.
4081 Actor::set_flag(Obj_flags::dead);// IMPORTANT: Set this before moving
4082 // objs. so Usecode(eventid=6) isn't called.
4083 int shnum = get_shapenum();
4084 // Special case: Hook, Dracothraxus.
4085 if (((shnum == 0x1fa || (shnum == 0x1f8 && Is_draco(this))) &&
4086 Game::get_game_type() == BLACK_GATE)) {
4087 // Exec. usecode before dying.
4088 ucmachine->call_usecode(ucmachine->get_shape_fun(shnum), this,
4089 Usecode_machine::internal_exec);
4090 if (is_pos_invalid()) // Invalid now?
4091 return;
4092 }
4093 // Get location.
4094 Tile_coord pos = get_tile();
4095 //properties[static_cast<int>(health)] = -50;
4096 const Shape_info &info = get_info();
4097 const Monster_info *minfo = info.get_monster_info();
4098 bool frost_serp = GAME_SI && get_shapenum() == 832;
4099 if ((frost_serp && (get_framenum() & 0xf) == Actor::sit_frame)
4100 || (get_framenum() & 0xf) == Actor::sleep_frame) {
4101 auto *scr = new Usecode_script(this);
4102 (*scr) << Ucscript::delay_ticks << 4 << Ucscript::remove;
4103 scr->start();
4104 } else // Laying down to die.
4105 lay_down(true);
4106
4107 std::shared_ptr<Dead_body> body_keep;
4108 Dead_body *body; // See if we need a body.
4109 if (info.has_body_info() && (!minfo || !minfo->has_no_body())) {
4110 // Get body shape/frame.
4111 shnum = info.get_body_shape(); // Default 400.
4112 int frnum = info.get_body_frame(); // Default 3.
4113 // Reflect if NPC reflected.
4114 frnum |= (get_framenum() & 32);
4115 body_keep = std::make_shared<Dead_body>(shnum, frnum, 0, 0, 0,
4116 npc_num > 0 ? npc_num : -1);
4117 body = body_keep.get();
4118 Shape_frame *shp;
4119 bool have_body_shape = (shp = body->get_shape()) != nullptr && shp->is_empty();
4120 if (have_body_shape) {
4121 // Note: only do this if target shape is an actual
4122 // body shape (frame 0 empty).
4123 auto *scr = new Usecode_script(body);
4124 (*scr) << Ucscript::delay_ticks << 4 << Ucscript::frame << frnum;
4125 scr->start();
4126 }
4127 if (npc_num > 0) {
4128 // Originals would use body->set_quality(2) instead
4129 // for bodies of dead monsters. What we must do for
4130 // backwards compatibility...
4131 body->set_quality(1); // Flag for dead body of NPC.
4132 gwin->set_body(npc_num, body);
4133 }
4134 // Tmp. monster => tmp. body.
4135 if (get_flag(Obj_flags::is_temporary))
4136 body->set_flag(Obj_flags::is_temporary);
4137 // Remove NPC from map to prevent the body
4138 // from colliding with it.
4139 Game_object_shared keep_this;
4140 Game_object::remove_this(&keep_this);
4141 const Shape_info &binf = body->get_info();
4142 int dx = binf.get_3d_xtiles(frnum) - info.get_3d_xtiles(get_framenum());
4143 int dy = binf.get_3d_ytiles(frnum) - info.get_3d_ytiles(get_framenum());
4144 Tile_coord bp;
4145 // First, try matching corners of the NPC with corners of the body.
4146 bp = Map_chunk::find_spot(pos + Tile_coord(0, 0, 0), 0, shnum, frnum, 0);
4147 if (bp.tx == -1)
4148 bp = Map_chunk::find_spot(pos + Tile_coord(dx, 0, 0), 0, shnum, frnum, 0);
4149 if (bp.tx == -1)
4150 bp = Map_chunk::find_spot(pos + Tile_coord(0, dy, 0), 0, shnum, frnum, 0);
4151 if (bp.tx == -1)
4152 bp = Map_chunk::find_spot(pos + Tile_coord(dx, dy, 0), 0, shnum, frnum, 0);
4153 // If still no spot, force to NPC pos, even if blocked.
4154 if (bp.tx == -1)
4155 bp = pos;
4156 // Add NPC back.
4157 Game_object::move(pos);
4158 body->move(bp);
4159 if (have_body_shape) {
4160 body->change_frame(0); // Make body invisible
4161 }
4162 } else
4163 body = nullptr;
4164 Game_object *item; // Move/remove all the items.
4165 Game_object_shared_vector tooheavy; // Some shouldn't be moved.
4166 while ((item = objects.get_first()) != nullptr) {
4167 Game_object_shared item_keep = shared_from_obj(item);
4168 remove(item);
4169 item->set_invalid();
4170 if (item->get_info().is_spell())
4171 {
4172 tooheavy.push_back(item_keep);
4173 continue;
4174 }
4175 if (body) {
4176 item->set_shape_pos(255, 255); // So it gets placed.
4177 body->add(item, true);// Always succeed at adding.
4178 } else { // No body? Drop on ground.
4179 item->set_flag_recursively(Obj_flags::okay_to_take);
4180 Tile_coord pos2 = Map_chunk::find_spot(pos, 5,
4181 item->get_shapenum(), item->get_framenum(), 1);
4182 if (pos.tx != -1)
4183 item->move(pos2);
4184 else // No room anywhere.
4185 tooheavy.push_back(item_keep);
4186 }
4187 }
4188 if (body) // Okay to take its contents.
4189 body->set_flag_recursively(Obj_flags::okay_to_take);
4190
4191 // Put the heavy ones back.
4192 for (auto &it : tooheavy)
4193 add(it.get(), true);
4194 if (body)
4195 gwin->add_dirty(body);
4196 add_dirty(); // Want to repaint area.
4197 delete_contents(); // remove what's left of inventory
4198 Actor *npc = attacker ? attacker->as_actor() : nullptr;
4199 if (npc) {
4200 // Set oppressor and cause nearby NPCs to attack attacker.
4201 fight_back(attacker);
4202 set_target(nullptr, false);
4203 set_schedule_type(Schedule::wander);
4204
4205 // Is this a bad guy?
4206 // Party defeated an evil monster?
4207 if (npc->is_in_party() && !is_in_party() && alignment >= evil)
4208 Combat_schedule::monster_died();
4209 }
4210 // TODO: De-hard-code this.
4211 if (GAME_BG && is_in_party() && !Audio::get_ptr()->is_voice_playing()
4212 && (rand() % 4) == 0) {
4213 Audio::get_ptr()->start_speech(22);
4214 }
4215 // Move party member to 'dead' list.
4216 partyman->update_party_status(this);
4217 }
4218
4219 /*
4220 * Create another monster of the same type as this, and adjacent.
4221 *
4222 * Output: ->monster, or nullptr if failed.
4223 */
4224
clone()4225 Game_object_shared Actor::clone(
4226 ) {
4227 const Shape_info &info = get_info();
4228 // Base distance on greater dim.
4229 int frame = get_framenum();
4230 int xs = info.get_3d_xtiles(frame);
4231 int ys = info.get_3d_ytiles(frame);
4232 // Find spot.
4233 Tile_coord pos = Map_chunk::find_spot(get_tile(),
4234 xs > ys ? xs : ys, get_shapenum(), 0, 1);
4235 if (pos.tx < 0)
4236 return nullptr; // Failed.
4237 // Create, temporary & with equip.
4238 Game_object_shared monst = Monster_actor::create(
4239 get_shapenum(), pos, get_schedule_type(),
4240 get_effective_alignment(), true, true);
4241 return monst;
4242 }
4243
4244 /*
4245 * Restore HP's on the hour.
4246 */
4247
mend_wounds(bool mendmana)4248 void Actor::mend_wounds(
4249 bool mendmana
4250 ) {
4251 int hp = properties[static_cast<int>(health)];
4252 bool starving = (get_property(static_cast<int>(food_level)) <= 9
4253 && is_in_party() && !get_info().does_not_eat());
4254 // It should be okay to leave is_cold_immune out.
4255 // It blocks raising temperature in the first place.
4256 bool freezing = (is_in_party() && temperature >= 50 &&
4257 !(gear_powers & Frame_flags::cold_immune));
4258 if (is_dead() || get_flag(Obj_flags::poisoned) || (starving && hp > 0) ||
4259 freezing)
4260 return;
4261 int maxhp = properties[static_cast<int>(strength)];
4262 if (maxhp > 0 && hp < maxhp) {
4263 // first case doesn't seem to be used in the original - will keep for npcs
4264 if (maxhp >= 3 && !starving && get_schedule_type() == Schedule::sleep)
4265 hp += 1 + rand() % (maxhp / 3);
4266 else
4267 hp += 1;
4268 if (hp > maxhp)
4269 hp = maxhp;
4270 properties[static_cast<int>(health)] = hp;
4271 }
4272
4273 if (!mendmana)
4274 return;
4275 // Restore some mana also.
4276 int maxmana = properties[static_cast<int>(magic)];
4277 int curmana = properties[static_cast<int>(mana)];
4278 clear_flag(Obj_flags::no_spell_casting);
4279
4280 if (maxmana > 0 && curmana < maxmana) {
4281 if (maxmana >= 3)
4282 curmana += 1 + rand() % (maxmana / 3);
4283 else
4284 curmana += 1;
4285 properties[static_cast<int>(mana)] = curmana <= maxmana ? curmana
4286 : maxmana;
4287 }
4288 }
4289
4290 /*
4291 * Restore from body. It must not be owned by anyone.
4292 *
4293 * Output: ->actor if successful, else nullptr.
4294 */
4295
resurrect(Dead_body * body)4296 Actor *Actor::resurrect(
4297 Dead_body *body // Must be this actor's body.
4298 ) {
4299 Tile_coord pos;
4300 if (body) {
4301 if (body->get_owner() || // Must be on ground.
4302 npc_num <= 0 || gwin->get_body(npc_num) != body)
4303 return nullptr;
4304 gwin->set_body(npc_num, nullptr); // Clear from gwin's list.
4305 Game_object *item; // Get back all the items.
4306 while ((item = body->get_objects().get_first()) != nullptr) {
4307 Game_object_shared keep = item->shared_from_this();
4308 body->remove(item);
4309 add(item, true); // Always succeed at adding.
4310 }
4311 gwin->add_dirty(body); // Need to repaint here.
4312 pos = body->get_tile();
4313 body->remove_this(); // Remove and delete body.
4314 } else
4315 pos = Tile_coord(-1, -1, 0);
4316 move(pos); // Move back to life.
4317 // Restore health to max.
4318 properties[static_cast<int>(health)] =
4319 properties[static_cast<int>(strength)];
4320 Actor::clear_flag(Obj_flags::dead);
4321 Actor::clear_flag(Obj_flags::poisoned);
4322 Actor::clear_flag(Obj_flags::paralyzed);
4323 Actor::clear_flag(Obj_flags::asleep);
4324 Actor::clear_flag(Obj_flags::protection);
4325 Actor::clear_flag(Obj_flags::cursed);
4326 Actor::clear_flag(Obj_flags::charmed);
4327 // Restore to party if possible.
4328 partyman->update_party_status(this);
4329 // Give a reasonable schedule.
4330 set_schedule_type(is_in_party() ? Schedule::follow_avatar
4331 : Schedule::loiter);
4332 // Stand up.
4333 if (!body)
4334 return this;
4335 auto *scr = new Usecode_script(this);
4336 (*scr) << (Ucscript::npc_frame + Actor::sleep_frame)
4337 << (Ucscript::npc_frame + Actor::kneel_frame)
4338 << (Ucscript::npc_frame + Actor::standing);
4339 scr->start(1);
4340 return this;
4341 }
4342
4343 /*
4344 * Check to see if an actor taking a step is really blocked.
4345 */
4346
is_really_blocked(Tile_coord & t,bool force)4347 bool Actor::is_really_blocked(
4348 Tile_coord &t,
4349 bool force
4350 ) {
4351 if (abs(t.tz - get_tile().tz) > 1)
4352 return true;
4353 Game_object *block = find_blocking(t, get_direction(t));
4354 if (!block)
4355 return true; // IE, water.
4356 if (block == this)
4357 return false;
4358 // Try to get blocker to move aside.
4359 if (block->move_aside(this, get_direction(block)))
4360 return false;
4361 // (May have swapped places.) If okay, try one last time.
4362 return t != get_tile() && is_blocked(t, nullptr, force ? MOVE_ALL : 0);
4363 }
4364
4365 /*
4366 * Handle a time event (for animation).
4367 */
4368
handle_event(unsigned long curtime,uintptr udata)4369 void Main_actor::handle_event(
4370 unsigned long curtime, // Current time of day.
4371 uintptr udata // Ignored.
4372 ) {
4373 purge_deleted_actions();
4374 if (action) { // Doing anything?
4375 // Do what we should.
4376 int speed = action->get_speed();
4377 int delay = action->handle_event(this);
4378 if (!delay) {
4379 // Action finished.
4380 // This makes for a smoother scrolling and prevents the
4381 // avatar from skipping a step when walking.
4382 frame_time = speed;
4383 if (!frame_time) // Not a path. Add a delay anyway.
4384 frame_time = gwin->get_std_delay();
4385 delay = frame_time;
4386 set_action(nullptr);
4387 }
4388
4389 gwin->get_tqueue()->add(
4390 curtime + delay, this, udata);
4391 } else if (in_usecode_control() || get_flag(Obj_flags::paralyzed)) {
4392 frame_time = 0;
4393 // Keep trying if we are in usecode control.
4394 gwin->get_tqueue()->add(
4395 curtime + gwin->get_std_delay(), this, udata);
4396 } else if (schedule) {
4397 frame_time = 0;
4398 schedule->now_what();
4399 }
4400 }
4401
4402 /*
4403 * Get the party to follow.
4404 */
4405
get_followers() const4406 void Main_actor::get_followers(
4407 ) const {
4408 int cnt = partyman->get_count();
4409 for (int i = 0; i < cnt; i++) {
4410 Actor *npc = gwin->get_npc(partyman->get_member(i));
4411 if (!npc || npc->get_flag(Obj_flags::asleep) ||
4412 npc->is_dead())
4413 continue;
4414 int sched = npc->get_schedule_type();
4415 // Skip if in combat or set to 'wait'.
4416 if (sched != Schedule::combat &&
4417 sched != Schedule::wait &&
4418 // Loiter added for SI.
4419 sched != Schedule::loiter) {
4420 if (sched != Schedule::follow_avatar)
4421 npc->set_schedule_type(
4422 Schedule::follow_avatar);
4423 else
4424 npc->follow(this);
4425 }
4426 }
4427 }
4428
4429 /*
4430 * Step onto an adjacent tile.
4431 *
4432 * Output: false if blocked.
4433 */
4434
step(Tile_coord t,int frame,bool force)4435 bool Main_actor::step(
4436 Tile_coord t, // Tile to step onto.
4437 int frame, // New frame #.
4438 bool force
4439 ) {
4440 rest_time = 0; // Reset counter.
4441 t.fixme();
4442 // Get chunk.
4443 int cx = t.tx / c_tiles_per_chunk;
4444 int cy = t.ty / c_tiles_per_chunk;
4445 // Get rel. tile coords.
4446 int tx = t.tx % c_tiles_per_chunk;
4447 int ty = t.ty % c_tiles_per_chunk;
4448 Map_chunk *nlist = gmap->get_chunk(cx, cy);
4449 bool water;
4450 bool poison; // Get tile info.
4451 get_tile_info(this, gwin, nlist, tx, ty, water, poison);
4452 if (is_blocked(t, nullptr, force ? MOVE_ALL : 0)) {
4453 if (is_really_blocked(t, force)) {
4454 if (schedule) // Tell scheduler.
4455 schedule->set_blocked(t);
4456 stop();
4457 return false;
4458 }
4459 }
4460 if (poison && t.tz == 0)
4461 Actor::set_flag(static_cast<int>(Obj_flags::poisoned));
4462 // Check for scrolling.
4463 gwin->scroll_if_needed(this, t);
4464 add_dirty(); // Set to update old location.
4465 // Get old chunk, old tile.
4466 Map_chunk *olist = get_chunk();
4467 Tile_coord oldtile = get_tile();
4468 // Move it.
4469 Actor::movef(olist, nlist, tx, ty, frame, t.tz);
4470 add_dirty(true); // Set to update new.
4471 // In a new chunk?
4472 if (olist != nlist)
4473 Main_actor::switched_chunks(olist, nlist);
4474 int roof_height = nlist->is_roof(tx, ty, t.tz);
4475 gwin->set_ice_dungeon(nlist->is_ice_dungeon(tx, ty));
4476 if (gwin->set_above_main_actor(roof_height)) {
4477 gwin->set_in_dungeon(nlist->has_dungeon() ?
4478 nlist->is_dungeon(tx, ty) : 0);
4479 gwin->set_all_dirty();
4480 } else if (roof_height < 31 && gwin->set_in_dungeon(nlist->has_dungeon() ?
4481 nlist->is_dungeon(tx, ty) : 0))
4482 gwin->set_all_dirty();
4483 // Near an egg? (Do this last, since
4484 // it may teleport.)
4485 nlist->activate_eggs(this, t.tx, t.ty, t.tz,
4486 oldtile.tx, oldtile.ty);
4487 quake_on_walk();
4488 return true;
4489 }
4490
4491 /*
4492 * Setup cache after a change in chunks.
4493 */
4494
switched_chunks(Map_chunk * olist,Map_chunk * nlist)4495 void Main_actor::switched_chunks(
4496 Map_chunk *olist, // Old chunk, or null.
4497 Map_chunk *nlist // New chunk.
4498 ) {
4499 int newcx = nlist->get_cx();
4500 int newcy = nlist->get_cy();
4501 int xfrom;
4502 int xto;
4503 int yfrom;
4504 int yto; // Get range of chunks.
4505 if (!olist || // No old, or new map? Use all 9.
4506 olist->get_map() != nlist->get_map()) {
4507 xfrom = newcx > 0 ? newcx - 1 : newcx;
4508 xto = newcx < c_num_chunks - 1 ? newcx + 1 : newcx;
4509 yfrom = newcy > 0 ? newcy - 1 : newcy;
4510 yto = newcy < c_num_chunks - 1 ? newcy + 1 : newcy;
4511 } else {
4512 int oldcx = olist->get_cx();
4513 int oldcy = olist->get_cy();
4514 if (newcx == oldcx + 1) {
4515 xfrom = newcx;
4516 xto = newcx < c_num_chunks - 1 ? newcx + 1 : newcx;
4517 } else if (newcx == oldcx - 1) {
4518 xfrom = newcx > 0 ? newcx - 1 : newcx;
4519 xto = newcx;
4520 } else {
4521 xfrom = newcx > 0 ? newcx - 1 : newcx;
4522 xto = newcx < c_num_chunks - 1 ? newcx + 1 : newcx;
4523 }
4524 if (newcy == oldcy + 1) {
4525 yfrom = newcy;
4526 yto = newcy < c_num_chunks - 1 ? newcy + 1 : newcy;
4527 } else if (newcy == oldcy - 1) {
4528 yfrom = newcy > 0 ? newcy - 1 : newcy;
4529 yto = newcy;
4530 } else {
4531 yfrom = newcy > 0 ? newcy - 1 : newcy;
4532 yto = newcy < c_num_chunks - 1 ? newcy + 1 : newcy;
4533 }
4534 }
4535 for (int y = yfrom; y <= yto; y++)
4536 for (int x = xfrom; x <= xto; x++)
4537 nlist->get_map()->get_chunk(FIX_COORD(x), FIX_COORD(y))->setup_cache();
4538
4539 // If change in Superchunk number, apply Old Style caching emulation
4540 gwin->emulate_cache(olist, nlist);
4541 }
4542
4543 /*
4544 * Move (teleport) to a new spot.
4545 */
4546
move(int newtx,int newty,int newlift,int newmap)4547 void Main_actor::move(
4548 int newtx,
4549 int newty,
4550 int newlift,
4551 int newmap
4552 ) {
4553 // Store old chunk list.
4554 Map_chunk *olist = get_chunk();
4555 // Move it.
4556 Actor::move(newtx, newty, newlift, newmap);
4557 Map_chunk *nlist = get_chunk();
4558 if (nlist != olist)
4559 Main_actor::switched_chunks(olist, nlist);
4560 int tx = get_tx();
4561 int ty = get_ty();
4562 gwin->set_ice_dungeon(nlist->is_ice_dungeon(tx, ty));
4563 if (gwin->set_above_main_actor(nlist->is_roof(tx, ty, newlift)))
4564 gwin->set_in_dungeon(nlist->has_dungeon() ?
4565 nlist->is_dungeon(tx, ty) : 0);
4566 }
4567
4568 /*
4569 * We're dead.
4570 */
4571
die(Game_object *)4572 void Main_actor::die(
4573 Game_object * /* attacker */
4574 ) {
4575 if (gwin->in_combat())
4576 gwin->toggle_combat(); // Hope this is safe....
4577 Actor::set_flag(Obj_flags::dead);
4578 gumpman->close_all_gumps(); // Obviously.
4579 // Special function for dying:
4580 Usecode_function_data *info = Shapeinfo_lookup::GetAvUsecode(0);
4581 ucmachine->call_usecode(info->fun_id, this,
4582 static_cast<Usecode_machine::Usecode_events>(info->event_id));
4583 }
4584
4585 /*
4586 * Set the shapenum based on skin color, sex, naked flag and petra and polymorph flag
4587 */
set_actor_shape()4588 void Actor::set_actor_shape() {
4589 if (get_npc_num() != 0 || get_skin_color() < 0 ||
4590 (get_flag(Obj_flags::polymorph) && !get_flag(Obj_flags::naked)))
4591 return;
4592
4593 int sn;
4594 int female = get_type_flag(tf_sex) ? 1 : 0;
4595 Skin_data *skin = Shapeinfo_lookup::GetSkinInfoSafe(this);
4596
4597 if (!skin || // Should never happen, but hey...
4598 (!sman->have_si_shapes() &&
4599 Shapeinfo_lookup::IsSkinImported(
4600 get_flag(Obj_flags::naked) ? skin->naked_shape : skin->shape_num)))
4601 sn = Shapeinfo_lookup::GetBaseAvInfo(female != 0)->shape_num;
4602 else
4603 sn = get_flag(Obj_flags::naked) ? skin->naked_shape : skin->shape_num;
4604
4605 #ifdef DEBUG
4606 cerr << "Setting Shape to " << sn << endl;
4607 #endif
4608 set_shape(sn, get_framenum());
4609 set_file(SF_SHAPES_VGA);
4610 }
4611
4612 // Sets the polymorph to shape
set_polymorph(int shape)4613 void Actor::set_polymorph(int shape) {
4614 #ifdef DEBUG
4615 cerr << "Setting polymorph for " << get_npc_num() << endl;
4616 cerr << "Shape " << shape << endl;
4617 cerr << "Save shape " << shape_save << endl;
4618 #endif
4619
4620 // Want to set to Avatar
4621 if (shape == Shapeinfo_lookup::GetMaleAvShape() ||
4622 shape == Shapeinfo_lookup::GetFemaleAvShape()) {
4623 Actor *avatar = gwin->get_main_actor();
4624 if (!avatar) return;
4625
4626 Skin_data *skin = Shapeinfo_lookup::GetSkinInfoSafe(avatar);
4627 shape = avatar->get_flag(Obj_flags::naked) ? skin->naked_shape : skin->shape_num;
4628 if (this == avatar)
4629 shape_save = shape; // Revert to default un-polymorphed shape.
4630 }
4631 set_file(SF_SHAPES_VGA);
4632
4633 if (shape == shape_save) {
4634 set_shape(shape_save);
4635 shape_save = -1;
4636 clear_flag(Obj_flags::polymorph);
4637 return;
4638 }
4639 if (shape_save == -1) shape_save = get_shapenum();
4640 // set_shape (shape, get_framenum());
4641 // ++++Taking a guess for SI amulet:
4642 set_shape(shape, get_dir_framenum(Actor::standing));
4643 set_flag(Obj_flags::polymorph);
4644 }
4645
4646 // Sets polymorph shape to defaults based on flags and npc num
set_polymorph_default()4647 void Actor::set_polymorph_default() {
4648 if (!get_flag(Obj_flags::polymorph)
4649 || (get_npc_num() != 0 &&
4650 (GAME_SI && get_npc_num() != 28)))
4651 return;
4652
4653 set_actor_shape();
4654
4655 shape_save = get_shapenum();
4656
4657 if (get_npc_num() == 28) // Handle Petra First
4658 set_polymorph(Shapeinfo_lookup::GetMaleAvShape());
4659 else if (get_flag(Obj_flags::petra)) // Avatar as petra
4660 set_polymorph(658);
4661 else // Snake
4662 set_polymorph(530);
4663 }
4664
4665 /*
4666 * Get 'real' shape for Usecode.
4667 */
4668
get_shape_real() const4669 int Actor::get_shape_real(
4670 ) const {
4671 if (npc_num != 0) // Not the avatar?
4672 return shape_save != -1 ? shape_save : get_shapenum();
4673 // Taking guess (6/18/01):
4674 if (get_type_flag(Actor::tf_sex))
4675 return Shapeinfo_lookup::GetFemaleAvShape();
4676 else
4677 return Shapeinfo_lookup::GetMaleAvShape();
4678 }
4679
4680 /**
4681 * Causes earthquake on step if the actor flag is set.
4682 * @return: True if caused quake on walk, false otherwise.
4683 */
4684
quake_on_walk()4685 bool Actor::quake_on_walk(
4686 ) {
4687 if (get_info().quake_on_walk()) {
4688 qsteps = (qsteps + 1) % 5;
4689 if (!qsteps) // Time to roll?
4690 gwin->get_tqueue()->add(Game::get_ticks() + 10, new Earthquake(2));
4691 return true;
4692 }
4693 return false;
4694 }
4695 /*
4696 * Create NPC.
4697 */
4698
Npc_actor(const std::string & nm,int shapenum,int num,int uc)4699 Npc_actor::Npc_actor(
4700 const std::string &nm, // Name. A copy is made.
4701 int shapenum,
4702 int num,
4703 int uc
4704 ) : Actor(nm, shapenum, num, uc), nearby(false),
4705 num_schedules(0),
4706 schedules(nullptr) {
4707 }
4708
4709 /*
4710 * Kill an actor.
4711 */
4712
~Npc_actor()4713 Npc_actor::~Npc_actor(
4714 ) {
4715 delete [] schedules;
4716 }
4717
4718 /*
4719 * Set schedule list.
4720 */
4721
set_schedules(Schedule_change * sc_list,int cnt)4722 void Npc_actor::set_schedules(
4723 Schedule_change *sc_list,
4724 int cnt
4725 ) {
4726 delete [] schedules;
4727 schedules = sc_list;
4728 num_schedules = cnt;
4729 }
4730
4731 /*
4732 * Set schedule type.
4733 */
4734
set_schedule_time_type(int time,int type)4735 void Npc_actor::set_schedule_time_type(int time, int type) {
4736 Tile_coord tile;
4737 int i;
4738
4739 for (i = 0; i < num_schedules; i++) if (schedules[i].get_time() == time) break;
4740
4741 if (i == num_schedules) { // Didn't find it
4742 auto *scheds = new Schedule_change[num_schedules + 1];
4743
4744 for (i = 0; i < num_schedules; i++) {
4745 tile = schedules[i].get_pos();
4746 scheds[i].set(tile.tx, tile.ty, tile.tz,
4747 schedules[i].get_type(), schedules[i].get_time());
4748 }
4749
4750 scheds[num_schedules].set(0, 0, 0,
4751 static_cast<unsigned char>(type),
4752 static_cast<unsigned char>(time));
4753 set_schedules(scheds, num_schedules + 1);
4754 } else { // Did find it
4755 tile = schedules[i].get_pos();
4756 schedules[i].set(tile.tx, tile.ty, tile.tz,
4757 static_cast<unsigned char>(type),
4758 static_cast<unsigned char>(time));
4759 }
4760 }
4761
4762 /*
4763 * Set schedule location.
4764 */
4765
set_schedule_time_location(int time,int x,int y)4766 void Npc_actor::set_schedule_time_location(int time, int x, int y) {
4767 int i;
4768
4769 for (i = 0; i < num_schedules; i++) if (schedules[i].get_time() == time) break;
4770
4771 if (i == num_schedules) { // Didn't find it
4772 Tile_coord tile;
4773 auto *scheds = new Schedule_change[num_schedules + 1];
4774
4775 for (i = 0; i < num_schedules; i++) {
4776 tile = schedules[i].get_pos();
4777 scheds[i].set(tile.tx, tile.ty, tile.tz,
4778 schedules[i].get_type(), schedules[i].get_time());
4779 }
4780
4781 scheds[num_schedules].set(x, y, 0, 0,
4782 static_cast<unsigned char>(time));
4783 set_schedules(scheds, num_schedules + 1);
4784 } else { // Did find it
4785 schedules[i].set(x, y, 0,
4786 schedules[i].get_type(), static_cast<unsigned char>(time));
4787 }
4788 }
4789
4790 /*
4791 * Remove schedule
4792 */
4793
remove_schedule(int time)4794 void Npc_actor::remove_schedule(int time) {
4795 int i;
4796
4797 for (i = 0; i < num_schedules; i++)
4798 if (schedules[i].get_time() == time) break;
4799 if (i != num_schedules) { // Found it
4800 int todel = i;
4801 Tile_coord tile;
4802 auto *scheds = new Schedule_change[num_schedules - 1];
4803
4804 for (i = 0; i < todel; i++) {
4805 tile = schedules[i].get_pos();
4806 scheds[i].set(tile.tx, tile.ty, tile.tz,
4807 schedules[i].get_type(), schedules[i].get_time());
4808 }
4809
4810 for (; i < num_schedules - 1; i++) {
4811 tile = schedules[i + 1].get_pos();
4812 scheds[i].set(tile.tx, tile.ty, tile.tz,
4813 schedules[i + 1].get_type(),
4814 schedules[i + 1].get_time());
4815 }
4816
4817 set_schedules(scheds, num_schedules - 1);
4818 }
4819 }
4820
4821 /*
4822 * Set schedule list.
4823 */
4824
get_schedules(Schedule_change * & sc_list,int & cnt) const4825 void Npc_actor::get_schedules(
4826 Schedule_change *&sc_list,
4827 int &cnt
4828 ) const {
4829 sc_list = schedules;
4830 cnt = num_schedules;
4831 }
4832 /*
4833 * Move and change frame.
4834 */
4835
movef(Map_chunk * old_chunk,Map_chunk * new_chunk,int new_sx,int new_sy,int new_frame,int new_lift)4836 void Npc_actor::movef(
4837 Map_chunk *old_chunk,
4838 Map_chunk *new_chunk,
4839 int new_sx, int new_sy,
4840 int new_frame,
4841 int new_lift
4842 ) {
4843 Actor::movef(old_chunk, new_chunk,
4844 new_sx, new_sy, new_frame, new_lift);
4845 if (old_chunk != new_chunk) // In new chunk?
4846 Npc_actor::switched_chunks(old_chunk, new_chunk);
4847 }
4848
4849 /*
4850 * Find day's schedule for a given time-of-day.
4851 *
4852 * Output: index of schedule change.
4853 * -1 if not found, or if a party member.
4854 */
4855
find_schedule_change(int hour3)4856 int Npc_actor::find_schedule_change(
4857 int hour3 // 0=midnight, 1=3am, etc.
4858 ) {
4859 if (party_id >= 0 || is_dead())
4860 return -1; // Fail if a party member or dead.
4861 for (int i = 0; i < num_schedules; i++)
4862 if (schedules[i].get_time() == hour3)
4863 return i;
4864 return -1;
4865 }
4866
find_schedule_at_time(int hour3)4867 int Npc_actor::find_schedule_at_time(
4868 int hour3 // 0=midnight, 1=3am, etc.
4869 ) {
4870 if (party_id >= 0 || is_dead() || num_schedules == 0)
4871 return -1; // Fail if a party member or dead.
4872 int closest_dist = 100;
4873 int closest_index = 0;
4874 for (int i = 0; i < num_schedules; i++) {
4875 int dist = (hour3 - schedules[i].get_time() + 8) % 8;
4876 if (dist < closest_dist) {
4877 closest_dist = dist;
4878 closest_index = i;
4879 }
4880 }
4881 assert(closest_dist != 100);
4882 return closest_index;
4883 }
4884
4885 /*
4886 * Update schedule at a 3-hour time change.
4887 */
4888
update_schedule(int hour3,int delay,Tile_coord * pos)4889 void Npc_actor::update_schedule(
4890 int hour3, // 0=midnight, 1=3am, etc.
4891 int delay, // Delay in msecs, or -1 for random.
4892 Tile_coord *pos // Were we want to return to.
4893 ) {
4894 int i = find_schedule_change(hour3);
4895 if (i < 0) {
4896 // Not found? Look at prev.
4897 i = find_schedule_at_time(hour3);
4898 if (i < 0)
4899 return;
4900 if ((schedule_type == schedules[i].get_type() ||
4901 restored_schedule == schedules[i].get_type()) &&
4902 old_schedule_loc == schedules[i].get_pos()) {
4903 restored_schedule = -1;
4904 return; // Already in it.
4905 }
4906 }
4907 restored_schedule = -1;
4908 old_schedule_loc = schedules[i].get_pos();
4909 Tile_coord newloc = pos ? *pos : schedules[i].get_pos();
4910 set_schedule_and_loc(schedules[i].get_type(), newloc, delay);
4911 }
4912
4913 /*
4914 * Render.
4915 */
4916
paint()4917 void Npc_actor::paint(
4918 ) {
4919 Actor::paint(); // Draw on screen.
4920 if (dormant && schedule && // Resume schedule.
4921 // FOR NOW: Not when in formation.
4922 (party_id < 0 || !gwin->walk_in_formation ||
4923 schedule_type != Schedule::follow_avatar)) {
4924 dormant = false; // But clear out old entries first.??
4925 gwin->get_tqueue()->remove(this);
4926 // Force schedule->now_what() in .5secs
4927 // DO NOT call now_what here!!!
4928 uint32 curtime = Game::get_ticks();
4929 gwin->get_tqueue()->add(curtime + 500, this, gwin);
4930 }
4931 if (!nearby) // Make sure we're in 'nearby' list.
4932 gwin->add_nearby_npc(this);
4933 }
4934
4935 /*
4936 * Run usecode when double-clicked.
4937 */
activate(int event)4938 void Npc_actor::activate(
4939 int event
4940 ) {
4941 if (is_dead() && !cheat.in_map_editor())
4942 return;
4943 // Converse, etc.
4944 Actor::activate(event);
4945 }
4946
4947 /*
4948 * Handle a time event (for animation).
4949 */
4950
handle_event(unsigned long curtime,uintptr udata)4951 void Npc_actor::handle_event(
4952 unsigned long curtime, // Current time of day.
4953 uintptr udata // Ignored.
4954 ) {
4955 purge_deleted_actions();
4956 if ((cheat.in_map_editor() && party_id < 0) ||
4957 (get_flag(Obj_flags::paralyzed) || is_dead() || is_knocked_out() ||
4958 (get_flag(Obj_flags::asleep) && schedule_type != Schedule::sleep))) {
4959 gwin->get_tqueue()->add(
4960 curtime + gwin->get_std_delay(), this, udata);
4961 return;
4962 }
4963 // Prevent actor from doing anything if not in the active map.
4964 // ... but not if the NPC is not on the map (breaks pathfinding
4965 // from offscreen if NPC not on map).
4966 if (get_map() && get_map() != gwin->get_map()) {
4967 set_action(nullptr);
4968 dormant = true;
4969 if (schedule)
4970 schedule->im_dormant();
4971 return;
4972 }
4973
4974 // Goblins in goblin village should be overly aggressive.
4975 if (is_goblin() && in_goblin_village(this) && party_id < 0 && can_act() &&
4976 schedule &&
4977 (schedule_type != Schedule::combat && // Not if already in combat.
4978 // Patrol schedule already does this.
4979 schedule_type != Schedule::patrol &&
4980 schedule_type != Schedule::sleep &&
4981 schedule_type != Schedule::wait &&
4982 schedule_type != Schedule::arrest_avatar))
4983 schedule->seek_foes();
4984
4985 if (!action) { // Not doing anything?
4986 frame_time = 0;
4987 if (in_usecode_control() || !can_act())
4988 // Can't move on our own. Keep trying.
4989 gwin->get_tqueue()->add(
4990 curtime + gwin->get_std_delay(), this, udata);
4991 else if (schedule) {
4992 if (!dormant)
4993 schedule->now_what();
4994 else
4995 schedule->im_dormant();
4996 }
4997 } else {
4998 // Do what we should.
4999 int delay = party_id < 0 ? gwin->is_time_stopped() : 0;
5000 if (delay <= 0) { // Time not stopped?
5001 int speed = action->get_speed();
5002 delay = action->handle_event(this);
5003 if (!delay) {
5004 // Action finished. Add a slight delay.
5005 frame_time = speed;
5006 if (!frame_time) // Not a path. Add a delay anyway.
5007 frame_time = gwin->get_std_delay();
5008 delay = frame_time;
5009 set_action(nullptr);
5010 }
5011 }
5012 gwin->get_tqueue()->add(
5013 curtime + delay, this, udata);
5014 }
5015 }
5016
5017 /*
5018 * Step onto an adjacent tile.
5019 *
5020 * Output: false if blocked (or paralyzed).
5021 * Dormant is set if off screen.
5022 */
5023
step(Tile_coord t,int frame,bool force)5024 bool Npc_actor::step(
5025 Tile_coord t, // Tile to step onto.
5026 int frame, // New frame #.
5027 bool force
5028 ) {
5029 if (get_flag(Obj_flags::paralyzed) || get_map() != gmap)
5030 return false;
5031 Tile_coord oldtile = get_tile();
5032 // Get old chunk.
5033 t.fixme();
5034 // Get chunk.
5035 int cx = t.tx / c_tiles_per_chunk;
5036 int cy = t.ty / c_tiles_per_chunk;
5037 // Get rel. tile coords.
5038 int tx = t.tx % c_tiles_per_chunk;
5039 int ty = t.ty % c_tiles_per_chunk;
5040 // Get ->new chunk.
5041 Map_chunk *nlist = gmap->get_chunk_safely(cx, cy);
5042 if (!nlist) { // Shouldn't happen!
5043 stop();
5044 return false;
5045 }
5046 bool water;
5047 bool poison; // Get tile info.
5048 get_tile_info(this, gwin, nlist, tx, ty, water, poison);
5049 if (is_blocked(t, nullptr, force ? MOVE_ALL : 0)) {
5050 if (is_really_blocked(t, force)) {
5051 if (schedule) // Tell scheduler.
5052 schedule->set_blocked(t);
5053 stop();
5054 // Offscreen, but not in party?
5055 if (!gwin->add_dirty(this) && party_id < 0 &&
5056 // And > a screenful away?
5057 distance(gwin->get_camera_actor()) > 1 + c_screen_tile_size)
5058 dormant = true; // Go dormant.
5059 return false; // Done.
5060 }
5061 }
5062 if (poison && t.tz == 0)
5063 Actor::set_flag(static_cast<int>(Obj_flags::poisoned));
5064 // Check for scrolling.
5065 gwin->scroll_if_needed(this, t);
5066 add_dirty(); // Set to repaint old area.
5067 // Move it.
5068 Map_chunk *olist = get_chunk();
5069 movef(olist, nlist, tx, ty, frame, t.tz);
5070
5071 // Near an egg? (Do this last, since
5072 // it may teleport.)
5073 nlist->activate_eggs(this, t.tx, t.ty, t.tz, oldtile.tx, oldtile.ty);
5074
5075 // Offscreen, but not in party?
5076 if (!add_dirty(true) && party_id < 0 &&
5077 // And > a screenful away?
5078 distance(gwin->get_camera_actor()) > 1 + c_screen_tile_size &&
5079 //++++++++Try getting rid of the 'talk' line:
5080 get_schedule_type() != Schedule::talk &&
5081 get_schedule_type() != Schedule::street_maintenance) {
5082 // No longer on screen.
5083 stop();
5084 dormant = true;
5085 return false;
5086 }
5087 quake_on_walk();
5088 return true; // Add back to queue for next time.
5089 }
5090
5091 /*
5092 * Remove an object from its container, or from the world.
5093 * The object is deleted.
5094 */
5095
remove_this(Game_object_shared * keep)5096 void Npc_actor::remove_this(
5097 Game_object_shared *keep // Non-null to not delete.
5098 ) {
5099 set_action(nullptr);
5100 // delete schedule; // Problems in SI monster creation.
5101 // schedule = nullptr;
5102 // Messes up resurrection num_schedules = 0;
5103 gwin->get_tqueue()->remove(this);// Remove from time queue.
5104 gwin->remove_nearby_npc(this); // Remove from nearby list.
5105 // Store old chunk list.
5106 Map_chunk *olist = get_chunk();
5107 Game_object_shared keep_this;
5108 Actor::remove_this(&keep_this); // Remove, but don't ever delete an NPC
5109 Npc_actor::switched_chunks(olist, nullptr);
5110 set_invalid();
5111 if (!keep && npc_num > 0) // Really going?
5112 unused = true; // Mark unused if a numbered NPC.
5113 if (keep)
5114 *keep = std::move(keep_this);
5115 }
5116
5117 /*
5118 * Update chunks' npc lists after this has moved.
5119 */
5120
switched_chunks(Map_chunk * olist,Map_chunk * nlist)5121 void Npc_actor::switched_chunks(
5122 Map_chunk *olist, // Old chunk, or null.
5123 Map_chunk *nlist // New chunk, or null.
5124 ) {
5125 ignore_unused_variable_warning(olist, nlist);
5126 //++++++++++No longer needed. Maybe it should go away.
5127 }
5128
5129 /*
5130 * Move (teleport) to a new spot.
5131 */
5132
move(int newtx,int newty,int newlift,int newmap)5133 void Npc_actor::move(
5134 int newtx,
5135 int newty,
5136 int newlift,
5137 int newmap
5138 ) {
5139 // Store old chunk list.
5140 Map_chunk *olist = get_chunk();
5141 // Move it.
5142 Actor::move(newtx, newty, newlift, newmap);
5143 Map_chunk *nlist = get_chunk();
5144 if (nlist != olist) {
5145 Npc_actor::switched_chunks(olist, nlist);
5146 if (!olist) // Moving back into world?
5147 dormant = true; // Cause activation if painted.
5148 }
5149 }
5150
5151 /*
5152 * Get # of NPC a body came from (or -1 if not known).
5153 */
5154
get_live_npc_num() const5155 int Dead_body::get_live_npc_num(
5156 ) const {
5157 return npc_num;
5158 }
5159
5160 /*
5161 * Get size of IREG. Returns -1 if can't write to buffer.
5162 */
5163
get_ireg_size()5164 int Dead_body::get_ireg_size() {
5165 int size = Container_game_object::get_ireg_size();
5166 return size < 0 ? size : size + 1;
5167 }
5168
5169 /*
5170 * Write out body and its members.
5171 */
5172
write_ireg(ODataSource * out)5173 void Dead_body::write_ireg(
5174 ODataSource *out
5175 ) {
5176 unsigned char buf[21]; // 13-byte entry - Exult extension.
5177 uint8 *ptr = write_common_ireg(13, buf);
5178 Game_object *first = objects.get_first(); // Guessing: +++++
5179 unsigned short tword = first ? first->get_prev()->get_shapenum()
5180 : 0;
5181 Write2(ptr, tword);
5182 *ptr++ = 0; // Unknown.
5183 *ptr++ = get_quality();
5184 int npc = get_live_npc_num(); // If body, get source.
5185 // Here, store NPC # more simply.
5186 Write2(ptr, npc); // Allowing larger range of NPC bodies.
5187 *ptr++ = nibble_swap(get_lift()); // Lift
5188 *ptr++ = static_cast<unsigned char>(get_obj_hp()); // Resistance.
5189 // Flags: B0=invis. B3=okay_to_take.
5190 *ptr++ = (get_flag(Obj_flags::invisible) ? 1 : 0) +
5191 (get_flag(Obj_flags::okay_to_take) ? (1 << 3) : 0);
5192 out->write(reinterpret_cast<char *>(buf), ptr - buf);
5193 write_contents(out); // Write what's contained within.
5194 // Write scheduled usecode.
5195 Game_map::write_scheduled(out, this);
5196 }
5197
5198
5199 /*
5200 * Create a sequence of frames.
5201 */
5202
Frames_sequence(int cnt,unsigned char * f)5203 Frames_sequence::Frames_sequence(
5204 int cnt, // # of frames.
5205 unsigned char *f // List of frames.
5206 ) : num_frames(cnt) {
5207 frames = new unsigned char[cnt];
5208 memcpy(frames, f, cnt); // Copy in the list.
5209 }
5210