1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/global_switches.h"
29 #include "engines/icb/session.h"
30 #include "engines/icb/animation_mega_set.h"
31 #include "engines/icb/object_structs.h"
32 #include "engines/icb/debug.h"
33 #include "engines/icb/p4_generic.h"
34 #include "engines/icb/mission.h"
35 #include "engines/icb/p4.h"
36 #include "engines/icb/player.h"
37 #include "engines/icb/global_objects.h"
38 #include "engines/icb/floors.h"
39 #include "engines/icb/common/px_scriptengine.h"
40 #include "engines/icb/common/px_floor_map.h"
41 #include "engines/icb/common/px_features.h"
42 #include "engines/icb/res_man.h"
43 
44 #include "common/util.h"
45 
46 namespace ICB {
47 
48 // this is the master animation declaration table.
49 _an_anim_entry master_anim_name_table[__TOTAL_ANIMS] = {
50 	{"walk", __WALK},
51 	{"walk_to_stand", __WALK_TO_STAND},
52 	{"walk_to_other_stand_(left_leg)", __WALK_TO_OTHER_STAND_LEFT_LEG},
53 	{"walk_to_pull_out_weapon", __WALK_TO_PULL_OUT_WEAPON},
54 
55 	{"stand", __STAND},
56 	{"stand_to_walk", __STAND_TO_WALK},
57 	{"stand_to_walk_upstairs_right", __STAND_TO_WALK_UP_STAIRS_RIGHT},
58 	{"stand_to_walk_downstairs_right", __STAND_TO_WALK_DOWN_STAIRS_RIGHT},
59 	{"stand_to_run", __STAND_TO_RUN},
60 	{"stand_to_step_backward", __STAND_TO_STEP_BACKWARD},
61 	{"stand_crouch_to_stand", __STAND_CROUCHED_TO_STAND},
62 	{"stand_crouch_to_walk_crouched", __STAND_CROUCHED_TO_WALK_CROUCHED},
63 
64 	{"run", __RUN},
65 	{"run_to_stand", __RUN_TO_STAND},
66 	{"run_to_pull_out_weapon", __RUN_TO_PULL_OUT_WEAPON},
67 
68 	{"use_card_on_slot", __USE_CARD_ON_SLOT},
69 	{"pick_up_object_from_floor", __PICK_UP_OBJECT_FROM_FLOOR},
70 	{"push_button", __PUSH_BUTTON},
71 	{"being_shot", __BEING_SHOT},
72 	{"being_shot_dead", __BEING_SHOT_DEAD},
73 
74 	{"sidestep_left", __SIDESTEP_LEFT},
75 	{"step_backward", __STEP_BACKWARD},
76 	{"step_forward", __STEP_FORWARD},
77 	{"step_backward_to_stand", __STEP_BACKWARD_TO_STAND},
78 	{"step_backward_to_other_stand_(left_leg)", __STEP_BACKWARD_TO_OTHER_STAND_LEFT},
79 
80 	{"stand_and_aim", __STAND_AND_AIM},
81 	{"stand_and_shoot", __STAND_AND_SHOOT},
82 	{"pull_out_weapon", __PULL_OUT_WEAPON},
83 	{"cord_strike", __STRIKE},
84 	{"low_strike", __LOW_STRIKE},
85 	{"hit_from_behind", __HIT_FROM_BEHIND},
86 
87 	{"turn_on_the_spot_cw", __TURN_ON_THE_SPOT_CLOCKWISE},
88 
89 	{"walk_upstairs_left", __WALK_UPSTAIRS_LEFT},
90 	{"walk_upstairs_right", __WALK_UPSTAIRS_RIGHT},
91 	{"walk_downstairs_left", __WALK_DOWNSTAIRS_LEFT},
92 	{"walk_downstairs_right", __WALK_DOWNSTAIRS_RIGHT},
93 
94 	{"walk_upstairs_left_to_stood_on_stairs_facing_up", __WALK_UPSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_UP},
95 	{"walk_upstairs_right_to_stood_on_stairs_facing_up", __WALK_UPSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_UP},
96 	{"walk_downstairs_left_to_stood_on_stairs_facing_down", __WALK_DOWNSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_DOWN},
97 	{"walk_downstairs_right_to_stood_on_stairs_facing_down", __WALK_DOWNSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_DOWN},
98 
99 	{"walk_upstairs_left_to_walk_downstairs_right", __WALK_UPSTAIRS_LEFT_TO_WALK_DOWNSTAIRS_RIGHT},
100 	{"walk_upstairs_right_to_walk_downstairs_left", __WALK_UPSTAIRS_RIGHT_TO_WALK_DOWNSTAIRS_LEFT},
101 	{"walk_downstairs_left_to_walk_upstairs_right", __WALK_DOWNSTAIRS_LEFT_TO_WALK_UPSTAIRS_RIGHT},
102 	{"walk_downstairs_right_to_walk_upstairs_left", __WALK_DOWNSTAIRS_RIGHT_TO_WALK_UPSTAIRS_LEFT},
103 
104 	{"run_up_stairs_left", __RUN_UPSTAIRS_LEFT},
105 	{"run_up_stairs_right", __RUN_UPSTAIRS_RIGHT},
106 	{"run_down_stairs_left", __RUN_DOWNSTAIRS_LEFT},
107 	{"run_down_stairs_right", __RUN_DOWNSTAIRS_RIGHT},
108 
109 	{"climb_up_ladder_left", __CLIMB_UP_LADDER_LEFT},
110 	{"climb_up_ladder_right", __CLIMB_UP_LADDER_RIGHT},
111 	{"climb_down_ladder_left", __CLIMB_DOWN_LADDER_LEFT},
112 	{"climb_down_ladder_right", __CLIMB_DOWN_LADDER_RIGHT},
113 
114 	{"climb_up_ladder_right_to_stand", __CLIMB_UP_LADDER_RIGHT_TO_STAND},
115 	{"climb_down_ladder_right_to_stand", __CLIMB_DOWN_LADDER_RIGHT_TO_STAND},
116 
117 	{"cord_stand_to_climb_up_ladder", __CORD_STAND_TO_CLIMB_UP_LADDER},
118 
119 	{"stand_to_climb_up_ladder_right", __STAND_TO_CLIMB_UP_LADDER_RIGHT},
120 	{"stand_to_climb_down_ladder_right", __STAND_TO_CLIMB_DOWN_LADDER_RIGHT},
121 
122 	{"climb_down_ladder_left_to_slide_down_ladder", __CLIMB_DOWN_LADDER_LEFT_TO_SLIDE_DOWN_LADDER},
123 	{"slide_down_ladder", __SLIDE_DOWN_LADDER},
124 	{"slide_down_ladder_to_stand", __SLIDE_DOWN_LADDER_TO_STAND},
125 
126 	{"load_gun", __LOAD_GUN},
127 	{"load_gun_2", __LOAD_GUN_2},
128 	{"load_gun2", __LOAD_GUN_CROUCH_2},
129 
130 	{"cowering", __COWER},
131 	{"cowering_to_stand", __COWER_TO_STAND},
132 	{"run_hand_through_hair", __HAND_HAIR},
133 	{"shrug", __SHRUG},
134 	{"look_at_watch", __LOOK_AT_WATCH},
135 	{"stretch", __STRETCH},
136 	{"scratching_backside", __SCRATCH},
137 };
138 
139 // these names must be in same order as __weapon
140 char weapon_text[__TOTAL_WEAPONS][MAX_WEAPON_NAME_LENGTH] = {"unarmed", "gun", "crouched", "crouched_gun"};
141 
142 bool8 armed_state_table[__TOTAL_WEAPONS] = {FALSE8, TRUE8, FALSE8, TRUE8};
143 
144 _player_stat player_stat_table[__TOTAL_WEAPONS] = {STOOD, NEW_AIM, CROUCHING, CROUCH_AIM};
145 
146 bool8 crouch_state_table[__TOTAL_WEAPONS] = {FALSE8, FALSE8, TRUE8, TRUE8};
147 
___init(const char * chr,const char * set,__weapon weapon)148 void _vox_image::___init(const char *chr, const char *set, __weapon weapon) {
149 // store these things temporarily so we can recall this function when swapping voxel -> polygon and vice verse...
150 	strcpy(temp_chr, chr);
151 	strcpy(temp_set, set);
152 	temp_weapon = weapon;
153 
154 	// constructor for mega-set-caps class
155 	// resolve the path of the voxel image directory
156 
157 	// we are passed the character name AND the graphic set
158 	// for example, cord, wetsuit
159 
160 	// this object is created by _game_session::fn_set_voxel_image_path
161 
162 	// where chr='cord'
163 	// set='casual_wear'
164 
165 	int32 k, len;
166 
167 	// check for no weapon being set
168 	if (weapon == __NOT_SET)
169 		Fatal_error("WARNING %s does not have a weapon type", MS->Fetch_object_name(MS->Fetch_cur_id()));
170 
171 	palette_hash = NULL_HASH;
172 
173 // get base path
174 	// Make hash filename of the character
175 	char chr_hash[8];
176 	HashFile(chr, chr_hash);
177 
178 	// Make hash filename of the outfit
179 	char set_hash[8];
180 	HashFile(set, set_hash);
181 
182 	// Make the cluster name "\c\<#character>\<#outfit>\outfit.clu"
183 	len = sprintf(base_path, CHR_PATH, chr_hash, set_hash);
184 	if (len > BASE_PATH_STR_LEN)
185 		Fatal_error("_vox_image::___init base_path string too long");
186 	base_path_hash = NULL_HASH;
187 
188 	Zdebug("make base path == %s from %s %s\n", (const char *)base_path, chr, set);
189 
190 	// In the clustered version the image path is the path inside the cluster
191 
192 	len = sprintf(image_path, "%s\\", weapon_text[weapon]);
193 	if (len > IMAGE_PATH_STR_LEN)
194 		Fatal_error("_vox_image::___init image_path [%s] string too long", image_path);
195 
196 	len = sprintf(shadow_mesh_name, "%s", "mesh_shadow.rap");
197 	if (len > IMAGE_PATH_STR_LEN)
198 		Fatal_error("_vox_image::___init shadow_mesh_name [%s] string too long", shadow_mesh_name);
199 
200 	len = sprintf(pose_name, "%s\\pose.rap", weapon_text[weapon]);
201 	if (len > IMAGE_PATH_STR_LEN)
202 		Fatal_error("_vox_image::___init pose_name [%s] string too long", pose_name);
203 
204 	pose_hash = HashString(pose_name);
205 	shadow_mesh_hash = HashString(shadow_mesh_name);
206 
207 	// Make the hash value for this cluster name
208 	base_path_hash = HashString(base_path);
209 
210 	// Make the hash value for this cluster name
211 	base_path_hash = HashString(base_path);
212 
213 	Zdebug("image path == %s\n", (const char *)image_path);
214 	Zdebug("base path == %s\n", (const char *)base_path);
215 
216 	for (k = 0; k < __NON_GENERIC; k++) {
217 		anim_table[k] = (int8)-1;
218 	}
219 
220 	if (((g_mission) && (g_mission->session)) && (MS->Fetch_cur_id() != 999)) {
221 		MS->logic_structs[MS->Fetch_cur_id()]->cur_anim_type = __STAND;
222 		MS->logic_structs[MS->Fetch_cur_id()]->anim_pc = 0;
223 	}
224 
225 	has_custom_path_built = FALSE8; // no custom animation exists
226 
227 	Zdebug("\n-------------------------------------------------------------------------------\n");
228 }
229 
MakeAnimEntry(int32 i)230 void _vox_image::MakeAnimEntry(int32 i) {
231 // make name
232 
233 	char name[ANIM_NAME_STR_LEN];
234 	int32 len;
235 
236 	len = sprintf(name, "%s%s.rab", (const char *)image_path, (const char *)master_anim_name_table[i].name);
237 
238 	if (len > ANIM_NAME_STR_LEN)
239 		Fatal_error("_vox_image::___init [%s] string too long", name);
240 	strcpy(anim_name[i], name);
241 
242 
243 	anim_name_hash[i] = HashString(name);
244 
245 
246 	len = sprintf(name, "%s%s.raj", (const char *)image_path, (const char *)master_anim_name_table[i].name);
247 
248 	if (len > ANIM_NAME_STR_LEN)
249 		Fatal_error("_vox_image::___init [%s] string too long", name);
250 	strcpy(info_name[i], name);
251 
252 
253 	info_name_hash[i] = HashString(name);
254 
255 	// do the test file
256 	anim_table[i] = (int8)(rs_anims->Test_file(get_anim_name(i), anim_name_hash[i], base_path, base_path_hash));
257 }
258 
Init_custom_animation(const char * anim)259 bool8 _vox_image::Init_custom_animation(const char *anim) {
260 	// init a non generic animation in its special __NON_GENERIC slot
261 	// this does not ensure the anim exists
262 	bool8 custom;
263 
264 	char custom_image_path_rav[128];
265 	char custom_image_path_rai[128];
266 
267 	uint32 len;
268 
269 	len = strlen(anim);
270 	uint32 j;
271 	for (j = 0; j < len; j++)
272 		if (Common::isUpper(*(anim + j)))
273 			Fatal_error("Init_custom_animation finds [%s] has upper case letters - implementor must edit the script", anim);
274 
275 	// has anyone been and built the path before?
276 	if (has_custom_path_built) {
277 		has_custom_path_built = FALSE8; // remove it
278 		return (TRUE8);                 // carry on
279 	}
280 
281 	custom = MS->Fetch_custom();
282 
283 	// check for no weapon being set
284 	if (custom == FALSE8 /*__NONE*/) {
285 // custom must be in the current weapon set - bah, shouldnt have done it like this - its daft
286 		// rav (or equiverlant always come from pcp directory...
287 		len = sprintf(custom_image_path_rav, "%s\\", weapon_text[MS->Fetch_cur_megas_pose()]);
288 
289 		// rai (or equiverlant always come from base path...
290 		len = sprintf(custom_image_path_rai, "%s\\", weapon_text[MS->Fetch_cur_megas_pose()]);
291 
292 		// pose mesh name
293 		len = sprintf(custom_pose_name, "%s\\pose.rap", weapon_text[MS->Fetch_cur_megas_pose()]);
294 
295 		custom_pose_hash = HashString(custom_pose_name);
296 	} else {
297 // we have specified a custom type - i.e. the anim is not part of the current weapon set, but instead sits parallel to weapon directory
298 		len = sprintf(custom_image_path_rav, "%s\\", MS->Fetch_cur_megas_custom_text());
299 		len = sprintf(custom_image_path_rai, "%s\\", MS->Fetch_cur_megas_custom_text());
300 		len = sprintf(custom_pose_name, "%s\\pose.rap", MS->Fetch_cur_megas_custom_text());
301 
302 		if (len > 128)
303 			Fatal_error("Init_custom_animation string error");
304 		custom_pose_hash = HashString(custom_pose_name);
305 
306 	}
307 
308 	len = sprintf(anim_name[__NON_GENERIC], "%s%s.rab", (const char *)custom_image_path_rav, (const char *)anim);
309 
310 	if (len > ANIM_NAME_STR_LEN)
311 		Fatal_error("Init_custom_animation string error");
312 	anim_name_hash[__NON_GENERIC] = HashString(anim_name[__NON_GENERIC]);
313 
314 	len = sprintf(info_name[__NON_GENERIC], "%s%s.raj", (const char *)custom_image_path_rai, (const char *)anim);
315 	if (len > ANIM_NAME_STR_LEN)
316 		Fatal_error("Init_custom_animation string error");
317 	info_name_hash[__NON_GENERIC] = HashString(info_name[__NON_GENERIC]);
318 
319 	anim_table[__NON_GENERIC] = 1;
320 
321 	if (!rs_anims->Test_file(get_anim_name(__NON_GENERIC), anim_name_hash[__NON_GENERIC], base_path, base_path_hash)) {
322 		Fatal_error("custom anim [%s,%08x] not found in cluster %s", (const char *)anim_name[__NON_GENERIC], anim_name_hash[__NON_GENERIC], base_path);
323 	}
324 
325 	Zdebug(" created [%s]", (const char *)anim_name[__NON_GENERIC]);
326 
327 	return (TRUE8);
328 }
329 
Promote_non_generic()330 void _vox_image::Promote_non_generic() {
331 	// copy non-generic path to safe __PROMOTED_NON_GENERIC slot
332 	// this is all for psx asyncing
333 
334 	memcpy(&anim_name[__PROMOTED_NON_GENERIC], &anim_name[__NON_GENERIC], ANIM_NAME_STR_LEN);
335 	memcpy(&info_name[__PROMOTED_NON_GENERIC], &info_name[__NON_GENERIC], ANIM_NAME_STR_LEN);
336 
337 	info_name_hash[__PROMOTED_NON_GENERIC] = info_name_hash[__NON_GENERIC];
338 	anim_name_hash[__PROMOTED_NON_GENERIC] = anim_name_hash[__NON_GENERIC];
339 
340 	anim_table[__PROMOTED_NON_GENERIC] = 1; // hack this
341 }
342 
Find_anim_type(__mega_set_names * anim,const char * name)343 bool8 _vox_image::Find_anim_type(__mega_set_names *anim, const char *name) {
344 	uint32 k;
345 
346 	for (k = 0; k < __TOTAL_ANIMS; k++) {
347 		// we must search the table
348 
349 		if (!strcmp(name, master_anim_name_table[k].name)) {
350 			*(anim) = master_anim_name_table[k].ref;
351 			return (TRUE8);
352 		}
353 	}
354 
355 	return (FALSE8);
356 }
357 
Start_generic_ascii_anim(const char * ascii_name)358 bool8 _game_session::Start_generic_ascii_anim(const char *ascii_name) {
359 	// search for named anim and setup if found
360 	uint32 k;
361 
362 	// search for the named generic anim - cant use __ANIM_NAME from script unfortunately
363 	for (k = 0; k < __TOTAL_ANIMS; k++) {
364 		// we must search the table
365 
366 		if (!strcmp(const_cast<char *>(ascii_name), master_anim_name_table[k].name)) {
367 			Zdebug("  Start_generic_ascii_anim found [%s]", ascii_name);
368 
369 			L->cur_anim_type = master_anim_name_table[k].ref;
370 			L->anim_pc = 0;
371 
372 			// Check to see if this anim exists on the hard drive
373 			// Note this will also make the name entry correctly if the name hasn't already
374 			// been made
375 			if (I->IsAnimTable(L->cur_anim_type) == (int8)-1)
376 				return (FALSE8);
377 
378 			return (TRUE8);
379 		}
380 	}
381 
382 	Zdebug("nightmare!");
383 
384 	return (FALSE8);
385 }
386 
Fetch_generic_anim_from_ascii(const char * ascii_name)387 __mega_set_names _game_session::Fetch_generic_anim_from_ascii(const char *ascii_name) {
388 	// pass name of a generic anim and return the type
389 	uint32 k;
390 
391 	// search for the named generic anim - cant use __ANIM_NAME from script unfortunately
392 	for (k = 0; k < __TOTAL_ANIMS; k++) {
393 		if (!strcmp(const_cast<char *>(ascii_name), master_anim_name_table[k].name)) {
394 			// found!
395 			if (I->IsAnimTable(L->cur_anim_type) == (int8)-1)
396 				Fatal_error("Fetch_generic_anim_from_ascii cant find on drive %s", ascii_name);
397 			return (master_anim_name_table[k].ref);
398 		}
399 	}
400 
401 	Fatal_error("Fetch_generic_anim_from_ascii cant find %s", ascii_name);
402 	return __NON_GENERIC;
403 }
404 
405 void PreRegisterTexture(const char *, uint32, const char *, uint32, const char *, uint32);
406 
Set_texture(const char * tex_name)407 bool8 _vox_image::Set_texture(const char *tex_name) {
408 	int32 len;
409 
410 	len = sprintf(texture_name, "%s.revtex", tex_name);
411 
412 	if (len > IMAGE_PATH_STR_LEN)
413 		Fatal_error("_vox_image::Set_texture [%s] string too long", tex_name);
414 
415 	texture_hash = HashString(texture_name);
416 
417 	// set palette to be same as texture
418 
419 	strcpy(palette_name, texture_name);
420 	palette_hash = texture_hash;
421 
422 	// okay preload the texture/palette combo
423 	PreRegisterTexture(texture_name, texture_hash, palette_name, palette_hash, base_path, base_path_hash);
424 
425 	return TRUE8;
426 }
427 
Set_mesh(const char * m_name)428 bool8 _vox_image::Set_mesh(const char *m_name) {
429 	char name[32];
430 	int32 len;
431 
432 	strcpy(name, m_name);
433 	strcat(name, ".rap");
434 
435 	len = sprintf(mesh_name, "%s", name);
436 	if (len > IMAGE_PATH_STR_LEN)
437 		Fatal_error("_vox_image::___init mesh_name [%s] string too long", mesh_name);
438 
439 	mesh_hash = HashString(mesh_name);
440 	return TRUE8;
441 }
442 
Set_palette(const char * pal_name)443 bool8 _vox_image::Set_palette(const char *pal_name) {
444 	// Ignore the default_palette : this is yucky and hacky but it is the end of the project so tough luck
445 	if (strcmp(pal_name, "default") == 0) {
446 		palette_hash = NULL_HASH;
447 		return TRUE8;
448 	}
449 
450 	int32 len;
451 
452 	len = sprintf(palette_name, "%s.revtex", pal_name);
453 
454 	if (len > IMAGE_PATH_STR_LEN)
455 		Fatal_error("_vox_image::Set_palette [%s] string too long", pal_name);
456 
457 	palette_hash = HashString(palette_name);
458 
459 	// okay preload the texture/palette combo
460 	PreRegisterTexture(texture_name, texture_hash, palette_name, palette_hash, base_path, base_path_hash);
461 
462 	return TRUE8;
463 }
464 
465 } // End of namespace ICB
466