838 lines
18 KiB
C++
838 lines
18 KiB
C++
/* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "m4/adv_r/conv_io.h"
|
|
#include "m4/adv_r/adv_control.h"
|
|
#include "m4/adv_r/conv.h"
|
|
#include "m4/adv_r/chunk_ops.h"
|
|
#include "m4/adv_r/db_env.h"
|
|
#include "m4/core/errors.h"
|
|
#include "m4/vars.h"
|
|
#include "m4/m4.h"
|
|
|
|
namespace M4 {
|
|
|
|
#define NAME_SIZE (g_engine->getGameType() == GType_Riddle ? 12 : 8)
|
|
|
|
#define HIDDEN 0x00000004
|
|
#define DESTROYED 0x00000008
|
|
|
|
#define INITIAL 1
|
|
#define PERSISTENT 2
|
|
|
|
#define CONV_OK 0
|
|
#define CONV_QUIT -1
|
|
#define CONV_NEW -2
|
|
#define CONV_BAIL -3
|
|
|
|
#define CONV_UNKNOWN_MODE 0
|
|
#define CONV_GET_TEXT_MODE 1
|
|
#define CONV_SET_TEXT_MODE 2
|
|
#define CONV_GET_MESG_MODE 3
|
|
#define CONV_UPDATE_MODE 4
|
|
|
|
#define DECL_POINTER 1
|
|
|
|
void Converstation_Globals::syncGame(Common::Serializer &s) {
|
|
if (s.isLoading())
|
|
conv_reset_all();
|
|
|
|
// Handle size
|
|
uint32 count = convSave.size();
|
|
s.syncAsUint32LE(count);
|
|
if (s.isLoading())
|
|
convSave.resize(count);
|
|
|
|
// Sync buffer contents
|
|
if (count)
|
|
s.syncBytes(&convSave[0], count);
|
|
}
|
|
|
|
void Converstation_Globals::conv_reset_all() {
|
|
convSave.clear();
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void cdd_init() {
|
|
for (int i = 0; i < 16; i++) {
|
|
_G(cdd).text[i] = nullptr;
|
|
_G(cdd).snd_files[i] = nullptr;
|
|
}
|
|
|
|
_G(cdd).num_txt_ents = 0;
|
|
Common::strcpy_s(_G(cdd).mesg, "");
|
|
_G(cdd).mesg_snd_file = nullptr;
|
|
}
|
|
|
|
Conv *conv_get_handle(void) {
|
|
return _GC(globConv);
|
|
}
|
|
|
|
void conv_set_handle(Conv *c) {
|
|
_GC(globConv) = c;
|
|
}
|
|
|
|
void conv_resume(Conv *c) {
|
|
conv_go(c);
|
|
}
|
|
|
|
void conv_resume() {
|
|
conv_resume(conv_get_handle());
|
|
}
|
|
|
|
int conv_is_event_ready() {
|
|
return _GC(event_ready);
|
|
}
|
|
|
|
void conv_set_event(int e) {
|
|
_GC(event) = e;
|
|
_GC(event_ready) = 1;
|
|
}
|
|
|
|
int conv_get_event() {
|
|
_GC(event_ready) = 0;
|
|
return _GC(event);
|
|
}
|
|
|
|
void conv_play(Conv *c) {
|
|
conv_go(c);
|
|
}
|
|
|
|
void conv_play() {
|
|
conv_play(conv_get_handle());
|
|
}
|
|
|
|
int32 conv_current_node() {
|
|
if (conv_get_handle())
|
|
return conv_get_handle()->node_hash;
|
|
return 0;
|
|
}
|
|
|
|
int32 conv_current_entry() {
|
|
return _GC(ent) - 1;
|
|
}
|
|
|
|
void conv_reset(const char *filename) {
|
|
_GC(restore_conv) = 0;
|
|
|
|
Conv *c = conv_load(filename, 1, 1, -1, false);
|
|
conv_unload(c);
|
|
}
|
|
|
|
|
|
void conv_reset_all() {
|
|
_G(conversations).conv_reset_all();
|
|
}
|
|
|
|
const char *conv_sound_to_play() {
|
|
return _G(cdd).mesg_snd_file;
|
|
}
|
|
|
|
int32 conv_whos_talking() {
|
|
return _G(cdd).player_non_player;
|
|
}
|
|
|
|
int ok_status(entry_chunk *entry) {
|
|
if (entry->status & DESTROYED)
|
|
return 0;
|
|
|
|
if (entry->status & HIDDEN)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int conv_toggle_flags(entry_chunk *entry) {
|
|
if (ok_status(entry))
|
|
return (entry->status & 0x0000000e); //mask off INITIAL bit.
|
|
return entry->status;
|
|
}
|
|
|
|
int32 conv_get_decl_val(Conv *c, decl_chunk *decl) {
|
|
if (decl->flags == DECL_POINTER)
|
|
return *c->_pointers[decl->addrIndex];
|
|
|
|
return decl->val;
|
|
}
|
|
|
|
void conv_set_decl_val(Conv *c, decl_chunk *decl, int32 val) {
|
|
if (decl->flags == DECL_POINTER) {
|
|
decl->val = val;
|
|
*c->_pointers[decl->addrIndex] = val;
|
|
} else {
|
|
decl->val = val;
|
|
}
|
|
}
|
|
|
|
void conv_export_value(Conv *c, int32 val, int index) {
|
|
int32 tag = 0, next;
|
|
int i = 0;
|
|
|
|
if (!c)
|
|
return;
|
|
|
|
const int32 ent_old = c->myCNode;
|
|
int32 ent = 0;
|
|
c->myCNode = 0;
|
|
|
|
while (ent < c->chunkSize) {
|
|
conv_ops_get_entry(ent, &next, &tag, c);
|
|
|
|
if (tag == DECL_CHUNK) {
|
|
if (i == index) {
|
|
decl_chunk *decl = get_decl(c, ent);
|
|
conv_set_decl_val(c, decl, val);
|
|
}
|
|
i++;
|
|
}
|
|
ent = next;
|
|
}
|
|
c->myCNode = ent_old;
|
|
}
|
|
|
|
void conv_export_value_curr(int32 val, int index) {
|
|
conv_export_value(conv_get_handle(), val, index);
|
|
}
|
|
|
|
void conv_export_pointer(Conv *c, int32 *val, int index) {
|
|
int32 tag = 0, next;
|
|
int i = 0;
|
|
|
|
if (!c)
|
|
return;
|
|
|
|
const int32 ent_old = c->myCNode;
|
|
int32 ent = 0;
|
|
c->myCNode = 0;
|
|
|
|
while (ent < c->chunkSize) {
|
|
conv_ops_get_entry(ent, &next, &tag, c);
|
|
|
|
switch (tag) {
|
|
case DECL_CHUNK:
|
|
if (i == index) {
|
|
decl_chunk *decl = get_decl(c, ent);
|
|
|
|
c->_pointers.push_back(val);
|
|
decl->addrIndex = c->_pointers.size() - 1;
|
|
decl->flags = DECL_POINTER;
|
|
}
|
|
i++;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
ent = next;
|
|
}
|
|
c->myCNode = ent_old;
|
|
}
|
|
|
|
void conv_export_pointer_curr(int32 *val, int index) {
|
|
conv_export_pointer(conv_get_handle(), val, index);
|
|
}
|
|
|
|
void conv_init(Conv *c) {
|
|
switch (c->exit_now) {
|
|
case CONV_OK:
|
|
case CONV_QUIT:
|
|
break;
|
|
|
|
case CONV_BAIL:
|
|
case CONV_NEW:
|
|
if (c->myCNode != CONV_QUIT) {
|
|
c->exit_now = CONV_NEW; //conv hasn't been run before. only done here once.
|
|
c->myCNode = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int32 find_state(const char *s, char *c, int file_size) {
|
|
char name[13];
|
|
int32 size = 0, offset = 0;
|
|
|
|
while (offset < file_size) {
|
|
Common::strcpy_s(name, &c[offset]);
|
|
|
|
if (!scumm_stricmp(name, s)) {
|
|
offset += NAME_SIZE * sizeof(char);
|
|
goto handled;
|
|
}
|
|
|
|
offset += NAME_SIZE * sizeof(char);
|
|
if (offset < file_size) {
|
|
memcpy(&size, &c[offset], sizeof(int32));
|
|
}
|
|
|
|
offset += size + sizeof(int32);
|
|
}
|
|
|
|
offset = -1;
|
|
|
|
handled:
|
|
return offset;
|
|
}
|
|
|
|
void find_and_set_conv_name(Conv *c) {
|
|
int32 ent = 0, tag = 0, next = 0;
|
|
|
|
c->myCNode = 0;
|
|
|
|
while (ent < c->chunkSize) {
|
|
conv_ops_get_entry(ent, &next, &tag, c);
|
|
|
|
if (tag == CONV_CHUNK) {
|
|
conv_chunk *conv = get_conv(c, ent);
|
|
assert(conv);
|
|
Common::strcpy_s(_GC(conv_name), get_string(c, c->myCNode + ent + sizeof(conv_chunk)));
|
|
}
|
|
ent = next;
|
|
}
|
|
}
|
|
|
|
static void conv_save_state(Conv *c) {
|
|
//-------------------------------------------------------------------------------
|
|
// Calculate amt_to_write by counting up the size of DECL_CHUNKs.
|
|
// the number of ENTRY_CHUNKs affects the amt_to_write
|
|
// also extract fname from the CONV_CHUNK
|
|
|
|
int32 amt_to_write = 3 * sizeof(int32); // Header size
|
|
int32 ent = 0;
|
|
int32 next, tag; // receive conv_ops_get_entry results
|
|
const int32 myCNode = c->myCNode;
|
|
char fname[13];
|
|
memset(fname, 0, 13);
|
|
|
|
int32 num_decls = 0;
|
|
int32 num_entries = 0;
|
|
|
|
c->myCNode = 0;
|
|
|
|
while (ent < c->chunkSize) {
|
|
conv_chunk *conv;
|
|
conv_ops_get_entry(ent, &next, &tag, c);
|
|
|
|
switch (tag) {
|
|
case CONV_CHUNK:
|
|
conv = get_conv(c, ent);
|
|
assert(conv);
|
|
Common::strcpy_s(fname, get_string(c, c->myCNode + ent + sizeof(conv_chunk)));
|
|
break;
|
|
|
|
case DECL_CHUNK:
|
|
num_decls++;
|
|
amt_to_write += sizeof(int32);
|
|
break;
|
|
|
|
case ENTRY_CHUNK:
|
|
num_entries++;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
ent = next;
|
|
}
|
|
|
|
amt_to_write += (num_entries / 8) * sizeof(int32);
|
|
if ((num_entries % 8) != 0)
|
|
amt_to_write += sizeof(int32); // Pad the sucker
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// if consave data exists, read it in
|
|
|
|
int32 file_size = 0;
|
|
int32 offset;
|
|
char *conv_save_buff;
|
|
bool overwrite_file = false;
|
|
|
|
if (!_GC(convSave).empty()) {
|
|
file_size = _GC(convSave).size();
|
|
|
|
conv_save_buff = (char *)mem_alloc(file_size, "conv save buff");
|
|
if (!conv_save_buff)
|
|
error_show(FL, 'OOM!');
|
|
|
|
Common::copy(&_GC(convSave)[0], &_GC(convSave)[0] + file_size, &conv_save_buff[0]);
|
|
|
|
//----------------------------------------------------------------------------
|
|
// If this conversation already in conv data, overwrite it,
|
|
// otherwise chuck out the buffer, and create a new buffer which is just
|
|
// big enough to hold the new save data.
|
|
|
|
offset = find_state(fname, conv_save_buff, file_size);
|
|
|
|
if (offset != -1) {
|
|
overwrite_file = true;
|
|
/* int32 prev_size = */ READ_LE_UINT32(&conv_save_buff[offset]);
|
|
/* prev_size += NAME_SIZE + sizeof(int32);*/
|
|
offset += sizeof(int32); // Skip header. (name + size)
|
|
} else {
|
|
// Append
|
|
offset = 0;
|
|
|
|
mem_free(conv_save_buff);
|
|
conv_save_buff = (char *)mem_alloc(amt_to_write + NAME_SIZE + sizeof(int32), "conv save buff");
|
|
if (!conv_save_buff)
|
|
error_show(FL, 'OOM!');
|
|
|
|
memcpy(&conv_save_buff[offset], fname, NAME_SIZE * sizeof(char));
|
|
offset += NAME_SIZE * sizeof(char);
|
|
WRITE_LE_UINT32(&conv_save_buff[offset], amt_to_write);
|
|
offset += sizeof(int32);
|
|
}
|
|
} else {
|
|
//----------------------------------------------------------------------------
|
|
// Conv save dat didn't exist, so we set things up for a create here.
|
|
|
|
offset = 0;
|
|
|
|
conv_save_buff = (char *)mem_alloc(amt_to_write + NAME_SIZE + sizeof(int32), "conv save buff");
|
|
if (!conv_save_buff)
|
|
error_show(FL, 'OOM!');
|
|
|
|
memcpy(&conv_save_buff[offset], fname, NAME_SIZE * sizeof(char));
|
|
offset += NAME_SIZE * sizeof(char);
|
|
WRITE_LE_UINT32(&conv_save_buff[offset], amt_to_write);
|
|
offset += sizeof(int32);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// finish filling in conv_save_buff data with num of entries etc.
|
|
|
|
WRITE_LE_INT32(&conv_save_buff[offset], myCNode);
|
|
offset += sizeof(int32);
|
|
|
|
WRITE_LE_UINT32(&conv_save_buff[offset], num_decls);
|
|
offset += sizeof(int32);
|
|
|
|
WRITE_LE_UINT32(&conv_save_buff[offset], num_entries);
|
|
offset += sizeof(int32);
|
|
|
|
int32 size = 3 * sizeof(int32);
|
|
|
|
// fill in all the entries themselves
|
|
|
|
int32 e_flags = 0;
|
|
short flag_index = 0;
|
|
|
|
ent = 0;
|
|
c->myCNode = 0;
|
|
|
|
int32 val;
|
|
entry_chunk *entry;
|
|
|
|
while (ent < c->chunkSize) {
|
|
conv_ops_get_entry(ent, &next, &tag, c);
|
|
decl_chunk *decl;
|
|
|
|
switch (tag) {
|
|
case DECL_CHUNK:
|
|
decl = get_decl(c, ent);
|
|
val = conv_get_decl_val(c, decl);
|
|
|
|
WRITE_LE_UINT32(&conv_save_buff[offset], val);
|
|
offset += sizeof(int32);
|
|
size += sizeof(int32);
|
|
break;
|
|
|
|
case LNODE_CHUNK:
|
|
case NODE_CHUNK:
|
|
break;
|
|
|
|
case ENTRY_CHUNK:
|
|
entry = get_entry(c, ent);
|
|
|
|
if (flag_index == 32) {
|
|
flag_index = 0;
|
|
|
|
WRITE_LE_UINT32(&conv_save_buff[offset], e_flags);
|
|
offset += sizeof(int32);
|
|
size += sizeof(int32);
|
|
|
|
e_flags = 0;
|
|
}
|
|
|
|
e_flags |= ((entry->status & 0x0000000f) << flag_index);
|
|
|
|
flag_index += 4;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ent = next;
|
|
}
|
|
|
|
// Copy the flags
|
|
if (flag_index != 0) {
|
|
WRITE_LE_UINT32(&conv_save_buff[offset], e_flags);
|
|
// offset += sizeof(int32);
|
|
size += sizeof(int32);
|
|
}
|
|
|
|
if (amt_to_write != size)
|
|
error_show(FL, 'CNVS', "save_state: error! size written != size (%d %d)", amt_to_write, size);
|
|
|
|
// Finally, write out the conversation data
|
|
if (overwrite_file == true) {
|
|
_GC(convSave).resize(file_size);
|
|
Common::copy(conv_save_buff, conv_save_buff + file_size, &_GC(convSave)[0]);
|
|
|
|
} else {
|
|
// Append conversation
|
|
const size_t oldSize = _GC(convSave).size();
|
|
file_size = amt_to_write + NAME_SIZE + sizeof(int32);
|
|
|
|
_GC(convSave).resize(_GC(convSave).size() + file_size);
|
|
Common::copy(conv_save_buff, conv_save_buff + file_size, &_GC(convSave)[oldSize]);
|
|
}
|
|
|
|
mem_free(conv_save_buff);
|
|
}
|
|
|
|
static Conv *conv_restore_state(Conv *c) {
|
|
int32 tag, next;
|
|
|
|
short flag_index = 0;
|
|
int32 val;
|
|
int32 e_flags = 0;
|
|
int32 myCNode;
|
|
|
|
char fname[13];
|
|
int file_size;
|
|
|
|
int32 ent;
|
|
c->myCNode = 0;
|
|
|
|
find_and_set_conv_name(c);
|
|
Common::strcpy_s(fname, _GC(conv_name));
|
|
|
|
if (_GC(convSave).empty())
|
|
file_size = -1;
|
|
else
|
|
file_size = _GC(convSave).size();
|
|
|
|
if (file_size <= 0) {
|
|
conv_init(c);
|
|
return c;
|
|
}
|
|
|
|
char *conv_save_buff = (char *)mem_alloc(file_size, "conv save buff");
|
|
if (!conv_save_buff)
|
|
error_show(FL, 'OOM!');
|
|
|
|
// ------------------
|
|
|
|
Common::copy(&_GC(convSave)[0], &_GC(convSave)[0] + file_size, &conv_save_buff[0]);
|
|
int32 offset = find_state(fname, conv_save_buff, file_size);
|
|
|
|
if (offset == -1)
|
|
goto i_am_so_done;
|
|
|
|
// Skip header.
|
|
offset += sizeof(int32);
|
|
|
|
myCNode = READ_LE_INT32(&conv_save_buff[offset]);
|
|
offset += sizeof(int32);
|
|
|
|
/*int num_decls = */READ_LE_UINT32(&conv_save_buff[offset]);
|
|
offset += sizeof(int32);
|
|
|
|
/*int num_entries = */READ_LE_UINT32(&conv_save_buff[offset]);
|
|
offset += sizeof(int32);
|
|
|
|
ent = 0; c->myCNode = 0;
|
|
|
|
while (ent < c->chunkSize) {
|
|
conv_ops_get_entry(ent, &next, &tag, c);
|
|
|
|
if (tag == DECL_CHUNK) {
|
|
val = READ_LE_UINT32(&conv_save_buff[offset]);
|
|
offset += sizeof(int32);
|
|
decl_chunk *decl = get_decl(c, ent);
|
|
|
|
conv_set_decl_val(c, decl, val);
|
|
}
|
|
|
|
ent = next;
|
|
}
|
|
|
|
ent = 0;
|
|
c->myCNode = 0;
|
|
|
|
while (ent < c->chunkSize) {
|
|
conv_ops_get_entry(ent, &next, &tag, c);
|
|
|
|
if (tag == ENTRY_CHUNK) {
|
|
entry_chunk *entry = get_entry(c, ent);
|
|
|
|
if (flag_index == 32) {
|
|
flag_index = 0;
|
|
//flag_num++;
|
|
}
|
|
|
|
if (flag_index == 0) {
|
|
e_flags = READ_LE_UINT32(&conv_save_buff[offset]);
|
|
offset += sizeof(int32);
|
|
}
|
|
|
|
val = (e_flags >> flag_index) & 0x0000000f;
|
|
entry->status = val;
|
|
|
|
flag_index += 4;
|
|
}
|
|
|
|
ent = next;
|
|
}
|
|
|
|
c->myCNode = myCNode;
|
|
if (c->myCNode == CONV_QUIT) {
|
|
c->exit_now = CONV_QUIT;
|
|
|
|
conv_unload(c);
|
|
c = nullptr;
|
|
} else
|
|
c->exit_now = CONV_OK;
|
|
|
|
i_am_so_done:
|
|
|
|
mem_free(conv_save_buff);
|
|
return c;
|
|
}
|
|
|
|
void conv_set_font_spacing(int32 h, int32 v) {
|
|
_GC(conv_font_spacing_h) = h;
|
|
_GC(conv_font_spacing_v) = v;
|
|
}
|
|
|
|
|
|
void conv_set_text_colours(int32 norm_colour, int32 norm_colour_alt1, int32 norm_colour_alt2,
|
|
int32 hi_colour, int32 hi_colour_alt1, int32 hi_colour_alt2) {
|
|
_GC(conv_normal_colour) = norm_colour;
|
|
_GC(conv_normal_colour_alt1) = norm_colour_alt1;
|
|
_GC(conv_normal_colour_alt2) = norm_colour_alt2;
|
|
_GC(conv_hilite_colour) = hi_colour;
|
|
_GC(conv_hilite_colour_alt1) = hi_colour_alt1;
|
|
_GC(conv_hilite_colour_alt2) = hi_colour_alt2;
|
|
}
|
|
|
|
void conv_set_text_colour(int32 norm_colour, int32 hi_colour) {
|
|
conv_set_text_colours(norm_colour, norm_colour, norm_colour, hi_colour, hi_colour, hi_colour);
|
|
}
|
|
|
|
void conv_set_default_hv(int32 h, int32 v) {
|
|
_GC(conv_default_h) = h;
|
|
_GC(conv_default_v) = v;
|
|
}
|
|
|
|
void conv_set_default_text_colour(int32 norm_colour, int32 hi_colour) {
|
|
conv_set_text_colours(norm_colour, norm_colour, norm_colour, hi_colour, hi_colour, hi_colour);
|
|
|
|
_GC(conv_default_normal_colour) = norm_colour;
|
|
_GC(conv_default_hilite_colour) = hi_colour;
|
|
}
|
|
|
|
void conv_set_shading(int32 shade) {
|
|
_GC(conv_shading) = shade;
|
|
}
|
|
|
|
void conv_set_box_xy(int32 x, int32 y) {
|
|
_GC(glob_x) = x;
|
|
_GC(glob_y) = y;
|
|
}
|
|
|
|
static void conv_set_disp_default(void) {
|
|
_GC(conv_font_spacing_h) = _GC(conv_default_h);
|
|
_GC(conv_font_spacing_v) = _GC(conv_default_v);
|
|
_GC(conv_normal_colour) = _GC(conv_default_normal_colour);
|
|
_GC(conv_hilite_colour) = _GC(conv_default_hilite_colour);
|
|
_GC(conv_shading) = 75;
|
|
}
|
|
|
|
Conv *conv_load(const char *filename, int x1, int y1, int32 myTrigger, bool want_box) {
|
|
char fullPathname[MAX_FILENAME_SIZE];
|
|
|
|
term_message("conv_load");
|
|
|
|
// Remember if player commands are on before we start the conversation
|
|
_GC(playerCommAllowed) = _G(player).comm_allowed;
|
|
_GC(interface_was_visible) = INTERFACE_VISIBLE;
|
|
|
|
term_message("conv load: %s", filename);
|
|
|
|
if (want_box) {
|
|
// If we want an interface box
|
|
conv_set_disp_default();
|
|
mouse_set_sprite(0); // Also if we want a text box, lock the mouse into arrow mode
|
|
mouse_lock_sprite(0);
|
|
player_set_commands_allowed(false); // with commands off
|
|
|
|
// Hide the interface if it's visible
|
|
if (INTERFACE_VISIBLE)
|
|
interface_hide();
|
|
}
|
|
|
|
// if not in rooms.db, use actual filename
|
|
char *str = env_find(filename);
|
|
if (str)
|
|
Common::strcpy_s(fullPathname, str);
|
|
else
|
|
Common::sprintf_s(fullPathname, "%s.chk", filename);
|
|
|
|
SysFile fp(fullPathname);
|
|
if (!fp.exists()) {
|
|
// Force the file open
|
|
error_show(FL, 'CNVL', "couldn't conv_load %s", fullPathname);
|
|
}
|
|
|
|
const int32 cSize = fp.size();
|
|
|
|
if (conv_get_handle() != nullptr) {
|
|
conv_unload();
|
|
}
|
|
|
|
Conv *convers = new Conv();
|
|
convers->chunkSize = cSize;
|
|
convers->conv = nullptr;
|
|
convers->myCNode = 0;
|
|
convers->exit_now = CONV_NEW;
|
|
convers->node_hash = 0;
|
|
convers->mode = CONV_GET_TEXT_MODE;
|
|
convers->c_entry_num = 1;
|
|
_GC(myFinalTrigger) = kernel_trigger_create(myTrigger);
|
|
|
|
convers->conv = (char *)mem_alloc(cSize * sizeof(char), "conv char data");
|
|
|
|
if (!fp.read((byte *)convers->conv, cSize)) {
|
|
conv_set_handle(nullptr);
|
|
delete convers;
|
|
convers = nullptr;
|
|
fp.close();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
conv_swap_words(convers);
|
|
find_and_set_conv_name(convers);
|
|
|
|
_GC(glob_x) = x1;
|
|
_GC(glob_y) = y1;
|
|
|
|
if (want_box)
|
|
set_dlg_rect();
|
|
|
|
if (_GC(restore_conv))
|
|
convers = conv_restore_state(convers);
|
|
_GC(restore_conv) = 1;
|
|
|
|
conv_set_handle(convers);
|
|
|
|
fp.close();
|
|
|
|
return convers;
|
|
}
|
|
|
|
void conv_load_and_prepare(const char *filename, int trigger, bool ignoreIt) {
|
|
player_set_commands_allowed(false);
|
|
|
|
if (!ignoreIt) {
|
|
conv_load(filename, 10, 375, trigger, true);
|
|
conv_set_shading(100);
|
|
conv_set_text_colours(3, 1, 2, 22, 10, 14);
|
|
conv_set_font_spacing(10, 2);
|
|
}
|
|
}
|
|
|
|
void conv_unload(Conv *c) {
|
|
mouse_unlock_sprite();
|
|
|
|
if (_GC(interface_was_visible)) { // Turn interface back on if it was on
|
|
interface_show();
|
|
}
|
|
|
|
_GC(globConv) = nullptr;
|
|
|
|
if (c)
|
|
conv_save_state(c);
|
|
|
|
player_set_commands_allowed(_GC(playerCommAllowed));
|
|
|
|
_G(player).command_ready = false;
|
|
_G(player).ready_to_walk = false;
|
|
_G(player).need_to_walk = false;
|
|
|
|
Common::strcpy_s(_G(player).verb, "");
|
|
Common::strcpy_s(_G(player).noun, "");
|
|
kernel_trigger_dispatchx(_GC(myFinalTrigger));
|
|
|
|
if (c) {
|
|
if (c->conv)
|
|
mem_free(c->conv);
|
|
delete c;
|
|
}
|
|
|
|
_GC(globConv) = c = nullptr;
|
|
}
|
|
|
|
void conv_unload() {
|
|
conv_unload(conv_get_handle());
|
|
}
|
|
|
|
// only called if node is visible.
|
|
// gets the TEXT chunks inside a node.
|
|
int conv_get_text(int32 offset, int32 size, Conv *c) {
|
|
int32 i = offset, tag, next;
|
|
int result = 0;
|
|
|
|
size -= sizeof(entry_chunk);
|
|
|
|
while (i < offset + size) {
|
|
conv_ops_get_entry(i, &next, &tag, c);
|
|
|
|
if (tag == TEXT_CHUNK) {
|
|
result = 1;
|
|
text_chunk *text = get_text(c, i);
|
|
assert(text);
|
|
const int32 text_len = conv_ops_text_strlen(get_string(c, c->myCNode + i + sizeof(text_chunk)));
|
|
_G(cdd).snd_files[_G(cdd).num_txt_ents] = get_string(c, c->myCNode + i + sizeof(text_chunk));
|
|
_G(cdd).text[_G(cdd).num_txt_ents] = get_string(c, c->myCNode + i + sizeof(text_chunk) + text_len);
|
|
|
|
const int32 text_width = gr_font_string_width(_G(cdd).text[_G(cdd).num_txt_ents], 1);
|
|
if (text_width > _GC(width))
|
|
_GC(width) = text_width;
|
|
|
|
_G(cdd).num_txt_ents++;
|
|
}
|
|
|
|
i = next;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} // End of namespace M4
|