1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ultima/nuvie/core/nuvie_defs.h"
24 #include "ultima/nuvie/misc/u6_misc.h"
25 #include "ultima/nuvie/conf/configuration.h"
26 #include "ultima/nuvie/files/nuvie_file_list.h"
27 #include "ultima/nuvie/save/obj_list.h"
28 
29 #include "ultima/nuvie/actors/actor.h"
30 #include "ultima/nuvie/actors/u6_actor.h"
31 #include "ultima/nuvie/actors/se_actor.h"
32 #include "ultima/nuvie/actors/md_actor.h"
33 #include "ultima/nuvie/actors/u6_work_types.h"
34 #include "ultima/nuvie/core/tile_manager.h"
35 #include "ultima/nuvie/misc/u6_llist.h"
36 #include "ultima/nuvie/actors/actor_manager.h"
37 #include "ultima/nuvie/files/nuvie_io_file.h"
38 #include "ultima/nuvie/core/game_clock.h"
39 #include "ultima/nuvie/core/game.h"
40 #include "ultima/nuvie/core/party.h"
41 #include "ultima/nuvie/portraits/portrait.h"
42 #include "ultima/nuvie/script/script.h"
43 #include "ultima/nuvie/core/u6_objects.h"
44 #include "ultima/nuvie/gui/widgets/map_window.h"
45 #include "ultima/nuvie/views/view_manager.h"
46 
47 namespace Ultima {
48 namespace Nuvie {
49 
50 #define ACTOR_TEMP_INIT 255
51 #define SCHEDULE_SIZE 5
52 
53 void config_get_path(Configuration *config, Std::string filename, Std::string &path);
54 
ActorManager(Configuration * cfg,Map * m,TileManager * tm,ObjManager * om,GameClock * c)55 ActorManager::ActorManager(Configuration *cfg, Map *m, TileManager *tm, ObjManager *om, GameClock *c) {
56 	uint16 i;
57 
58 	config = cfg;
59 	map = m;
60 	tile_manager = tm;
61 	obj_manager = om;
62 	clock = c;
63 
64 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++)
65 		actors[i] = NULL;
66 	temp_actor_offset = 224;
67 	init();
68 }
69 
~ActorManager()70 ActorManager::~ActorManager() {
71 	clean();
72 }
73 
init()74 void ActorManager::init() {
75 	player_actor = 1;
76 
77 	last_obj_blk_x = cur_x = 0;
78 	last_obj_blk_y = cur_y = 0;
79 	last_obj_blk_z = cur_z = OBJ_TEMP_INIT;
80 	cmp_actor_loc = 0;
81 
82 	update = true;
83 	wait_for_player = true;
84 	combat_movement = false;
85 	should_clean_temp_actors = true;
86 
87 	return;
88 }
89 
clean()90 void ActorManager::clean() {
91 	uint16 i;
92 
93 //delete all actors
94 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
95 		if (actors[i]) {
96 			delete actors[i];
97 			actors[i] = NULL;
98 		}
99 	}
100 
101 	init();
102 
103 	return;
104 }
105 
load(NuvieIO * objlist)106 bool ActorManager::load(NuvieIO *objlist) {
107 	uint16 i;
108 	uint8 b1, b2, b3;
109 	int game_type;
110 
111 	clean();
112 
113 	config->value("config/GameType", game_type);
114 
115 	objlist->seek(0x100); // Start of Actor position info
116 	if (game_type == NUVIE_GAME_U6)
117 		temp_actor_offset = 203;
118 	else
119 		temp_actor_offset = 224;
120 
121 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
122 		switch (game_type) {
123 		case NUVIE_GAME_U6 :
124 			actors[i] = new U6Actor(map, obj_manager, clock);
125 			break;
126 		case NUVIE_GAME_MD :
127 			actors[i] = new MDActor(map, obj_manager, clock);
128 			break;
129 		case NUVIE_GAME_SE :
130 			actors[i] = new SEActor(map, obj_manager, clock);
131 			break;
132 		}
133 
134 		b1 = objlist->read1();
135 		b2 = objlist->read1();
136 		b3 = objlist->read1();
137 
138 		actors[i]->x = b1;
139 		actors[i]->x += (b2 & 0x3) << 8;
140 
141 		actors[i]->y = (b2 & 0xfc) >> 2;
142 		actors[i]->y += (b3 & 0xf) << 6;
143 
144 		actors[i]->z = (b3 & 0xf0) >> 4;
145 		actors[i]->id_n = (uint8)i;
146 
147 		actors[i]->temp_actor = is_temp_actor(actors[i]->id_n);
148 	}
149 
150 // objlist.seek(0x15f1);
151 
152 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
153 		b1 = objlist->read1();
154 		b2 = objlist->read1();
155 		actors[i]->obj_n = b1;
156 		actors[i]->obj_n += (b2 & 0x3) << 8;
157 
158 		actors[i]->frame_n = (b2 & 0xfc) >> 2;
159 		actors[i]->direction = actors[i]->frame_n / 4;
160 		if (actors[i]->obj_n == 0) { //Hack to get rid of Exodus.
161 			actors[i]->x = 0;
162 			actors[i]->y = 0;
163 			actors[i]->z = 0;
164 		}
165 	}
166 
167 // Object flags.
168 
169 	objlist->seek(0x000);
170 
171 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
172 		actors[i]->obj_flags = objlist->read1();
173 	}
174 
175 // Actor status flags.
176 
177 	objlist->seek(0x800);
178 
179 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
180 		actors[i]->status_flags = objlist->read1();
181 		actors[i]->alignment = ((actors[i]->status_flags & ACTOR_STATUS_ALIGNMENT_MASK) >> 5) + 1;
182 	}
183 
184 //old obj_n & frame_n values
185 
186 	objlist->seek(game_type == NUVIE_GAME_U6 ? 0x15f1 : 0x16f1);
187 
188 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
189 		b1 = objlist->read1();
190 		b2 = objlist->read1();
191 		actors[i]->base_obj_n = b1;
192 		actors[i]->base_obj_n += (b2 & 0x3) << 8;
193 
194 		actors[i]->old_frame_n = (b2 & 0xfc) >> 2;
195 
196 		if (actors[i]->obj_n == 0) {
197 			//actors[i]->obj_n = actors[i]->base_obj_n;
198 			//actors[i]->frame_n = actors[i]->old_frame_n;
199 			actors[i]->hide();
200 		}
201 
202 		if (actors[i]->base_obj_n == 0) {
203 			actors[i]->base_obj_n = actors[i]->obj_n;
204 			actors[i]->old_frame_n = actors[i]->frame_n;
205 		}
206 	}
207 // Strength
208 
209 	objlist->seek(0x900);
210 
211 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
212 		actors[i]->strength = objlist->read1();
213 	}
214 
215 // Dexterity
216 
217 	objlist->seek(0xa00);
218 
219 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
220 		actors[i]->dex = objlist->read1();
221 	}
222 
223 // Intelligence
224 
225 	objlist->seek(0xb00);
226 
227 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
228 		actors[i]->intelligence = objlist->read1();
229 	}
230 
231 	// Experience
232 
233 	objlist->seek(0xc00);
234 
235 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
236 		actors[i]->exp = objlist->read2();
237 	}
238 
239 // Health
240 
241 	objlist->seek(0xe00);
242 
243 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
244 		actors[i]->hp = objlist->read1();
245 	}
246 
247 // Experience Level
248 
249 	objlist->seek(0xff1);
250 
251 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
252 		actors[i]->level = objlist->read1();
253 	}
254 
255 
256 // Combat mode
257 
258 	objlist->seek(0x12f1);
259 
260 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
261 		switch (game_type) {
262 		case NUVIE_GAME_U6 :
263 			actors[i]->combat_mode = objlist->read1();
264 			break;
265 
266 		case NUVIE_GAME_MD : // FIXME not sure what this is supposed to be
267 		case NUVIE_GAME_SE :
268 			actors[i]->magic = objlist->read1();
269 			break;
270 		}
271 	}
272 
273 // Magic Points
274 
275 	objlist->seek(0x13f1);
276 
277 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
278 		switch (game_type) {
279 		case NUVIE_GAME_U6 :
280 			actors[i]->magic = objlist->read1();
281 			break;
282 
283 		case NUVIE_GAME_MD :
284 		case NUVIE_GAME_SE :
285 			actors[i]->combat_mode = objlist->read1();
286 			break;
287 		}
288 	}
289 
290 	if (game_type == NUVIE_GAME_U6) {
291 		objlist->seek(OBJLIST_OFFSET_U6_TALK_FLAGS); // Start of Talk flags
292 	} else {
293 		objlist->seek(OBJLIST_OFFSET_MD_TALK_FLAGS); //MD talk flags location. FIXME: check SE
294 	}
295 
296 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
297 		actors[i]->talk_flags = objlist->read1();
298 	}
299 
300 	objlist->seek(game_type == NUVIE_GAME_MD ? OBJLIST_OFFSET_MD_MOVEMENT_FLAGS : OBJLIST_OFFSET_U6_MOVEMENT_FLAGS);
301 
302 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) { //movement flags.
303 		actors[i]->movement_flags = objlist->read1();
304 	}
305 
306 	loadActorSchedules();
307 
308 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
309 		actors[i]->inventory_parse_readied_objects();
310 
311 		actors[i]->init(); //let the actor object do some init
312 	}
313 
314 // Moves
315 
316 	objlist->seek(game_type == NUVIE_GAME_MD ? OBJLIST_OFFSET_MD_MOVEMENT_POINTS : OBJLIST_OFFSET_U6_MOVEMENT_POINTS);
317 
318 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
319 		actors[i]->moves = objlist->read1();
320 	}
321 
322 // Current Worktype
323 
324 	objlist->seek(0x11f1);
325 
326 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
327 		actors[i]->set_worktype(objlist->read1(), true);
328 	}
329 
330 //cleanup party actor if not currently set as the player.
331 
332 	if (actors[ACTOR_VEHICLE_ID_N]->get_worktype() != ACTOR_WT_PLAYER) {
333 		Actor *a = actors[ACTOR_VEHICLE_ID_N];
334 		a->set_obj_n(0);
335 		a->x = 0;
336 		a->y = 0;
337 		a->z = 0;
338 		//a->status_flags = ACTOR_STATUS_DEAD;
339 		//a->hide();
340 	}
341 
342 	updateSchedules();
343 	loadCustomTiles(game_type);
344 
345 	return true;
346 }
347 
save(NuvieIO * objlist)348 bool ActorManager::save(NuvieIO *objlist) {
349 	uint16 i;
350 	uint8 b;
351 	int game_type;
352 
353 	config->value("config/GameType", game_type);
354 
355 	objlist->seek(0x100); // Start of Actor position info
356 
357 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
358 		objlist->write1(actors[i]->x & 0xff);
359 
360 		b = actors[i]->x >> 8;
361 		b += actors[i]->y << 2;
362 		objlist->write1(b);
363 
364 		b = actors[i]->y >> 6;
365 		b += actors[i]->z << 4;
366 		objlist->write1(b);
367 	}
368 
369 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
370 		objlist->write1(actors[i]->obj_n & 0xff);
371 		b = actors[i]->obj_n >> 8;
372 		b += actors[i]->frame_n << 2;
373 		objlist->write1(b);
374 	}
375 
376 //old obj_n & frame_n values
377 
378 	objlist->seek(game_type == NUVIE_GAME_U6 ? 0x15f1 : 0x16f1);
379 
380 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
381 		objlist->write1(actors[i]->base_obj_n & 0xff);
382 		b = actors[i]->base_obj_n >> 8;
383 		b += actors[i]->old_frame_n << 2;
384 		objlist->write1(b);
385 	}
386 
387 // Strength
388 
389 	objlist->seek(0x900);
390 
391 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
392 		objlist->write1(actors[i]->strength);
393 	}
394 
395 // Dexterity
396 
397 	objlist->seek(0xa00);
398 
399 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
400 		objlist->write1(actors[i]->dex);
401 	}
402 
403 // Intelligence
404 
405 	objlist->seek(0xb00);
406 
407 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
408 		objlist->write1(actors[i]->intelligence);
409 	}
410 
411 	// Experience
412 
413 	objlist->seek(0xc00);
414 
415 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
416 		objlist->write2(actors[i]->exp);
417 	}
418 
419 // Health
420 
421 	objlist->seek(0xe00);
422 
423 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
424 		objlist->write1(actors[i]->hp);
425 	}
426 
427 // Experience Level
428 
429 	objlist->seek(0xff1);
430 
431 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
432 		objlist->write1(actors[i]->level);
433 	}
434 
435 
436 // Combat mode
437 
438 	objlist->seek(0x12f1);
439 
440 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
441 		switch (game_type) {
442 		case NUVIE_GAME_U6 :
443 			objlist->write1(actors[i]->combat_mode);
444 			break;
445 
446 		case NUVIE_GAME_MD : // FIXME not sure what this is supposed to be
447 		case NUVIE_GAME_SE :
448 			objlist->write1(actors[i]->magic);
449 			break;
450 		}
451 	}
452 
453 // Magic Points
454 
455 	objlist->seek(0x13f1);
456 
457 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
458 		switch (game_type) {
459 		case NUVIE_GAME_U6 :
460 			objlist->write1(actors[i]->magic);
461 			break;
462 
463 		case NUVIE_GAME_MD :
464 		case NUVIE_GAME_SE :
465 			objlist->write1(actors[i]->combat_mode);
466 			break;
467 		}
468 	}
469 
470 // Moves
471 
472 	objlist->seek(0x14f1);
473 
474 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
475 		objlist->write1(actors[i]->moves);
476 	}
477 
478 	objlist->seek(0); // Start of Obj flags
479 
480 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
481 		objlist->write1(actors[i]->obj_flags);
482 	}
483 
484 	objlist->seek(0x800); // Start of Status flags
485 
486 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
487 		actors[i]->status_flags &= 0x9f;
488 		actors[i]->status_flags |= (actors[i]->alignment - 1) << 5;
489 		objlist->write1(actors[i]->status_flags);
490 	}
491 
492 	if (game_type == NUVIE_GAME_U6) {
493 		objlist->seek(0x17f1); // Start of Talk flags
494 	} else {
495 		objlist->seek(0x18f1); //MD talk flags location. FIXME: check SE
496 	}
497 
498 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
499 		objlist->write1(actors[i]->talk_flags);
500 	}
501 
502 	objlist->seek(0x19f1);
503 
504 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) { //movement flags.
505 		objlist->write1(actors[i]->movement_flags);
506 	}
507 	/*
508 	 for(i=0;i < ACTORMANAGER_MAX_ACTORS; i++)
509 	   {
510 	    actors[i]->inventory_parse_readied_objects();
511 
512 	    actors[i]->init(); //let the actor object do some init
513 	   }
514 	*/
515 // Current Worktype
516 
517 	objlist->seek(0x11f1);
518 
519 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
520 		objlist->write1(actors[i]->get_worktype());
521 	}
522 
523 	return true;
524 }
525 
get_actor_list()526 ActorList *ActorManager::get_actor_list() {
527 	ActorList *_actors = new ActorList(ACTORMANAGER_MAX_ACTORS);
528 	for (uint16 i = 0; i < ACTORMANAGER_MAX_ACTORS; i++)
529 		(*_actors)[i] = actors[i];
530 	return _actors;
531 }
532 
get_actor(uint8 actor_num)533 Actor *ActorManager::get_actor(uint8 actor_num) {
534 	return actors[actor_num];
535 }
536 
get_actor(uint16 x,uint16 y,uint8 z,bool inc_surrounding_objs,Actor * excluded_actor)537 Actor *ActorManager::get_actor(uint16 x, uint16 y, uint8 z, bool inc_surrounding_objs, Actor *excluded_actor) {
538 	uint16 i;
539 
540 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
541 		if (actors[i]->x == x && actors[i]->y == y && actors[i]->z == z && actors[i] != excluded_actor)
542 			return actors[i];
543 	}
544 
545 	if (inc_surrounding_objs) {
546 		Obj *obj = obj_manager->get_obj(x, y, z);
547 		if (obj && obj->is_actor_obj()) {
548 			if (obj->obj_n == OBJ_U6_SILVER_SERPENT && Game::get_game()->get_game_type() == NUVIE_GAME_U6)
549 				return actors[obj->qty];
550 
551 			return actors[obj->quality];
552 		}
553 
554 		return get_multi_tile_actor(x, y, z);
555 	}
556 
557 	return NULL;
558 }
559 
get_multi_tile_actor(uint16 x,uint16 y,uint8 z)560 Actor *ActorManager::get_multi_tile_actor(uint16 x, uint16 y, uint8 z) {
561 	Actor *actor = get_actor(x + 1, y + 1, z, false); //search for 2x2 tile actor.
562 	if (actor) {
563 		Tile *tile = actor->get_tile();
564 		if (tile->dbl_width && tile->dbl_height)
565 			return actor;
566 	}
567 
568 	actor = get_actor(x, y + 1, z, false); //search for 1x2 tile actor.
569 	if (actor) {
570 		Tile *tile = actor->get_tile();
571 		if (tile->dbl_height)
572 			return actor;
573 	}
574 
575 	actor = get_actor(x + 1, y, z, false); //search for 1x2 tile actor.
576 	if (actor) {
577 		Tile *tile = actor->get_tile();
578 		if (tile->dbl_width)
579 			return actor;
580 	}
581 
582 
583 	return NULL;
584 }
585 
get_avatar()586 Actor *ActorManager::get_avatar() {
587 	return get_actor(ACTOR_AVATAR_ID_N);
588 }
589 
get_player()590 Actor *ActorManager::get_player() {
591 	return actors[player_actor]; //FIX here for dead party leader etc.
592 }
593 
set_player(Actor * a)594 void ActorManager::set_player(Actor *a) {
595 	player_actor = a->id_n;
596 }
597 
598 /* Returns an actor's "look-string," a general description of their occupation
599  * or appearance. (the tile description)
600  */
look_actor(Actor * a,bool show_prefix)601 const char *ActorManager::look_actor(Actor *a, bool show_prefix) {
602 	uint16 tile_num = obj_manager->get_obj_tile_num(a->base_obj_n);
603 	if (tile_num == 0) {
604 		uint8 actor_num = a->id_n;
605 		if (actor_num == 191) // U6: Statue of Exodus
606 			return tile_manager->lookAtTile(obj_manager->get_obj_tile_num(399), 0, show_prefix);
607 		else if (actor_num == 189) // Statue of Mondain
608 			return tile_manager->lookAtTile(obj_manager->get_obj_tile_num(397), 0, show_prefix);
609 		else if (actor_num == 190) // Statue of Minax
610 			return tile_manager->lookAtTile(obj_manager->get_obj_tile_num(398), 0, show_prefix);
611 		else if (a->id_n >= 192 && a->id_n <= 200) // shrines
612 			return tile_manager->lookAtTile(obj_manager->get_obj_tile_num(393), 0, show_prefix);
613 
614 		return tile_manager->lookAtTile(obj_manager->get_obj_tile_num(a->obj_n), 0, show_prefix);
615 	}
616 	return tile_manager->lookAtTile(tile_num, 0, show_prefix);
617 }
618 
619 // Update area, and spawn or remove actors.
updateActors(uint16 x,uint16 y,uint8 z)620 void ActorManager::updateActors(uint16 x, uint16 y, uint8 z) {
621 // uint8 cur_hour;
622 // uint16 i;
623 
624 // if(!update)
625 //  return;
626 //DEBUG(0,LEVEL_DEBUGGING,"updateActors()\n");
627 
628 	cur_x = x;
629 	cur_y = y;
630 	cur_z = z;
631 
632 	uint16 cur_blk_x = x >> 3; // x / 8;
633 	uint16 cur_blk_y = y >> 3; // y / 8;
634 
635 	update_temp_actors(x, y, z); // Remove out of range temp actors
636 
637 	last_obj_blk_x = cur_blk_x; // moved from update_temp_actors() (SB-X)
638 	last_obj_blk_y = cur_blk_y;
639 	last_obj_blk_z = z;
640 
641 	return;
642 }
643 
644 // After player/party moves, continue moving actors.
startActors()645 void ActorManager::startActors() {
646 //DEBUG(0,LEVEL_DEBUGGING,"startActors()\n");
647 
648 	wait_for_player = false;
649 	//ERIC Game::get_game()->pause_user();
650 }
651 
updateSchedules(bool teleport)652 void ActorManager::updateSchedules(bool teleport) {
653 	uint8 cur_hour = clock->get_hour();
654 
655 	for (int i = 0; i < ACTORMANAGER_MAX_ACTORS; i++)
656 		if (!actors[i]->is_in_party()) // don't do scheduled activities while partying
657 			actors[i]->updateSchedule(cur_hour, teleport);
658 }
659 
twitchActors()660 void ActorManager::twitchActors() {
661 	uint16 i;
662 
663 // while Actors are part of the world, their twitching is considered animation
664 	if (Game::get_game()->anims_paused())
665 		return;
666 
667 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++)
668 		actors[i]->twitch();
669 
670 }
671 
672 // Update actors. StopActors() if no one can move.
moveActors()673 void ActorManager::moveActors() {
674 	if (!update || wait_for_player) {
675 		return;// nothing to do
676 	}
677 
678 	Game::get_game()->pause_user();
679 	Game::get_game()->get_script()->call_actor_update_all();
680 	Game::get_game()->get_map_window()->updateAmbience();
681 	Game::get_game()->get_view_manager()->update();
682 	//updateTime();
683 	Game::get_game()->unpause_user();
684 	wait_for_player = true;
685 
686 	return;
687 }
688 
loadActorSchedules()689 bool ActorManager::loadActorSchedules() {
690 	Std::string filename;
691 	NuvieIOFileRead schedule;
692 	uint16 i;
693 	uint16 total_schedules;
694 	uint16 num_schedules[ACTORMANAGER_MAX_ACTORS]; // an array to hold the number of schedule entries for each Actor.
695 	uint32 bytes_read;
696 	unsigned char *sched_data;
697 	uint16 *sched_offsets;
698 	unsigned char *s_ptr;
699 
700 	config_get_path(config, "schedule", filename);
701 	if (schedule.open(filename) == false)
702 		return false;
703 
704 	sched_offsets = (uint16 *)malloc(ACTORMANAGER_MAX_ACTORS * sizeof(uint16));
705 
706 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++)
707 		sched_offsets[i] = schedule.read2();
708 
709 	total_schedules = schedule.read2();
710 
711 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
712 		//if (sched_offsets[i] == 0)
713 		//    num_schedules[i] = 0;
714 		//else
715 		if (sched_offsets[i] > (total_schedules - 1))
716 			num_schedules[i] = 0;
717 		else
718 			// sched_offsets[i] is valid
719 		{
720 			if (i == ACTORMANAGER_MAX_ACTORS - 1)
721 				num_schedules[i] = total_schedules - sched_offsets[i];
722 			else if (sched_offsets[i + 1] > (total_schedules - 1))
723 				num_schedules[i] = total_schedules - sched_offsets[i];
724 			else
725 				// sched_offsets[i+1] is valid
726 				num_schedules[i] = sched_offsets[i + 1] - sched_offsets[i];
727 		}
728 	}
729 
730 	sched_data = schedule.readBuf(total_schedules * SCHEDULE_SIZE, &bytes_read);
731 
732 	if (!sched_data || bytes_read != (uint32)(total_schedules * SCHEDULE_SIZE)) {
733 		if (sched_data)
734 			free(sched_data);
735 		free(sched_offsets);
736 		DEBUG(0, LEVEL_ERROR, "Failed to read schedules!\n");
737 		return false;
738 	}
739 
740 	for (i = 0; i < ACTORMANAGER_MAX_ACTORS; i++) {
741 		s_ptr = sched_data + (sched_offsets[i] * SCHEDULE_SIZE);
742 		actors[i]->loadSchedule(s_ptr, num_schedules[i]);
743 	}
744 
745 	free(sched_data);
746 	free(sched_offsets);
747 
748 	return true;
749 }
750 
clear_actor(Actor * actor)751 void ActorManager::clear_actor(Actor *actor) {
752 	if (is_temp_actor(actor))
753 		clean_temp_actor(actor);
754 	else
755 		actor->clear();
756 
757 	return;
758 }
759 
resurrect_actor(Obj * actor_obj,MapCoord new_position)760 bool ActorManager::resurrect_actor(Obj *actor_obj, MapCoord new_position) {
761 	Actor *actor;
762 
763 	if (!is_temp_actor(actor_obj->quality)) {
764 		actor = get_actor(actor_obj->quality);
765 		actor->resurrect(new_position, actor_obj);
766 	}
767 
768 	return true;
769 }
770 
is_temp_actor(Actor * actor)771 bool ActorManager::is_temp_actor(Actor *actor) {
772 	if (actor)
773 		return is_temp_actor(actor->id_n);
774 
775 	return false;
776 }
777 
is_temp_actor(uint8 id_n)778 bool ActorManager::is_temp_actor(uint8 id_n) {
779 	if (id_n >= temp_actor_offset)
780 		return true;
781 
782 	return false;
783 }
784 
create_temp_actor(uint16 obj_n,uint8 obj_status,uint16 x,uint16 y,uint8 z,uint8 alignment,uint8 worktype,Actor ** new_actor)785 bool ActorManager::create_temp_actor(uint16 obj_n, uint8 obj_status, uint16 x, uint16 y, uint8 z, uint8 alignment, uint8 worktype, Actor **new_actor) {
786 	Actor *actor;
787 	actor = find_free_temp_actor();
788 
789 
790 	if (actor) {
791 		actor->inventory_del_all_objs(); //We need to do this because the original game doesn't unset inventory flag when temp actors die.
792 
793 		actor->base_obj_n = obj_n;
794 		actor->obj_n = obj_n;
795 		actor->frame_n = 0;
796 
797 		actor->x = x;
798 		actor->y = y;
799 		actor->z = z;
800 
801 		actor->temp_actor = true;
802 
803 		actor->obj_flags = 0;
804 		actor->status_flags = 0;
805 		actor->talk_flags = 0;
806 		actor->movement_flags = 0;
807 		actor->alignment = ACTOR_ALIGNMENT_NEUTRAL;
808 
809 		actor->init(obj_status);
810 
811 		Game::get_game()->get_script()->call_actor_init(actor, alignment);
812 
813 		// spawn double-tiled actors, like cows, facing west (SB-X)
814 		if (actor->get_tile_type() == ACTOR_DT)
815 			actor->set_direction(-1, 0);
816 		//if(worktype != 0)
817 		actor->set_worktype(worktype);
818 		actor->show();
819 
820 		DEBUG(0, LEVEL_INFORMATIONAL, "Adding Temp Actor #%d: %s (%x,%x,%x).\n", actor->id_n, tile_manager->lookAtTile(obj_manager->get_obj_tile_num(actor->obj_n) + actor->frame_n, 0, false), actor->x, actor->y, actor->z);
821 
822 		if (new_actor)
823 			*new_actor = actor;
824 		actor->handle_lightsource(clock->get_hour());
825 		return true;
826 	} else
827 		DEBUG(0, LEVEL_NOTIFICATION, "***All Temp Actor Slots Full***\n");
828 
829 	if (new_actor)
830 		*new_actor = NULL;
831 	return false;
832 }
833 
find_free_temp_actor()834 inline Actor *ActorManager::find_free_temp_actor() {
835 	uint16 i;
836 
837 	for (i = temp_actor_offset; i < ACTORMANAGER_MAX_ACTORS; i++) {
838 		if (actors[i]->obj_n == 0)
839 			return actors[i];
840 	}
841 
842 	return NULL;
843 }
844 
845 //FIX? should this be in Player??
846 // NO!
update_temp_actors(uint16 x,uint16 y,uint8 z)847 void ActorManager::update_temp_actors(uint16 x, uint16 y, uint8 z) {
848 	uint16 cur_blk_x, cur_blk_y;
849 
850 // We're changing levels so clean out all temp actors on the current level.
851 	if (last_obj_blk_z != z) {
852 		if (last_obj_blk_z != ACTOR_TEMP_INIT) { //don't clean actors on startup.
853 			clean_temp_actors_from_level(last_obj_blk_z);
854 			return;
855 		}
856 //    last_obj_blk_z = z;
857 	}
858 
859 	cur_blk_x = x >> 3; // x / 8;
860 	cur_blk_y = y >> 3; // y / 8;
861 
862 	if (cur_blk_x != last_obj_blk_x || cur_blk_y != last_obj_blk_y) {
863 //    last_obj_blk_x = cur_blk_x;
864 //    last_obj_blk_y = cur_blk_y;
865 
866 		clean_temp_actors_from_area(x, y);
867 	}
868 
869 	return;
870 }
871 
clean_temp_actors_from_level(uint8 level)872 void ActorManager::clean_temp_actors_from_level(uint8 level) {
873 	uint16 i;
874 
875 	for (i = temp_actor_offset; i < ACTORMANAGER_MAX_ACTORS; i++) {
876 		if ((actors[i]->is_visible() || actors[i]->x != 0 || actors[i]->y != 0 || actors[i]->z != 0)
877 		        && actors[i]->is_in_party() == false && actors[i]->z == level)
878 			clean_temp_actor(actors[i]);
879 	}
880 
881 	return;
882 }
883 
clean_temp_actors_from_area(uint16 x,uint16 y)884 void ActorManager::clean_temp_actors_from_area(uint16 x, uint16 y) {
885 	uint16 i;
886 	uint16 dist_x, dist_y;
887 
888 	if (!should_clean_temp_actors)
889 		return;
890 
891 	for (i = temp_actor_offset; i < ACTORMANAGER_MAX_ACTORS; i++) {
892 		if ((actors[i]->is_visible() || actors[i]->x != 0 || actors[i]->y != 0 || actors[i]->z != 0)
893 		        && actors[i]->is_in_party() == false) {
894 			dist_x = abs((sint16)actors[i]->x - x);
895 			dist_y = abs((sint16)actors[i]->y - y);
896 
897 			if (dist_x > 19 || dist_y > 19) {
898 				clean_temp_actor(actors[i]);
899 			}
900 		}
901 	}
902 
903 	return;
904 }
905 
clean_temp_actor(Actor * actor)906 inline void ActorManager::clean_temp_actor(Actor *actor) {
907 	DEBUG(0, LEVEL_INFORMATIONAL, "Removing Temp Actor #%d: %s (%x,%x,%x).\n", actor->id_n, tile_manager->lookAtTile(obj_manager->get_obj_tile_num(actor->obj_n) + actor->frame_n, 0, false), actor->x, actor->y, actor->z);
908 	actor->obj_n = 0;
909 	actor->clear();
910 
911 	return;
912 }
913 
clone_actor(Actor * actor,Actor ** new_actor,MapCoord new_location)914 bool ActorManager::clone_actor(Actor *actor, Actor **new_actor, MapCoord new_location) {
915 	if (actor == NULL)
916 		return false;
917 
918 	if (create_temp_actor(actor->obj_n, NO_OBJ_STATUS, new_location.x, new_location.y, new_location.z, actor->alignment, actor->worktype, new_actor) == false)
919 		return false;
920 
921 	(*new_actor)->strength = actor->strength;
922 	(*new_actor)->dex = actor->dex;
923 	(*new_actor)->intelligence = actor->intelligence;
924 
925 	(*new_actor)->magic = actor->magic;
926 	(*new_actor)->exp = actor->exp;
927 	(*new_actor)->hp = actor->hp;
928 
929 	return true;
930 }
931 
932 /* Move an actor to a random location within range.
933  * Returns true when tossed.
934  */
toss_actor(Actor * actor,uint16 xrange,uint16 yrange)935 bool ActorManager::toss_actor(Actor *actor, uint16 xrange, uint16 yrange) {
936 	// maximum number of tries
937 	const uint32 toss_max = MAX(xrange, yrange) * MIN(xrange, yrange) * 2;
938 	uint32 t = 0;
939 	LineTestResult lt;
940 	if (xrange > 0) --xrange; // range includes the starting location
941 	if (yrange > 0) --yrange;
942 	while (t++ < toss_max) { // TRY RANDOM LOCATION
943 		sint16 x = (actor->x - xrange) + (NUVIE_RAND() % ((actor->x + xrange) - (actor->x - xrange) + 1)),
944 		       y = (actor->y - yrange) + (NUVIE_RAND() % ((actor->y + yrange) - (actor->y - yrange) + 1));
945 		if (!map->lineTest(actor->x, actor->y, x, y, actor->z, LT_HitUnpassable, lt))
946 			if (!get_actor(x, y, actor->z))
947 				return (actor->move(x, y, actor->z));
948 	}
949 	// TRY ANY LOCATION
950 	for (int y = actor->y - yrange; y < actor->y + yrange; y++)
951 		for (int x = actor->x - xrange; x < actor->x + xrange; x++)
952 			if (!map->lineTest(actor->x, actor->y, x, y, actor->z, LT_HitUnpassable, lt))
953 				if (!get_actor(x, y, actor->z))
954 					return (actor->move(x, y, actor->z));
955 	return (false);
956 }
957 
958 /* Find a location to put actor within range.
959  * Returns true when tossed.
960  */
toss_actor_get_location(uint16 start_x,uint16 start_y,uint8 start_z,uint16 xrange,uint16 yrange,MapCoord * location)961 bool ActorManager::toss_actor_get_location(uint16 start_x, uint16 start_y, uint8 start_z, uint16 xrange, uint16 yrange, MapCoord *location) {
962 	// maximum number of tries
963 	const uint32 toss_max = MAX(xrange, yrange) * MIN(xrange, yrange) * 2;
964 	uint32 t = 0;
965 	LineTestResult lt;
966 	if (xrange > 0) --xrange; // range includes the starting location
967 	if (yrange > 0) --yrange;
968 	while (t++ < toss_max) { // TRY RANDOM LOCATION
969 		sint16 x = (start_x - xrange) + (NUVIE_RAND() % ((start_x + xrange) - (start_x - xrange) + 1)),
970 		       y = (start_y - yrange) + (NUVIE_RAND() % ((start_y + yrange) - (start_y - yrange) + 1));
971 		if (!map->lineTest(start_x, start_y, x, y, start_z, LT_HitUnpassable, lt)) {
972 			if (!get_actor(x, y, start_z)) {
973 				location->x = x;
974 				location->y = y;
975 				location->z = start_z;
976 				return can_put_actor(*location);
977 			}
978 
979 		}
980 	}
981 	// TRY ANY LOCATION
982 	for (int y = start_y - yrange; y < start_y + yrange; y++)
983 		for (int x = start_x - xrange; x < start_x + xrange; x++)
984 			if (!map->lineTest(start_x, start_y, x, y, start_z, LT_HitUnpassable, lt)) {
985 				if (!get_actor(x, y, start_z)) {
986 					location->x = x;
987 					location->y = y;
988 					location->z = start_z;
989 					return can_put_actor(*location);
990 				}
991 			}
992 
993 	return (false);
994 }
995 
996 
997 /* Returns the actor whose inventory contains an object. */
get_actor_holding_obj(Obj * obj)998 Actor *ActorManager::get_actor_holding_obj(Obj *obj) {
999 	assert(obj->is_in_inventory());
1000 
1001 	while (obj->is_in_container())
1002 		obj = obj->get_container_obj();
1003 	return (Actor *)obj->parent;
1004 }
1005 
1006 // Remove list actors who fall out of a certain range from a location.
filter_distance(ActorList * list,uint16 x,uint16 y,uint8 z,uint16 dist)1007 ActorList *ActorManager::filter_distance(ActorList *list, uint16 x, uint16 y, uint8 z, uint16 dist) {
1008 	ActorIterator i = list->begin();
1009 	while (i != list->end()) {
1010 		Actor *actor = *i;
1011 		MapCoord loc(x, y, z);
1012 		MapCoord actor_loc(actor->x, actor->y, actor->z);
1013 		if (loc.distance(actor_loc) > dist || loc.z != actor_loc.z)
1014 			i = list->erase(i);
1015 		else ++i;
1016 	}
1017 	return list;
1018 }
1019 
1020 // Remove actors who don't need to move in this turn. That includes anyone not
1021 // in a certain range of xyz, and actors that are already out of moves.
filter_active_actors(ActorList * list,uint16 x,uint16 y,uint8 z)1022 inline ActorList *ActorManager::filter_active_actors(ActorList *list, uint16 x, uint16 y, uint8 z) {
1023 	const uint8 dist = 24;
1024 	ActorIterator i = list->begin();
1025 	while (i != list->end()) {
1026 		Actor *actor = *i;
1027 		MapCoord loc(x, y, z);
1028 		MapCoord actor_loc(actor->x, actor->y, actor->z);
1029 		if (!actor->is_in_party()) {
1030 			if ((loc.distance(actor_loc) > dist || loc.z != actor_loc.z)
1031 			        && actor->worktype != WORKTYPE_U6_WALK_TO_LOCATION)
1032 				actor->set_moves_left(0);
1033 			if (actor->is_sleeping() || actor->is_immobile() || !actor->is_alive())
1034 				actor->set_moves_left(0);
1035 		}
1036 		if ((actor->is_in_party() == true && combat_movement == false) || actor->moves <= 0)
1037 			i = list->erase(i);
1038 		else ++i;
1039 	}
1040 	return list;
1041 }
1042 
1043 // Sort list by distance to a location. Remove actors on different planes.
sort_nearest(ActorList * list,uint16 x,uint16 y,uint8 z)1044 ActorList *ActorManager::sort_nearest(ActorList *list, uint16 x, uint16 y, uint8 z) {
1045 	struct Actor::cmp_distance_to_loc cmp_func; // comparison function object
1046 	MapCoord loc(x, y, z);
1047 	cmp_func(loc); // set location in function object
1048 	Common::sort(list->begin(), list->end(), cmp_func);
1049 
1050 	ActorIterator a = list->begin();
1051 	while (a != list->end())
1052 		if ((*a)->z != z)
1053 			a = list->erase(a); // only return actors on the same map
1054 		else ++a;
1055 	return list;
1056 }
1057 
print_actor(Actor * actor)1058 void ActorManager::print_actor(Actor *actor) {
1059 	actor->print();
1060 }
1061 
can_put_actor(MapCoord location)1062 bool ActorManager::can_put_actor(MapCoord location) {
1063 	if (!map->is_passable(location.x, location.y, location.z))
1064 		return false;
1065 
1066 	if (get_actor(location.x, location.y, location.z) != NULL)
1067 		return false;
1068 
1069 	return true;
1070 }
1071 
1072 // Remove actors with a certain alignment from the list. Returns the same list.
filter_alignment(ActorList * list,uint8 align)1073 ActorList *ActorManager::filter_alignment(ActorList *list, uint8 align) {
1074 	ActorIterator i = list->begin();
1075 	while (i != list->end()) {
1076 		Actor *actor = *i;
1077 		if (actor->alignment == align)
1078 			i = list->erase(i);
1079 		else ++i;
1080 	}
1081 	return list;
1082 }
1083 
1084 // Remove actors in the party. Returns the original list pointer.
filter_party(ActorList * list)1085 ActorList *ActorManager::filter_party(ActorList *list) {
1086 	ActorIterator i = list->begin();
1087 	while (i != list->end()) {
1088 		Actor *actor = *i;
1089 		if (actor->is_in_party() == true || actor->id_n == 0) // also remove vehicle
1090 			i = list->erase(i);
1091 		else ++i;
1092 	}
1093 	return list;
1094 }
1095 
set_combat_movement(bool c)1096 void ActorManager::set_combat_movement(bool c) {
1097 	combat_movement = c;
1098 }
1099 
loadCustomTiles(nuvie_game_t game_type)1100 bool ActorManager::loadCustomTiles(nuvie_game_t game_type) {
1101 	if (obj_manager->use_custom_actor_tiles() == false) {
1102 		return false;
1103 	}
1104 
1105 	Std::string datadir = "images";
1106 	Std::string path;
1107 
1108 	build_path(datadir, "tiles", path);
1109 	datadir = path;
1110 	build_path(datadir, get_game_tag(game_type), path);
1111 	datadir = path;
1112 
1113 	tile_manager->freeCustomTiles(); //FIXME this might need to change if we start using custom tiles outside of ActorManager. eg custom map/object tilesets
1114 
1115 	loadCustomBaseTiles(datadir);
1116 	loadAvatarTiles(datadir);
1117 	loadNPCTiles(datadir);
1118 
1119 	return true;
1120 }
1121 
loadCustomBaseTiles(Std::string datadir)1122 void ActorManager::loadCustomBaseTiles(Std::string datadir) {
1123 	Std::string imagefile;
1124 	build_path(datadir, "custom_tiles.bmp", imagefile);
1125 
1126 	//attempt to load custom base tiles if the file exists.
1127 	tile_manager->loadCustomTiles(Game::get_game()->get_data_file_path(imagefile), true, true, 0);
1128 }
1129 
loadAvatarTiles(Std::string datadir)1130 void ActorManager::loadAvatarTiles(Std::string datadir) {
1131 	Std::string imagefile;
1132 
1133 	uint8 avatar_portrait = Game::get_game()->get_portrait()->get_avatar_portrait_num();
1134 
1135 	Std::set<Std::string> files = getCustomTileFilenames(datadir, "avatar_");
1136 
1137 	for (Std::set<Std::string>::iterator iter = files.begin(); iter != files.end(); iter++) {
1138 		Std::string filename = *iter;
1139 		if (filename.length() != 19) { // avatar_nnn_nnnn.bmp
1140 			continue;
1141 		}
1142 		Std::string num_str = filename.substr(7, 3);
1143 		uint8 portrait_num = (uint8)strtol(num_str.c_str(), NULL, 10);
1144 
1145 		if (portrait_num == avatar_portrait) {
1146 			num_str = filename.substr(11, 4);
1147 			uint16 obj_n = (uint16)strtol(num_str.c_str(), NULL, 10);
1148 
1149 			Std::string path;
1150 			build_path(datadir, filename, path);
1151 			imagefile = Game::get_game()->get_data_file_path(path);
1152 			Tile *start_tile = tile_manager->loadCustomTiles(imagefile, false, true, actors[1]->get_tile_num());
1153 			if (start_tile) {
1154 				actors[1]->set_custom_tile_num(obj_n, start_tile->tile_num);
1155 			}
1156 		}
1157 	}
1158 	return;
1159 }
1160 
loadNPCTiles(Std::string datadir)1161 void ActorManager::loadNPCTiles(Std::string datadir) {
1162 	Std::string imagefile;
1163 
1164 	Std::set<Std::string> files = getCustomTileFilenames(datadir, "actor_");
1165 
1166 	for (Std::set<Std::string>::iterator iter = files.begin(); iter != files.end(); iter++) {
1167 		Std::string filename = *iter;
1168 		if (filename.length() != 18) { // actor_nnn_nnnn.bmp
1169 			continue;
1170 		}
1171 		Std::string num_str = filename.substr(6, 3);
1172 		uint8 actor_num = (uint8)strtol(num_str.c_str(), NULL, 10);
1173 
1174 		num_str = filename.substr(10, 4);
1175 		uint16 obj_n = (uint16)strtol(num_str.c_str(), NULL, 10);
1176 
1177 		Std::string path;
1178 		build_path(datadir, filename, path);
1179 		imagefile = Game::get_game()->get_data_file_path(path);
1180 		Tile *start_tile = tile_manager->loadCustomTiles(imagefile, false, true, actors[actor_num]->get_tile_num());
1181 		if (start_tile) {
1182 			actors[actor_num]->set_custom_tile_num(obj_n, start_tile->tile_num);
1183 		}
1184 	}
1185 	return;
1186 }
1187 
getCustomTileFilenames(Std::string datadir,Std::string filenamePrefix)1188 Std::set<Std::string> ActorManager::getCustomTileFilenames(Std::string datadir, Std::string filenamePrefix) {
1189 	NuvieFileList filelistDataDir;
1190 	NuvieFileList filelistSaveGameDir;
1191 	Std::string path;
1192 
1193 	build_path(GUI::get_gui()->get_data_dir(), datadir, path);
1194 	filelistDataDir.open(path.c_str(), filenamePrefix.c_str(), NUVIE_SORT_NAME_ASC);
1195 
1196 	path = "data";
1197 	build_path(path, datadir, path);
1198 	filelistSaveGameDir.open(path.c_str(), filenamePrefix.c_str(), NUVIE_SORT_NAME_ASC);
1199 
1200 	Std::set<Std::string> files = filelistSaveGameDir.get_filenames();
1201 	Std::set<Std::string> dataFiles = filelistDataDir.get_filenames();
1202 	files.insert(dataFiles.begin(), dataFiles.end());
1203 	return files;
1204 }
1205 
1206 } // End of namespace Nuvie
1207 } // End of namespace Ultima
1208