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