/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "m4/burger/walker.h"
#include "m4/adv_r/adv_control.h"
#include "m4/burger/vars.h"
#include "m4/core/imath.h"
#include "m4/graphics/gr_series.h"
namespace M4 {
namespace Burger {
// Starting hashes for walker machines/sequences/etc */
#define WALKER_HASH 8 // machine/data starting hash for wilbur
#define WALKER_SERIES_HASH 0
#define NUM_WALKER_SERIES 8
#define SHADOW_SERIES_HASH 8
#define NUM_SHADOW_SERIES 5
// These are the walker types
#define WALKER_PLAYER 0
#define WALKER_ALT 1
// These are the shadow types
#define SHADOW_PLAYER 0
#define SHADOW_ALT 1
static const char *WILBUR_SERIES[8] = {
"WILBUR01", "WILBUR02", "WILBUR03", "WILBUR04", "WILBUR05",
"WILBUR07", "WILBUR08", "WILBUR09"
};
static const int16 WILBUR_SERIES_DIRS[] = {
0, 1, 2, 3, 4, 5, 6, 7, -1
};
static const char *WILBUR_SHADOWS[5] = {
"WILBUR01_SHADOW", "WILBUR02_SHADOW", "WILBUR03_SHADOW",
"WILBUR04_SHADOW", "WILBUR05_SHADOW"
};
static const int16 WILBUR_SHADOWS_DIRS[6] = {
8, 9, 10, 11, 12, -1
};
void Walker::player_walker_callback(frac16 myMessage, machine *sender) {
int32 triggerType, soundNumber;
triggerType = _G(globals)[GLB_TEMP_1] >> 16;
switch (triggerType) {
case 0:
// Ignore this trigger, it's not important
break;
case 1:
// Specific action is finished
// If user trigger is desired, dispatch it
if (myMessage >> 16 >= 0)
// Trigger will go to where it was called from
kernel_trigger_dispatchx(myMessage);
break;
case 2:
// Walker has arrived at a node
if (walker_has_walk_finished(sender)) {
// Walks walker to next node if not at end of walk
sendWSMessage(ENDWALK << 16, 0, sender, 0, nullptr, 1);
}
break;
case 3:
// Walker has finished his walk and is facing final direction
_G(player).waiting_for_walk = false;
// if user trigger is desired, dispatch it
if (myMessage >> 16 >= 0)
// trigger will go to where it was called from
kernel_trigger_dispatchx(myMessage);
break;
case 20:
// Walker wants to make a sound
soundNumber = myMessage >> 16;
switch (soundNumber) {
case 21:
case 22:
case 25:
if (!_G(flags)[kDisableFootsteps])
_G(digi).playFootsteps();
break;
case 23:
switch (imath_ranged_rand(1, 3)) {
case 1:
digi_play("crack1", 1, 50, NO_TRIGGER, GLOBAL_SCENE);
break;
case 2:
digi_play("crack2", 1, 60, NO_TRIGGER, GLOBAL_SCENE);
break;
case 3:
digi_play("crack3", 1, 80, NO_TRIGGER, GLOBAL_SCENE);
break;
default:
break;
}
break;
case 24:
if (!_G(flags)[kDisableFootsteps])
digi_play("hmmm", 1, 60, NO_TRIGGER, GLOBAL_SCENE);
break;
default:
break;
}
break;
default:
_G(player).waiting_for_walk = false;
break;
}
}
bool Walker::walk_load_walker_and_shadow_series() {
return ws_walk_load_walker_series(WILBUR_SERIES_DIRS, WILBUR_SERIES, true) &&
ws_walk_load_shadow_series(WILBUR_SHADOWS_DIRS, WILBUR_SHADOWS);
}
machine *Walker::walk_initialize_walker() {
machine *m;
int32 s;
if (!_G(player).walker_in_this_scene) {
_G(player).walker_visible = false;
m = nullptr;
} else {
_G(player).walker_visible = true;
// Wilbur walker
_G(player).walker_type = WALKER_PLAYER;
_G(player).shadow_type = SHADOW_PLAYER;
_G(globals)[GLB_TEMP_1] = _G(player).walker_type << 16;
_G(globals)[GLB_TEMP_2] = WALKER_SERIES_HASH << 24; // starting series hash of default walker GAMECTRL loads shadows starting @ 0
_G(globals)[GLB_TEMP_3] = SHADOW_SERIES_HASH << 24; // starting series hash of default walker shadows. GAMECTRL loads shadows starting @ 10
// initialize with bogus data (this is for the real walker)
s = _G(globals)[GLB_MIN_SCALE] + FixedMul((400 << 16) - _G(globals)[GLB_MIN_Y], _G(globals)[GLB_SCALER]);
_G(globals)[GLB_TEMP_4] = static_cast(-320) << 16;
_G(globals)[GLB_TEMP_5] = 400 << 16;
_G(globals)[GLB_TEMP_6] = s;
_G(globals)[GLB_TEMP_7] = 3 << 16; // facing
m = TriggerMachineByHash(WALKER_HASH, nullptr, _G(player).walker_type + WALKER_HASH, 0, player_walker_callback, false, "Wilbur Walker");
// we need to all init sequences to happen immediately (init coordinates)
cycleEngines(nullptr, &(_G(currentSceneDef).depth_table[0]),
nullptr, (uint8 *)&_G(master_palette)[0], _G(inverse_pal)->get_ptr(), true);
_G(inverse_pal)->release();
}
return m;
}
void Walker::reset_walker_sprites() {
if (_G(roomVal3)) {
for (int i = 0; WILBUR_SERIES_DIRS[i] != -1; ++i) {
series_load(WILBUR_SERIES[i], WILBUR_SERIES_DIRS[i]);
}
}
ws_unhide_walker(_G(my_walker));
gr_restore_palette();
kernel_timing_trigger(1, 1026);
}
void Walker::unloadSprites() {
if (_G(player).walker_in_this_scene) {
term_message("Unloading Wilbur walker...");
player_update_info();
// Send message for the unload
sendWSMessage(0x60000, 0, _G(my_walker), 0, nullptr, 1);
_G(player).walker_in_this_scene = false;
for (int i = 0; i < 7; ++i)
series_unload(i);
_G(my_walker) = nullptr;
}
}
void Walker::wilbur_speech(const char *name, int trigger, int room, byte flags, int vol, int channel) {
KernelTriggerType oldMode = _G(kernel).trigger_mode;
_name = name;
_channel = channel;
_room = room;
_vol = vol;
_trigger = kernel_trigger_create(trigger);
_animateLips = (flags & 1) == 0;
_G(kernel).trigger_mode = KT_DAEMON;
kernel_trigger_dispatch_now(kWILBURS_SPEECH_START);
_G(kernel).trigger_mode = oldMode;
}
void Walker::wilbur_say() {
KernelTriggerType oldMode = _G(kernel).trigger_mode;
if (_animateLips && _G(player).walker_in_this_scene && _G(player).walker_visible)
sendWSMessage(0x140000, 0, _G(my_walker), 0, 0, 1);
term_message("wilbur_say: wilburs_talk_trigger = %d", _trigger);
digi_stop(_channel);
_G(kernel).trigger_mode = KT_DAEMON;
kernel_trigger_dispatch_now(kWILBUR_SPEECH_STARTED);
digi_play(_name, _channel, _vol, kWILBURS_SPEECH_FINISHED, _room);
_G(kernel).trigger_mode = oldMode;
}
bool Walker::wilbur_said(const char *list[][4]) {
if (!list)
return false;
for (int index = 0; list[index][0]; ++index) {
if (player_said(list[index][0])) {
if (player_said("look at") && list[index][1]) {
wilbur_speech(list[index][1]);
return true;
} else if (player_said("take") && list[index][2]) {
wilbur_speech(list[index][2]);
return true;
} else if (player_said("gear") && list[index][3]) {
wilbur_speech(list[index][3]);
return true;
} else {
return false;
}
}
}
return false;
}
void Walker::wilburs_speech_finished() {
if (_animateLips && _G(player).walker_in_this_scene && _G(player).walker_visible)
sendWSMessage(0x150000, 0, _G(my_walker), 0, 0, 1);
term_message("wilburs_speech_finished: dispatching wilburs_talk_trigger = %d", _trigger);
kernel_trigger_dispatchx(_trigger);
}
void enable_player() {
player_set_commands_allowed(true);
ws_unhide_walker(_G(my_walker));
}
void disable_player() {
player_set_commands_allowed(false);
ws_hide_walker(_G(my_walker));
}
void wilbur_abduct(int trigger) {
player_set_commands_allowed(false);
digi_stop(1);
if (_G(executing) == INTERACTIVE_DEMO) {
_G(game).setRoom(608);
return;
}
digi_preload("999_004");
if (_G(my_walker) && _G(player).walker_in_this_scene && _G(player).walker_visible) {
player_update_info();
switch (_G(player_info).facing) {
case 1:
case 2:
series_play("999ab02", _G(player_info).depth, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
series_play("999ab02s", _G(player_info).depth + 1, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
break;
case 3:
case 4:
case 5:
series_play("999ab04", _G(player_info).depth, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
series_play("999ab04s", _G(player_info).depth + 1, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
break;
case 7:
case 8:
case 9:
series_play("999ab08", _G(player_info).depth, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
series_play("999ab08s", _G(player_info).depth + 1, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
break;
case 10:
case 11:
series_play("999ab10", _G(player_info).depth, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
series_play("999ab10s", _G(player_info).depth + 1, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
break;
default:
series_play("999ab02", _G(player_info).depth, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
series_play("999ab02s", _G(player_info).depth + 1, 0, -1, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
break;
}
ws_hide_walker();
}
digi_play("999_004", 2, 255, -1);
kernel_timing_trigger_daemon(180, trigger);
if (!_G(flags)[V154] || imath_rand_bool(5)) {
digi_preload("402w005z");
digi_play("402w005z", 1, 255, -1);
_G(flags)[V154] = 1;
}
}
void Walker::speech_random(int count, int trigger,
const char *name1, const char *name2, const char *name3,
const char *name4, const char *name5, const char *name6,
const char *name7, const char *name8, const char *name9) {
const char *names[9] = {
name1, name2, name3, name4, name5, name6, name7, name8, name9
};
wilbur_speech(names[imath_ranged_rand(1, count) - 1], trigger);
}
bool Walker::wilbur_parser(const char **list) {
for (const char **curr = list; *curr; ++curr) {
if (player_said(*curr)) {
// Found section for the item
bool useDefault = true;
++curr;
while (*curr) {
const char *action = *curr++;
const char *sound = *curr++;
if (player_said(action)) {
// Found the action on the item we want
if (sound) {
// Has a sound
wilbur_speech(sound);
return true;
} else {
// No sound for this
useDefault = false;
}
}
}
// Check default fallback
const char *defaultSound = *++curr;
if (defaultSound && useDefault) {
wilbur_speech(defaultSound);
return true;
}
// Skip past the item end entry
++curr;
} else {
// Not the item we want, so skip the section
for (; !*curr || scumm_stricmp(*curr, PARSER_ITEM_END); ++curr) {
}
}
}
return false;
}
bool Walker::wilbur_match(const WilburMatch *list) {
for (; list->_word0 || list->_word1; ++list) {
const WilburMatch &m = *list;
if (player_said(m._word0, m._word1)) {
term_message("matched %s and %s", m._word0, m._word1);
term_message("test variable:%d value:%d",
m._testVariable ? *m._testVariable : 0, m._testValue);
if (!m._testVariable || *m._testVariable == m._testValue) {
if (m._newVariable)
*m._newVariable = m._newValue;
if (m._trigger != -1)
kernel_trigger_dispatch_now(m._trigger);
return true;
}
}
}
return false;
}
void Walker::wilbur_poof() {
player_update_info();
_wilburPoof = series_load("999poof");
series_play("999poof", _G(player_info).depth, 0, kUNPOOF, 6, 0,
_G(player_info).scale, _G(player_info).x, _G(player_info).y);
digi_play("999_003", 1, 255);
}
void Walker::wilbur_unpoof() {
series_unload(_wilburPoof);
_wilburPoof = -1;
}
void player_walk_to(int32 x, int32 y, int32 facing_x, int32 facing_y, int trigger) {
_G(player_facing_x) = facing_x;
_G(player_facing_y) = facing_y;
_G(player_trigger) = trigger;
player_hotspot_walk_override(x, y, -1, kSET_FACING);
}
void player_walk_to(int32 x, int32 y, int trigger) {
player_walk_to(x, y, _G(player).click_x, _G(player).click_y, trigger);
}
void wilbur_speech(const char *name, int trigger, int room, byte flags,
int vol, int channel) {
_G(walker).wilbur_speech(name, trigger, room, flags, vol, channel);
}
} // namespace Burger
} // namespace M4